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 | 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 | 201 | void mips_r4k_init (int ram_size, int vga_ram_size, int boot_device, |
| 115 | 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 | 204 | const char *initrd_filename) |
| 118 | 205 | { |
| 119 | 206 | char buf[1024]; |
| 120 | - int64_t entry = 0; | |
| 121 | 207 | unsigned long bios_offset; |
| 122 | 208 | int ret; |
| 123 | 209 | CPUState *env; |
| 124 | - long kernel_size; | |
| 125 | 210 | int i; |
| 126 | 211 | |
| 127 | 212 | env = cpu_init(); |
| 128 | 213 | register_savevm("cpu", 0, 3, cpu_save, cpu_load, env); |
| 214 | + qemu_register_reset(main_cpu_reset, env); | |
| 129 | 215 | |
| 130 | 216 | /* allocate RAM */ |
| 131 | 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 | 225 | /* Try to load a BIOS image. If this fails, we continue regardless, |
| 134 | 226 | but initialize the hardware ourselves. When a kernel gets |
| 135 | 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 | 238 | buf); |
| 147 | 239 | } |
| 148 | 240 | |
| 149 | - kernel_size = 0; | |
| 150 | 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 | 250 | /* Init internal devices */ | ... | ... |
target-mips/cpu.h
| ... | ... | @@ -182,7 +182,6 @@ struct CPUMIPSState { |
| 182 | 182 | uint32_t CP0_ErrorEPC; |
| 183 | 183 | uint32_t CP0_DESAVE; |
| 184 | 184 | /* Qemu */ |
| 185 | - struct QEMUTimer *timer; /* Internal timer */ | |
| 186 | 185 | int interrupt_request; |
| 187 | 186 | jmp_buf jmp_env; |
| 188 | 187 | int exception_index; |
| ... | ... | @@ -213,6 +212,13 @@ struct CPUMIPSState { |
| 213 | 212 | int halted; /* TRUE if the CPU is in suspend state */ |
| 214 | 213 | |
| 215 | 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 | 224 | #include "cpu-all.h" | ... | ... |
target-mips/translate.c
| ... | ... | @@ -2425,7 +2425,16 @@ CPUMIPSState *cpu_mips_init (void) |
| 2425 | 2425 | if (!env) |
| 2426 | 2426 | return NULL; |
| 2427 | 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 | 2436 | tlb_flush(env, 1); |
| 2437 | + | |
| 2429 | 2438 | /* Minimal init */ |
| 2430 | 2439 | env->PC = 0xBFC00000; |
| 2431 | 2440 | #if defined (MIPS_USES_R4K_TLB) |
| ... | ... | @@ -2456,5 +2465,4 @@ CPUMIPSState *cpu_mips_init (void) |
| 2456 | 2465 | #ifdef MIPS_USES_FPU |
| 2457 | 2466 | env->fcr0 = MIPS_FCR0; |
| 2458 | 2467 | #endif |
| 2459 | - return env; | |
| 2460 | 2468 | } | ... | ... |