Merge branch 'master' of ssh://repo.or.cz/srv/git/qemu
[qemu/mmix.git] / hw / mmixplatform.c
blobfaff998b1e804a1012d53ebd1faf8c0482071342
1 /*
2 * MMIX simple platform
4 * Copyright (c) 2009 Stuart Brady, Laurent Desnogues
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 /* This platform is based on IntegratorCP. */
22 #include "hw.h"
23 #include "pc.h"
24 #include "boards.h"
26 /* MMO loading */
28 #define MMO_MM 0x98
29 #define MMO_LOP_QUOTE 0x0
30 #define MMO_LOP_LOC 0x1
31 #define MMO_LOP_SKIP 0x2
32 #define MMO_LOP_FIXO 0x3
33 #define MMO_LOP_FIXR 0x4
34 #define MMO_LOP_FIXRX 0x5
35 #define MMO_LOP_FILE 0x6
36 #define MMO_LOP_LINE 0x7
37 #define MMO_LOP_SPEC 0x8
38 #define MMO_LOP_PRE 0x9
39 #define MMO_LOP_POST 0xa
40 #define MMO_LOP_STAB 0xb
41 #define MMO_LOP_END 0xc
43 typedef struct {
44 uint8_t magic; /* MMO_MM */
45 uint8_t pre; /* MMO_LOP_PRE */
46 uint8_t version; /* 1 */
47 uint8_t info;
48 } mmo_header_t;
50 static uint8_t mmo_buf[4];
51 static int mmo_yzbytes;
52 static uint32_t mmo_tet;
54 #define mmo_ybyte mmo_buf[2]
55 #define mmo_zbyte mmo_buf[3]
57 static void mmo_load(void *loader_phys, uint64_t loc, uint32_t val)
59 uint32_t v;
60 uint8_t buf[4];
62 cpu_physical_memory_read(loc, buf, 4);
63 v = (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3];
64 v = v ^ val;
65 buf[0] = v >> 24;
66 buf[1] = v >> 16;
67 buf[2] = v >> 8;
68 buf[3] = v;
69 cpu_physical_memory_write_rom(loc, buf, 4);
72 static int mmo_read_4(int fd)
74 if (read(fd, mmo_buf, 4) != 4) {
75 return -1;
77 mmo_yzbytes = (mmo_buf[2] << 8) + mmo_buf[3];
78 mmo_tet = (((mmo_buf[0] << 8) + mmo_buf[1]) << 16) + mmo_yzbytes;
79 return 0;
82 #define mmo_read_tet(fd) \
83 do { \
84 if (mmo_read_4(fd) < 0) \
85 goto out; \
86 } while (0)
88 static int load_mmo(CPUState *env, const char *filename, void *loader_phys,
89 target_ulong *entry_point)
91 int fd;
92 int size;
93 mmo_header_t h;
94 mmo_header_t *hdr = &h;
95 int ret = -1;
97 int mmo_postamble = 0;
98 uint64_t mmo_cur_loc;
99 int mmo_delta;
100 int mmo_cur_file = -1;
101 int mmo_j;
102 int mmo_file_info[256];
104 fd = open(filename, O_RDONLY | O_BINARY);
105 if (fd < 0)
106 return -1;
108 size = read(fd, hdr, sizeof(mmo_header_t));
109 if (size < 0)
110 goto out;
111 if (h.magic != MMO_MM
112 || h.pre != MMO_LOP_PRE
113 || h.version != 1)
114 goto out;
115 if (h.info > 0) {
116 if (lseek(fd, 4 + h.info * 4, SEEK_SET) < 0)
117 goto out;
120 mmo_cur_loc = 0;
121 mmo_j = 0;
122 memset(mmo_file_info, 0, sizeof(mmo_file_info));
123 do {
124 mmo_read_tet(fd);
125 loop:
126 if (mmo_buf[0] == MMO_MM) {
127 switch (mmo_buf[1]) {
128 case MMO_LOP_QUOTE:
129 if (mmo_yzbytes != 1)
130 goto err;
131 mmo_read_tet(fd);
132 break;
134 case MMO_LOP_LOC:
135 if (mmo_zbyte == 2) {
136 mmo_j = mmo_ybyte;
137 mmo_read_tet(fd);
138 mmo_cur_loc = (uint64_t)((mmo_j << 24) + mmo_tet) << 32;
139 } else if (mmo_zbyte == 1)
140 mmo_cur_loc = (uint64_t)mmo_ybyte << 56;
141 else
142 goto err;
143 mmo_read_tet(fd);
144 mmo_cur_loc |= mmo_tet;
145 continue;
147 case MMO_LOP_SKIP:
148 mmo_cur_loc += mmo_yzbytes;
149 continue;
151 case MMO_LOP_FIXO:
153 uint64_t mmo_tmp;
154 if (mmo_zbyte == 2) {
155 mmo_j = mmo_ybyte;
156 mmo_read_tet(fd);
157 mmo_tmp = (uint64_t)((mmo_j << 24) + mmo_tet) << 32;
158 } else if (mmo_zbyte == 1)
159 mmo_tmp = (uint64_t)mmo_ybyte << 56;
160 else
161 goto err;
162 mmo_read_tet(fd);
163 mmo_tmp |= mmo_tet;
164 mmo_load(loader_phys, mmo_tmp, mmo_cur_loc >> 32);
165 mmo_load(loader_phys, mmo_tmp + 4, (uint32_t)mmo_cur_loc);
167 continue;
169 case MMO_LOP_FIXR:
170 mmo_delta = mmo_yzbytes;
171 goto fixr;
173 case MMO_LOP_FIXRX:
174 mmo_j = mmo_yzbytes;
175 if (mmo_j != 16 && mmo_j != 24)
176 goto err;
177 mmo_read_tet(fd);
178 mmo_delta = mmo_tet;
179 if (mmo_delta & 0xfe000000)
180 goto err;
181 fixr:
183 uint64_t mmo_tmp;
184 mmo_tmp =
185 mmo_cur_loc - ((mmo_delta >= 0x1000000
186 ? (mmo_delta & 0xffffff) - (1 << mmo_j)
187 : mmo_delta) << 2);
188 mmo_load(loader_phys, mmo_tmp, mmo_delta);
190 continue;
192 case MMO_LOP_FILE:
193 if (mmo_file_info[mmo_ybyte]) {
194 if (mmo_zbyte)
195 goto err;
196 mmo_cur_file = mmo_ybyte;
197 } else {
198 if (!mmo_zbyte)
199 goto err;
200 mmo_file_info[mmo_ybyte] = 1;
201 mmo_cur_file = mmo_ybyte;
202 for (mmo_j = mmo_zbyte; mmo_j > 0; mmo_j--) {
203 mmo_read_tet(fd);
206 continue;
208 case MMO_LOP_LINE:
209 if (mmo_cur_file < 0)
210 goto err;
211 continue;
213 case MMO_LOP_SPEC:
214 while (1) {
215 mmo_read_tet(fd);
216 if (mmo_buf[0] == MMO_MM) {
217 if (mmo_buf[1] != MMO_LOP_QUOTE || mmo_yzbytes != 1)
218 goto loop;
219 mmo_read_tet(fd);
223 case MMO_LOP_POST:
224 mmo_postamble = 1;
225 if (mmo_ybyte || mmo_zbyte < 32)
226 goto err;
227 continue;
229 default:
230 goto err;
234 mmo_load(loader_phys, mmo_cur_loc, mmo_tet);
235 mmo_cur_loc += 4;
236 mmo_cur_loc &= -4ll;
237 } while (!mmo_postamble);
239 for (mmo_j = mmo_zbyte; mmo_j < 256; mmo_j++) {
240 uint64_t mmo_tmp;
242 mmo_read_tet(fd);
243 mmo_tmp = (uint64_t)mmo_tet << 32;
244 mmo_read_tet(fd);
245 mmo_tmp |= mmo_tet;
246 env->regs[mmo_j] = mmo_tmp;
248 /* XXX: there's more to read... */
250 /* XXX: tempo */
251 *entry_point = 0x100ull;
252 ret = 0;
253 goto out;
255 err:
256 fprintf(stderr, "Error reading MMO file\n");
258 out:
259 close(fd);
260 return ret;
263 /* Boot */
264 #include "sysemu.h"
266 #define KERNEL_ARGS_ADDR 0x100
267 #define KERNEL_LOAD_ADDR 0x00010000
268 #define INITRD_LOAD_ADDR 0x00800000
270 static uint32_t bootloader[] = {
271 0x21000012, /* add $0,$0,18 */
272 0x20000000, /* add $0,$0,18 */
273 0, /* Address of kernel args. Set by mmix_load_kernel. */
274 0 /* Kernel entry point. Set by mmix_load_kernel. */
277 struct mmix_boot_info {
278 int ram_size;
279 const char *kernel_filename;
280 const char *kernel_cmdline;
281 const char *initrd_filename;
282 target_phys_addr_t loader_start;
283 int nb_cpus;
285 static void mmix_load_kernel(CPUState *env, struct mmix_boot_info *info);
287 static void main_cpu_reset(void *opaque)
289 CPUState *env = opaque;
291 cpu_reset(env);
292 if (env->boot_info)
293 mmix_load_kernel(env, env->boot_info);
296 /* XXX: tempo */
297 static void set_kernel_args(struct mmix_boot_info *info,
298 int initrd_size, void *base)
302 /* XXX: tempo */
303 static
304 void mmix_load_kernel(CPUState *env, struct mmix_boot_info *info)
306 int kernel_size;
307 int initrd_size;
308 int n;
309 int is_linux = 0;
310 target_ulong entry;
311 uint64_t elf_entry;
312 uint32_t pd;
313 void *loader_phys;
315 /* Load the kernel. */
316 if (!info->kernel_filename) {
317 fprintf(stderr, "Kernel image must be specified\n");
318 exit(1);
321 if (!env->boot_info) {
322 if (info->nb_cpus == 0)
323 info->nb_cpus = 1;
324 env->boot_info = info;
325 qemu_register_reset(main_cpu_reset, env);
328 pd = cpu_get_physical_page_desc(info->loader_start);
329 loader_phys = phys_ram_base + (pd & TARGET_PAGE_MASK) +
330 (info->loader_start & ~TARGET_PAGE_MASK);
332 /* Try .mmo file first. */
333 kernel_size = load_mmo(env, info->kernel_filename, loader_phys, &entry);
334 /* Assume that raw images are linux kernels, and ELF images are not. */
335 if (kernel_size < 0) {
336 kernel_size = load_elf(info->kernel_filename, 0, &elf_entry, NULL,
337 NULL);
338 entry = elf_entry;
340 if (kernel_size < 0) {
341 kernel_size = load_uimage(info->kernel_filename, &entry, NULL,
342 &is_linux);
344 if (kernel_size < 0) {
345 kernel_size = load_image(info->kernel_filename,
346 loader_phys + KERNEL_LOAD_ADDR);
347 entry = info->loader_start + KERNEL_LOAD_ADDR;
348 is_linux = 1;
350 if (kernel_size < 0) {
351 fprintf(stderr, "qemu: could not load kernel '%s'\n",
352 info->kernel_filename);
353 exit(1);
355 if (!is_linux) {
356 /* Jump to the entry point. */
357 env->pc = entry;
358 } else {
359 if (info->initrd_filename) {
360 initrd_size = load_image(info->initrd_filename,
361 loader_phys + INITRD_LOAD_ADDR);
362 if (initrd_size < 0) {
363 fprintf(stderr, "qemu: could not load initrd '%s'\n",
364 info->initrd_filename);
365 exit(1);
367 } else {
368 initrd_size = 0;
370 /* XXX: change these indices. */
371 /* bootloader[1] = info->loader_start + KERNEL_ARGS_ADDR; */
372 /* bootloader[2] = entry; */
373 for (n = 0; n < sizeof(bootloader) / 4; n++) {
374 printf("L %016x %08x (%p)\n", n * 4, bootloader[n], loader_phys + (n * 4));
375 stl_raw(loader_phys + (n * 4), bootloader[n]);
377 set_kernel_args(info, initrd_size, loader_phys);
381 /* XXX: tempo */
382 void irq_info(Monitor *mon)
386 /* XXX: tempo */
387 void pic_info(Monitor *mon)
391 /* XXX: tempo */
392 typedef struct {
393 } mmixplatform_state;
395 /* Board init. */
397 static struct mmix_boot_info mmix_binfo = {
398 .loader_start = 0x0,
401 /* XXX: tempo */
402 static
403 void mmixplatform_init(ram_addr_t ram_size, int vga_ram_size,
404 const char *boot_device,
405 const char *kernel_filename, const char *kernel_cmdline,
406 const char *initrd_filename, const char *cpu_model)
408 CPUState *env;
409 ram_addr_t ram_offset, secondary_ram_offset;
411 env = cpu_init(cpu_model);
412 if (!env) {
413 fprintf(stderr, "Unable to find CPU definition\n");
414 exit(1);
417 /* allocate RAM */
418 ram_offset = qemu_ram_alloc(ram_size / 2);
419 cpu_register_physical_memory(0, ram_size / 2, ram_offset | IO_MEM_RAM);
421 /* XXX: tempo */
422 secondary_ram_offset = qemu_ram_alloc(ram_size / 2);
423 cpu_register_physical_memory(0x2000000000000000ull, ram_size / 2, secondary_ram_offset);
425 mmix_binfo.ram_size = ram_size;
426 mmix_binfo.kernel_filename = kernel_filename;
427 mmix_binfo.kernel_cmdline = kernel_cmdline;
428 mmix_binfo.initrd_filename = initrd_filename;
429 mmix_load_kernel(env, &mmix_binfo);
432 QEMUMachine mmixplatform_machine = {
433 .name = "mmixplatform",
434 .desc = "MMIX platform",
435 .init = mmixplatform_init,
436 .ram_require = 0x100000,