]>
Commit | Line | Data |
---|---|---|
6af0bf9c FB |
1 | #include "vl.h" |
2 | ||
6af0bf9c FB |
3 | #define BIOS_FILENAME "mips_bios.bin" |
4 | //#define BIOS_FILENAME "system.bin" | |
5 | #define KERNEL_LOAD_ADDR 0x80010000 | |
6 | #define INITRD_LOAD_ADDR 0x80800000 | |
7 | ||
66a93e0f FB |
8 | #define VIRT_TO_PHYS_ADDEND (-0x80000000LL) |
9 | ||
6af0bf9c FB |
10 | extern FILE *logfile; |
11 | ||
697584ab FB |
12 | static PITState *pit; |
13 | ||
73133662 | 14 | static void pic_irq_request(void *opaque, int level) |
6af0bf9c | 15 | { |
c68ea704 | 16 | CPUState *env = first_cpu; |
73133662 | 17 | if (level) { |
c68ea704 FB |
18 | env->CP0_Cause |= 0x00000400; |
19 | cpu_interrupt(env, CPU_INTERRUPT_HARD); | |
6af0bf9c | 20 | } else { |
c68ea704 FB |
21 | env->CP0_Cause &= ~0x00000400; |
22 | cpu_reset_interrupt(env, CPU_INTERRUPT_HARD); | |
6af0bf9c | 23 | } |
6af0bf9c FB |
24 | } |
25 | ||
26 | void cpu_mips_irqctrl_init (void) | |
27 | { | |
28 | } | |
29 | ||
f5d2a381 | 30 | /* XXX: do not use a global */ |
6af0bf9c FB |
31 | uint32_t cpu_mips_get_random (CPUState *env) |
32 | { | |
f5d2a381 FB |
33 | static uint32_t seed = 0; |
34 | uint32_t idx; | |
35 | seed = seed * 314159 + 1; | |
36 | idx = (seed >> 16) % (MIPS_TLB_NB - env->CP0_Wired) + env->CP0_Wired; | |
37 | return idx; | |
6af0bf9c FB |
38 | } |
39 | ||
899abcf5 | 40 | /* MIPS R4K timer */ |
6af0bf9c FB |
41 | uint32_t cpu_mips_get_count (CPUState *env) |
42 | { | |
43 | return env->CP0_Count + | |
44 | (uint32_t)muldiv64(qemu_get_clock(vm_clock), | |
45 | 100 * 1000 * 1000, ticks_per_sec); | |
46 | } | |
47 | ||
48 | static void cpu_mips_update_count (CPUState *env, uint32_t count, | |
49 | uint32_t compare) | |
50 | { | |
51 | uint64_t now, next; | |
52 | uint32_t tmp; | |
53 | ||
54 | tmp = count; | |
55 | if (count == compare) | |
56 | tmp++; | |
57 | now = qemu_get_clock(vm_clock); | |
58 | next = now + muldiv64(compare - tmp, ticks_per_sec, 100 * 1000 * 1000); | |
59 | if (next == now) | |
60 | next++; | |
2d7272a5 | 61 | #if 0 |
6af0bf9c | 62 | if (logfile) { |
26a76461 | 63 | fprintf(logfile, "%s: 0x%08" PRIx64 " %08x %08x => 0x%08" PRIx64 "\n", |
6af0bf9c FB |
64 | __func__, now, count, compare, next - now); |
65 | } | |
66 | #endif | |
67 | /* Store new count and compare registers */ | |
68 | env->CP0_Compare = compare; | |
69 | env->CP0_Count = | |
70 | count - (uint32_t)muldiv64(now, 100 * 1000 * 1000, ticks_per_sec); | |
71 | /* Adjust timer */ | |
72 | qemu_mod_timer(env->timer, next); | |
73 | } | |
74 | ||
75 | void cpu_mips_store_count (CPUState *env, uint32_t value) | |
76 | { | |
77 | cpu_mips_update_count(env, value, env->CP0_Compare); | |
78 | } | |
79 | ||
80 | void cpu_mips_store_compare (CPUState *env, uint32_t value) | |
81 | { | |
82 | cpu_mips_update_count(env, cpu_mips_get_count(env), value); | |
c68ea704 FB |
83 | env->CP0_Cause &= ~0x00008000; |
84 | cpu_reset_interrupt(env, CPU_INTERRUPT_HARD); | |
6af0bf9c FB |
85 | } |
86 | ||
87 | static void mips_timer_cb (void *opaque) | |
88 | { | |
89 | CPUState *env; | |
90 | ||
91 | env = opaque; | |
2d7272a5 | 92 | #if 0 |
6af0bf9c FB |
93 | if (logfile) { |
94 | fprintf(logfile, "%s\n", __func__); | |
95 | } | |
96 | #endif | |
97 | cpu_mips_update_count(env, cpu_mips_get_count(env), env->CP0_Compare); | |
c68ea704 FB |
98 | env->CP0_Cause |= 0x00008000; |
99 | cpu_interrupt(env, CPU_INTERRUPT_HARD); | |
6af0bf9c FB |
100 | } |
101 | ||
102 | void cpu_mips_clock_init (CPUState *env) | |
103 | { | |
104 | env->timer = qemu_new_timer(vm_clock, &mips_timer_cb, env); | |
105 | env->CP0_Compare = 0; | |
106 | cpu_mips_update_count(env, 1, 0); | |
107 | } | |
108 | ||
66a93e0f | 109 | |
6af0bf9c FB |
110 | static void io_writeb (void *opaque, target_phys_addr_t addr, uint32_t value) |
111 | { | |
2d7272a5 | 112 | #if 0 |
6af0bf9c FB |
113 | if (logfile) |
114 | fprintf(logfile, "%s: addr %08x val %08x\n", __func__, addr, value); | |
2d7272a5 | 115 | #endif |
6af0bf9c FB |
116 | cpu_outb(NULL, addr & 0xffff, value); |
117 | } | |
118 | ||
119 | static uint32_t io_readb (void *opaque, target_phys_addr_t addr) | |
120 | { | |
121 | uint32_t ret = cpu_inb(NULL, addr & 0xffff); | |
2d7272a5 | 122 | #if 0 |
6af0bf9c FB |
123 | if (logfile) |
124 | fprintf(logfile, "%s: addr %08x val %08x\n", __func__, addr, ret); | |
2d7272a5 | 125 | #endif |
6af0bf9c FB |
126 | return ret; |
127 | } | |
128 | ||
129 | static void io_writew (void *opaque, target_phys_addr_t addr, uint32_t value) | |
130 | { | |
2d7272a5 | 131 | #if 0 |
6af0bf9c FB |
132 | if (logfile) |
133 | fprintf(logfile, "%s: addr %08x val %08x\n", __func__, addr, value); | |
2d7272a5 | 134 | #endif |
6af0bf9c FB |
135 | #ifdef TARGET_WORDS_BIGENDIAN |
136 | value = bswap16(value); | |
137 | #endif | |
138 | cpu_outw(NULL, addr & 0xffff, value); | |
139 | } | |
140 | ||
141 | static uint32_t io_readw (void *opaque, target_phys_addr_t addr) | |
142 | { | |
143 | uint32_t ret = cpu_inw(NULL, addr & 0xffff); | |
144 | #ifdef TARGET_WORDS_BIGENDIAN | |
145 | ret = bswap16(ret); | |
146 | #endif | |
2d7272a5 | 147 | #if 0 |
6af0bf9c FB |
148 | if (logfile) |
149 | fprintf(logfile, "%s: addr %08x val %08x\n", __func__, addr, ret); | |
2d7272a5 | 150 | #endif |
6af0bf9c FB |
151 | return ret; |
152 | } | |
153 | ||
154 | static void io_writel (void *opaque, target_phys_addr_t addr, uint32_t value) | |
155 | { | |
2d7272a5 | 156 | #if 0 |
6af0bf9c FB |
157 | if (logfile) |
158 | fprintf(logfile, "%s: addr %08x val %08x\n", __func__, addr, value); | |
2d7272a5 | 159 | #endif |
6af0bf9c FB |
160 | #ifdef TARGET_WORDS_BIGENDIAN |
161 | value = bswap32(value); | |
162 | #endif | |
163 | cpu_outl(NULL, addr & 0xffff, value); | |
164 | } | |
165 | ||
166 | static uint32_t io_readl (void *opaque, target_phys_addr_t addr) | |
167 | { | |
168 | uint32_t ret = cpu_inl(NULL, addr & 0xffff); | |
169 | ||
170 | #ifdef TARGET_WORDS_BIGENDIAN | |
171 | ret = bswap32(ret); | |
172 | #endif | |
2d7272a5 | 173 | #if 0 |
6af0bf9c FB |
174 | if (logfile) |
175 | fprintf(logfile, "%s: addr %08x val %08x\n", __func__, addr, ret); | |
2d7272a5 | 176 | #endif |
6af0bf9c FB |
177 | return ret; |
178 | } | |
179 | ||
180 | CPUWriteMemoryFunc *io_write[] = { | |
181 | &io_writeb, | |
182 | &io_writew, | |
183 | &io_writel, | |
184 | }; | |
185 | ||
186 | CPUReadMemoryFunc *io_read[] = { | |
187 | &io_readb, | |
188 | &io_readw, | |
189 | &io_readl, | |
190 | }; | |
191 | ||
192 | void mips_r4k_init (int ram_size, int vga_ram_size, int boot_device, | |
193 | DisplayState *ds, const char **fd_filename, int snapshot, | |
194 | const char *kernel_filename, const char *kernel_cmdline, | |
195 | const char *initrd_filename) | |
196 | { | |
197 | char buf[1024]; | |
66a93e0f | 198 | int64_t entry = 0; |
6af0bf9c FB |
199 | unsigned long bios_offset; |
200 | int io_memory; | |
6af0bf9c | 201 | int ret; |
c68ea704 | 202 | CPUState *env; |
66a93e0f | 203 | long kernel_size; |
c68ea704 FB |
204 | |
205 | env = cpu_init(); | |
206 | register_savevm("cpu", 0, 3, cpu_save, cpu_load, env); | |
207 | ||
6af0bf9c FB |
208 | /* allocate RAM */ |
209 | cpu_register_physical_memory(0, ram_size, IO_MEM_RAM); | |
66a93e0f FB |
210 | |
211 | /* Try to load a BIOS image. If this fails, we continue regardless, | |
212 | but initialize the hardware ourselves. When a kernel gets | |
213 | preloaded we also initialize the hardware, since the BIOS wasn't | |
214 | run. */ | |
6af0bf9c FB |
215 | bios_offset = ram_size + vga_ram_size; |
216 | snprintf(buf, sizeof(buf), "%s/%s", bios_dir, BIOS_FILENAME); | |
6af0bf9c | 217 | ret = load_image(buf, phys_ram_base + bios_offset); |
66a93e0f FB |
218 | if (ret == BIOS_SIZE) { |
219 | cpu_register_physical_memory((uint32_t)(0x1fc00000), | |
220 | BIOS_SIZE, bios_offset | IO_MEM_ROM); | |
66a93e0f FB |
221 | } else { |
222 | /* not fatal */ | |
223 | fprintf(stderr, "qemu: Warning, could not load MIPS bios '%s'\n", | |
224 | buf); | |
6af0bf9c | 225 | } |
66a93e0f FB |
226 | |
227 | kernel_size = 0; | |
228 | if (kernel_filename) { | |
229 | kernel_size = load_elf(kernel_filename, VIRT_TO_PHYS_ADDEND, &entry); | |
230 | if (kernel_size >= 0) | |
231 | env->PC = entry; | |
232 | else { | |
233 | kernel_size = load_image(kernel_filename, | |
234 | phys_ram_base + KERNEL_LOAD_ADDR + VIRT_TO_PHYS_ADDEND); | |
235 | if (kernel_size < 0) { | |
236 | fprintf(stderr, "qemu: could not load kernel '%s'\n", | |
237 | kernel_filename); | |
238 | exit(1); | |
239 | } | |
240 | env->PC = KERNEL_LOAD_ADDR; | |
241 | } | |
242 | ||
6af0bf9c FB |
243 | /* load initrd */ |
244 | if (initrd_filename) { | |
66a93e0f FB |
245 | if (load_image(initrd_filename, |
246 | phys_ram_base + INITRD_LOAD_ADDR + VIRT_TO_PHYS_ADDEND) | |
247 | == (target_ulong) -1) { | |
6af0bf9c FB |
248 | fprintf(stderr, "qemu: could not load initial ram disk '%s'\n", |
249 | initrd_filename); | |
250 | exit(1); | |
251 | } | |
6af0bf9c | 252 | } |
66a93e0f | 253 | |
2d7272a5 FB |
254 | /* Store command line. */ |
255 | strcpy (phys_ram_base + (16 << 20) - 256, kernel_cmdline); | |
256 | /* FIXME: little endian support */ | |
257 | *(int *)(phys_ram_base + (16 << 20) - 260) = tswap32 (0x12345678); | |
258 | *(int *)(phys_ram_base + (16 << 20) - 264) = tswap32 (ram_size); | |
6af0bf9c | 259 | } |
6af0bf9c FB |
260 | |
261 | /* Init internal devices */ | |
c68ea704 | 262 | cpu_mips_clock_init(env); |
6af0bf9c FB |
263 | cpu_mips_irqctrl_init(); |
264 | ||
0699b548 | 265 | /* Register 64 KB of ISA IO space at 0x14000000 */ |
6af0bf9c | 266 | io_memory = cpu_register_io_memory(0, io_read, io_write, NULL); |
0699b548 FB |
267 | cpu_register_physical_memory(0x14000000, 0x00010000, io_memory); |
268 | isa_mem_base = 0x10000000; | |
269 | ||
c68ea704 | 270 | isa_pic = pic_init(pic_irq_request, env); |
697584ab | 271 | pit = pit_init(0x40, 0); |
e5d13e2f | 272 | serial_init(&pic_set_irq_new, isa_pic, 0x3f8, 4, serial_hds[0]); |
0699b548 | 273 | vga_initialize(NULL, ds, phys_ram_base + ram_size, ram_size, |
d5295253 | 274 | vga_ram_size, 0, 0); |
9827e95c | 275 | |
a41b2ff2 PB |
276 | if (nd_table[0].vlan) { |
277 | if (nd_table[0].model == NULL | |
278 | || strcmp(nd_table[0].model, "ne2k_isa") == 0) { | |
279 | isa_ne2000_init(0x300, 9, &nd_table[0]); | |
280 | } else { | |
281 | fprintf(stderr, "qemu: Unsupported NIC: %s\n", nd_table[0].model); | |
282 | exit (1); | |
283 | } | |
284 | } | |
6af0bf9c FB |
285 | } |
286 | ||
287 | QEMUMachine mips_machine = { | |
288 | "mips", | |
289 | "mips r4k platform", | |
290 | mips_r4k_init, | |
291 | }; |