Commit 6ae817752b72a7c9c3bb031afa7e7cc0e4d10eaf
1 parent
814b9a47
Halt/reboot support for Linux, by Daniel Jacobowitz. This is a band-aid
until we emulate real MIPS hardware with real firmware. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2221 c046a42c-6fe2-441c-8c8c-71466251a162
Showing
3 changed files
with
116 additions
and
35 deletions
hw/mips_r4k.c
@@ -110,6 +110,93 @@ void cpu_mips_clock_init (CPUState *env) | @@ -110,6 +110,93 @@ void cpu_mips_clock_init (CPUState *env) | ||
110 | cpu_mips_update_count(env, 1, 0); | 110 | cpu_mips_update_count(env, 1, 0); |
111 | } | 111 | } |
112 | 112 | ||
113 | +static void mips_qemu_writel (void *opaque, target_phys_addr_t addr, | ||
114 | + uint32_t val) | ||
115 | +{ | ||
116 | + if ((addr & 0xffff) == 0 && val == 42) | ||
117 | + qemu_system_reset_request (); | ||
118 | + else if ((addr & 0xffff) == 4 && val == 42) | ||
119 | + qemu_system_shutdown_request (); | ||
120 | +} | ||
121 | + | ||
122 | +static uint32_t mips_qemu_readl (void *opaque, target_phys_addr_t addr) | ||
123 | +{ | ||
124 | + return 0; | ||
125 | +} | ||
126 | + | ||
127 | +static CPUWriteMemoryFunc *mips_qemu_write[] = { | ||
128 | + &mips_qemu_writel, | ||
129 | + &mips_qemu_writel, | ||
130 | + &mips_qemu_writel, | ||
131 | +}; | ||
132 | + | ||
133 | +static CPUReadMemoryFunc *mips_qemu_read[] = { | ||
134 | + &mips_qemu_readl, | ||
135 | + &mips_qemu_readl, | ||
136 | + &mips_qemu_readl, | ||
137 | +}; | ||
138 | + | ||
139 | +static int mips_qemu_iomemtype = 0; | ||
140 | + | ||
141 | +void load_kernel (CPUState *env, int ram_size, const char *kernel_filename, | ||
142 | + const char *kernel_cmdline, | ||
143 | + const char *initrd_filename) | ||
144 | +{ | ||
145 | + int64_t entry = 0; | ||
146 | + long kernel_size, initrd_size; | ||
147 | + | ||
148 | + kernel_size = load_elf(kernel_filename, VIRT_TO_PHYS_ADDEND, &entry); | ||
149 | + if (kernel_size >= 0) | ||
150 | + env->PC = entry; | ||
151 | + else { | ||
152 | + kernel_size = load_image(kernel_filename, | ||
153 | + phys_ram_base + KERNEL_LOAD_ADDR + VIRT_TO_PHYS_ADDEND); | ||
154 | + if (kernel_size < 0) { | ||
155 | + fprintf(stderr, "qemu: could not load kernel '%s'\n", | ||
156 | + kernel_filename); | ||
157 | + exit(1); | ||
158 | + } | ||
159 | + env->PC = KERNEL_LOAD_ADDR; | ||
160 | + } | ||
161 | + | ||
162 | + /* load initrd */ | ||
163 | + initrd_size = 0; | ||
164 | + if (initrd_filename) { | ||
165 | + initrd_size = load_image(initrd_filename, | ||
166 | + phys_ram_base + INITRD_LOAD_ADDR + VIRT_TO_PHYS_ADDEND); | ||
167 | + if (initrd_size == (target_ulong) -1) { | ||
168 | + fprintf(stderr, "qemu: could not load initial ram disk '%s'\n", | ||
169 | + initrd_filename); | ||
170 | + exit(1); | ||
171 | + } | ||
172 | + } | ||
173 | + | ||
174 | + /* Store command line. */ | ||
175 | + if (initrd_size > 0) { | ||
176 | + int ret; | ||
177 | + ret = sprintf(phys_ram_base + (16 << 20) - 256, | ||
178 | + "rd_start=0x%08x rd_size=%li ", | ||
179 | + INITRD_LOAD_ADDR, | ||
180 | + initrd_size); | ||
181 | + strcpy (phys_ram_base + (16 << 20) - 256 + ret, kernel_cmdline); | ||
182 | + } | ||
183 | + else { | ||
184 | + strcpy (phys_ram_base + (16 << 20) - 256, kernel_cmdline); | ||
185 | + } | ||
186 | + | ||
187 | + *(int *)(phys_ram_base + (16 << 20) - 260) = tswap32 (0x12345678); | ||
188 | + *(int *)(phys_ram_base + (16 << 20) - 264) = tswap32 (ram_size); | ||
189 | +} | ||
190 | + | ||
191 | +static void main_cpu_reset(void *opaque) | ||
192 | +{ | ||
193 | + CPUState *env = opaque; | ||
194 | + cpu_reset(env); | ||
195 | + | ||
196 | + if (env->kernel_filename) | ||
197 | + load_kernel (env, env->ram_size, env->kernel_filename, | ||
198 | + env->kernel_cmdline, env->initrd_filename); | ||
199 | +} | ||
113 | 200 | ||
114 | void mips_r4k_init (int ram_size, int vga_ram_size, int boot_device, | 201 | void mips_r4k_init (int ram_size, int vga_ram_size, int boot_device, |
115 | DisplayState *ds, const char **fd_filename, int snapshot, | 202 | DisplayState *ds, const char **fd_filename, int snapshot, |
@@ -117,19 +204,24 @@ void mips_r4k_init (int ram_size, int vga_ram_size, int boot_device, | @@ -117,19 +204,24 @@ void mips_r4k_init (int ram_size, int vga_ram_size, int boot_device, | ||
117 | const char *initrd_filename) | 204 | const char *initrd_filename) |
118 | { | 205 | { |
119 | char buf[1024]; | 206 | char buf[1024]; |
120 | - int64_t entry = 0; | ||
121 | unsigned long bios_offset; | 207 | unsigned long bios_offset; |
122 | int ret; | 208 | int ret; |
123 | CPUState *env; | 209 | CPUState *env; |
124 | - long kernel_size; | ||
125 | int i; | 210 | int i; |
126 | 211 | ||
127 | env = cpu_init(); | 212 | env = cpu_init(); |
128 | register_savevm("cpu", 0, 3, cpu_save, cpu_load, env); | 213 | register_savevm("cpu", 0, 3, cpu_save, cpu_load, env); |
214 | + qemu_register_reset(main_cpu_reset, env); | ||
129 | 215 | ||
130 | /* allocate RAM */ | 216 | /* allocate RAM */ |
131 | cpu_register_physical_memory(0, ram_size, IO_MEM_RAM); | 217 | cpu_register_physical_memory(0, ram_size, IO_MEM_RAM); |
132 | 218 | ||
219 | + if (!mips_qemu_iomemtype) { | ||
220 | + mips_qemu_iomemtype = cpu_register_io_memory(0, mips_qemu_read, | ||
221 | + mips_qemu_write, NULL); | ||
222 | + } | ||
223 | + cpu_register_physical_memory(0x1fbf0000, 0x10000, mips_qemu_iomemtype); | ||
224 | + | ||
133 | /* Try to load a BIOS image. If this fails, we continue regardless, | 225 | /* Try to load a BIOS image. If this fails, we continue regardless, |
134 | but initialize the hardware ourselves. When a kernel gets | 226 | but initialize the hardware ourselves. When a kernel gets |
135 | preloaded we also initialize the hardware, since the BIOS wasn't | 227 | preloaded we also initialize the hardware, since the BIOS wasn't |
@@ -146,38 +238,13 @@ void mips_r4k_init (int ram_size, int vga_ram_size, int boot_device, | @@ -146,38 +238,13 @@ void mips_r4k_init (int ram_size, int vga_ram_size, int boot_device, | ||
146 | buf); | 238 | buf); |
147 | } | 239 | } |
148 | 240 | ||
149 | - kernel_size = 0; | ||
150 | if (kernel_filename) { | 241 | if (kernel_filename) { |
151 | - kernel_size = load_elf(kernel_filename, VIRT_TO_PHYS_ADDEND, &entry); | ||
152 | - if (kernel_size >= 0) | ||
153 | - env->PC = entry; | ||
154 | - else { | ||
155 | - kernel_size = load_image(kernel_filename, | ||
156 | - phys_ram_base + KERNEL_LOAD_ADDR + VIRT_TO_PHYS_ADDEND); | ||
157 | - if (kernel_size < 0) { | ||
158 | - fprintf(stderr, "qemu: could not load kernel '%s'\n", | ||
159 | - kernel_filename); | ||
160 | - exit(1); | ||
161 | - } | ||
162 | - env->PC = KERNEL_LOAD_ADDR; | ||
163 | - } | ||
164 | - | ||
165 | - /* load initrd */ | ||
166 | - if (initrd_filename) { | ||
167 | - if (load_image(initrd_filename, | ||
168 | - phys_ram_base + INITRD_LOAD_ADDR + VIRT_TO_PHYS_ADDEND) | ||
169 | - == (target_ulong) -1) { | ||
170 | - fprintf(stderr, "qemu: could not load initial ram disk '%s'\n", | ||
171 | - initrd_filename); | ||
172 | - exit(1); | ||
173 | - } | ||
174 | - } | ||
175 | - | ||
176 | - /* Store command line. */ | ||
177 | - strcpy (phys_ram_base + (16 << 20) - 256, kernel_cmdline); | ||
178 | - /* FIXME: little endian support */ | ||
179 | - *(int *)(phys_ram_base + (16 << 20) - 260) = tswap32 (0x12345678); | ||
180 | - *(int *)(phys_ram_base + (16 << 20) - 264) = tswap32 (ram_size); | 242 | + load_kernel (env, ram_size, kernel_filename, kernel_cmdline, |
243 | + initrd_filename); | ||
244 | + env->ram_size = ram_size; | ||
245 | + env->kernel_filename = kernel_filename; | ||
246 | + env->kernel_cmdline = kernel_cmdline; | ||
247 | + env->initrd_filename = initrd_filename; | ||
181 | } | 248 | } |
182 | 249 | ||
183 | /* Init internal devices */ | 250 | /* Init internal devices */ |
target-mips/cpu.h
@@ -182,7 +182,6 @@ struct CPUMIPSState { | @@ -182,7 +182,6 @@ struct CPUMIPSState { | ||
182 | uint32_t CP0_ErrorEPC; | 182 | uint32_t CP0_ErrorEPC; |
183 | uint32_t CP0_DESAVE; | 183 | uint32_t CP0_DESAVE; |
184 | /* Qemu */ | 184 | /* Qemu */ |
185 | - struct QEMUTimer *timer; /* Internal timer */ | ||
186 | int interrupt_request; | 185 | int interrupt_request; |
187 | jmp_buf jmp_env; | 186 | jmp_buf jmp_env; |
188 | int exception_index; | 187 | int exception_index; |
@@ -213,6 +212,13 @@ struct CPUMIPSState { | @@ -213,6 +212,13 @@ struct CPUMIPSState { | ||
213 | int halted; /* TRUE if the CPU is in suspend state */ | 212 | int halted; /* TRUE if the CPU is in suspend state */ |
214 | 213 | ||
215 | CPU_COMMON | 214 | CPU_COMMON |
215 | + | ||
216 | + int ram_size; | ||
217 | + const char *kernel_filename; | ||
218 | + const char *kernel_cmdline; | ||
219 | + const char *initrd_filename; | ||
220 | + | ||
221 | + struct QEMUTimer *timer; /* Internal timer */ | ||
216 | }; | 222 | }; |
217 | 223 | ||
218 | #include "cpu-all.h" | 224 | #include "cpu-all.h" |
target-mips/translate.c
@@ -2425,7 +2425,16 @@ CPUMIPSState *cpu_mips_init (void) | @@ -2425,7 +2425,16 @@ CPUMIPSState *cpu_mips_init (void) | ||
2425 | if (!env) | 2425 | if (!env) |
2426 | return NULL; | 2426 | return NULL; |
2427 | cpu_exec_init(env); | 2427 | cpu_exec_init(env); |
2428 | + cpu_reset(env); | ||
2429 | + return env; | ||
2430 | +} | ||
2431 | + | ||
2432 | +void cpu_reset (CPUMIPSState *env) | ||
2433 | +{ | ||
2434 | + memset(env, 0, offsetof(CPUMIPSState, breakpoints)); | ||
2435 | + | ||
2428 | tlb_flush(env, 1); | 2436 | tlb_flush(env, 1); |
2437 | + | ||
2429 | /* Minimal init */ | 2438 | /* Minimal init */ |
2430 | env->PC = 0xBFC00000; | 2439 | env->PC = 0xBFC00000; |
2431 | #if defined (MIPS_USES_R4K_TLB) | 2440 | #if defined (MIPS_USES_R4K_TLB) |
@@ -2456,5 +2465,4 @@ CPUMIPSState *cpu_mips_init (void) | @@ -2456,5 +2465,4 @@ CPUMIPSState *cpu_mips_init (void) | ||
2456 | #ifdef MIPS_USES_FPU | 2465 | #ifdef MIPS_USES_FPU |
2457 | env->fcr0 = MIPS_FCR0; | 2466 | env->fcr0 = MIPS_FCR0; |
2458 | #endif | 2467 | #endif |
2459 | - return env; | ||
2460 | } | 2468 | } |