]>
Commit | Line | Data |
---|---|---|
f0fc6f8f TS |
1 | /* |
2 | * QEMU/mipssim emulation | |
3 | * | |
4 | * Emulates a very simple machine model similiar to the one use by the | |
5 | * proprietary MIPS emulator. | |
6 | */ | |
7 | #include "vl.h" | |
8 | ||
9 | #ifdef TARGET_WORDS_BIGENDIAN | |
10 | #define BIOS_FILENAME "mips_bios.bin" | |
11 | #else | |
12 | #define BIOS_FILENAME "mipsel_bios.bin" | |
13 | #endif | |
14 | ||
15 | #ifdef TARGET_MIPS64 | |
16 | #define PHYS_TO_VIRT(x) ((x) | ~0x7fffffffULL) | |
17 | #else | |
18 | #define PHYS_TO_VIRT(x) ((x) | ~0x7fffffffU) | |
19 | #endif | |
20 | ||
21 | #define VIRT_TO_PHYS_ADDEND (-((int64_t)(int32_t)0x80000000)) | |
22 | ||
23 | static void load_kernel (CPUState *env) | |
24 | { | |
25 | int64_t entry, kernel_low, kernel_high; | |
26 | long kernel_size; | |
27 | long initrd_size; | |
28 | ram_addr_t initrd_offset; | |
29 | ||
30 | kernel_size = load_elf(env->kernel_filename, VIRT_TO_PHYS_ADDEND, | |
31 | &entry, &kernel_low, &kernel_high); | |
32 | if (kernel_size >= 0) { | |
33 | if ((entry & ~0x7fffffffULL) == 0x80000000) | |
34 | entry = (int32_t)entry; | |
35 | env->PC[env->current_tc] = entry; | |
36 | } else { | |
37 | fprintf(stderr, "qemu: could not load kernel '%s'\n", | |
38 | env->kernel_filename); | |
39 | exit(1); | |
40 | } | |
41 | ||
42 | /* load initrd */ | |
43 | initrd_size = 0; | |
44 | initrd_offset = 0; | |
45 | if (env->initrd_filename) { | |
46 | initrd_size = get_image_size (env->initrd_filename); | |
47 | if (initrd_size > 0) { | |
48 | initrd_offset = (kernel_high + ~TARGET_PAGE_MASK) & TARGET_PAGE_MASK; | |
49 | if (initrd_offset + initrd_size > env->ram_size) { | |
50 | fprintf(stderr, | |
51 | "qemu: memory too small for initial ram disk '%s'\n", | |
52 | env->initrd_filename); | |
53 | exit(1); | |
54 | } | |
55 | initrd_size = load_image(env->initrd_filename, | |
56 | phys_ram_base + initrd_offset); | |
57 | } | |
58 | if (initrd_size == (target_ulong) -1) { | |
59 | fprintf(stderr, "qemu: could not load initial ram disk '%s'\n", | |
60 | env->initrd_filename); | |
61 | exit(1); | |
62 | } | |
63 | } | |
64 | } | |
65 | ||
66 | static void main_cpu_reset(void *opaque) | |
67 | { | |
68 | CPUState *env = opaque; | |
69 | cpu_reset(env); | |
70 | cpu_mips_register(env, NULL); | |
71 | ||
72 | if (env->kernel_filename) | |
73 | load_kernel (env); | |
74 | } | |
75 | ||
76 | static void | |
6ac0e82d | 77 | mips_mipssim_init (int ram_size, int vga_ram_size, const char *boot_device, |
f0fc6f8f TS |
78 | DisplayState *ds, const char **fd_filename, int snapshot, |
79 | const char *kernel_filename, const char *kernel_cmdline, | |
80 | const char *initrd_filename, const char *cpu_model) | |
81 | { | |
82 | char buf[1024]; | |
83 | unsigned long bios_offset; | |
84 | CPUState *env; | |
b5334159 | 85 | int bios_size; |
f0fc6f8f TS |
86 | mips_def_t *def; |
87 | ||
88 | /* Init CPUs. */ | |
89 | if (cpu_model == NULL) { | |
90 | #ifdef TARGET_MIPS64 | |
91 | cpu_model = "5Kf"; | |
92 | #else | |
93 | cpu_model = "24Kf"; | |
94 | #endif | |
95 | } | |
96 | if (mips_find_by_name(cpu_model, &def) != 0) | |
97 | def = NULL; | |
98 | env = cpu_init(); | |
99 | cpu_mips_register(env, def); | |
100 | register_savevm("cpu", 0, 3, cpu_save, cpu_load, env); | |
101 | qemu_register_reset(main_cpu_reset, env); | |
102 | ||
103 | /* Allocate RAM. */ | |
104 | cpu_register_physical_memory(0, ram_size, IO_MEM_RAM); | |
105 | ||
f0fc6f8f | 106 | /* Load a BIOS / boot exception handler image. */ |
b5334159 | 107 | bios_offset = ram_size + vga_ram_size; |
f0fc6f8f TS |
108 | if (bios_name == NULL) |
109 | bios_name = BIOS_FILENAME; | |
110 | snprintf(buf, sizeof(buf), "%s/%s", bios_dir, bios_name); | |
b5334159 TS |
111 | bios_size = load_image(buf, phys_ram_base + bios_offset); |
112 | if ((bios_size < 0 || bios_size > BIOS_SIZE) && !kernel_filename) { | |
f0fc6f8f TS |
113 | /* Bail out if we have neither a kernel image nor boot vector code. */ |
114 | fprintf(stderr, | |
115 | "qemu: Could not load MIPS bios '%s', and no -kernel argument was specified\n", | |
116 | buf); | |
117 | exit(1); | |
118 | } else { | |
b5334159 | 119 | /* Map the BIOS / boot exception handler. */ |
f0fc6f8f | 120 | cpu_register_physical_memory(0x1fc00000LL, |
b5334159 TS |
121 | bios_size, bios_offset | IO_MEM_ROM); |
122 | /* We have a boot vector start address. */ | |
123 | env->PC[env->current_tc] = (target_long)(int32_t)0xbfc00000; | |
f0fc6f8f TS |
124 | } |
125 | ||
126 | if (kernel_filename) { | |
127 | env->ram_size = ram_size; | |
128 | env->kernel_filename = kernel_filename; | |
129 | env->kernel_cmdline = kernel_cmdline; | |
130 | env->initrd_filename = initrd_filename; | |
131 | load_kernel(env); | |
132 | } | |
133 | ||
134 | /* Init CPU internal devices. */ | |
135 | cpu_mips_irq_init_cpu(env); | |
136 | cpu_mips_clock_init(env); | |
137 | cpu_mips_irqctrl_init(); | |
138 | ||
139 | /* Register 64 KB of ISA IO space at 0x1fd00000. */ | |
140 | isa_mmio_init(0x1fd00000, 0x00010000); | |
141 | ||
142 | /* A single 16450 sits at offset 0x3f8. It is attached to | |
143 | MIPS CPU INT2, which is interrupt 4. */ | |
144 | if (serial_hds[0]) | |
145 | serial_init(0x3f8, env->irq[4], serial_hds[0]); | |
146 | ||
147 | if (nd_table[0].vlan) { | |
148 | if (nd_table[0].model == NULL | |
149 | || strcmp(nd_table[0].model, "mipsnet") == 0) { | |
150 | /* MIPSnet uses the MIPS CPU INT0, which is interrupt 2. */ | |
151 | mipsnet_init(0x4200, env->irq[2], &nd_table[0]); | |
152 | } else if (strcmp(nd_table[0].model, "?") == 0) { | |
153 | fprintf(stderr, "qemu: Supported NICs: mipsnet\n"); | |
154 | exit (1); | |
155 | } else { | |
156 | fprintf(stderr, "qemu: Unsupported NIC: %s\n", nd_table[0].model); | |
157 | exit (1); | |
158 | } | |
159 | } | |
160 | } | |
161 | ||
162 | QEMUMachine mips_mipssim_machine = { | |
163 | "mipssim", | |
164 | "MIPS MIPSsim platform", | |
165 | mips_mipssim_init, | |
166 | }; |