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. */
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
44 uint8_t magic
; /* MMO_MM */
45 uint8_t pre
; /* MMO_LOP_PRE */
46 uint8_t version
; /* 1 */
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
)
62 cpu_physical_memory_read(loc
, buf
, 4);
63 v
= (buf
[0] << 24) | (buf
[1] << 16) | (buf
[2] << 8) | buf
[3];
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) {
77 mmo_yzbytes
= (mmo_buf
[2] << 8) + mmo_buf
[3];
78 mmo_tet
= (((mmo_buf
[0] << 8) + mmo_buf
[1]) << 16) + mmo_yzbytes
;
82 #define mmo_read_tet(fd) \
84 if (mmo_read_4(fd) < 0) \
88 static int load_mmo(CPUState
*env
, const char *filename
, void *loader_phys
,
89 target_ulong
*entry_point
)
94 mmo_header_t
*hdr
= &h
;
97 int mmo_postamble
= 0;
100 int mmo_cur_file
= -1;
102 int mmo_file_info
[256];
104 fd
= open(filename
, O_RDONLY
| O_BINARY
);
108 size
= read(fd
, hdr
, sizeof(mmo_header_t
));
111 if (h
.magic
!= MMO_MM
112 || h
.pre
!= MMO_LOP_PRE
116 if (lseek(fd
, 4 + h
.info
* 4, SEEK_SET
) < 0)
122 memset(mmo_file_info
, 0, sizeof(mmo_file_info
));
126 if (mmo_buf
[0] == MMO_MM
) {
127 switch (mmo_buf
[1]) {
129 if (mmo_yzbytes
!= 1)
135 if (mmo_zbyte
== 2) {
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;
144 mmo_cur_loc
|= mmo_tet
;
148 mmo_cur_loc
+= mmo_yzbytes
;
154 if (mmo_zbyte
== 2) {
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;
164 mmo_load(loader_phys
, mmo_tmp
, mmo_cur_loc
>> 32);
165 mmo_load(loader_phys
, mmo_tmp
+ 4, (uint32_t)mmo_cur_loc
);
170 mmo_delta
= mmo_yzbytes
;
175 if (mmo_j
!= 16 && mmo_j
!= 24)
179 if (mmo_delta
& 0xfe000000)
185 mmo_cur_loc
- ((mmo_delta
>= 0x1000000
186 ? (mmo_delta
& 0xffffff) - (1 << mmo_j
)
188 mmo_load(loader_phys
, mmo_tmp
, mmo_delta
);
193 if (mmo_file_info
[mmo_ybyte
]) {
196 mmo_cur_file
= mmo_ybyte
;
200 mmo_file_info
[mmo_ybyte
] = 1;
201 mmo_cur_file
= mmo_ybyte
;
202 for (mmo_j
= mmo_zbyte
; mmo_j
> 0; mmo_j
--) {
209 if (mmo_cur_file
< 0)
216 if (mmo_buf
[0] == MMO_MM
) {
217 if (mmo_buf
[1] != MMO_LOP_QUOTE
|| mmo_yzbytes
!= 1)
225 if (mmo_ybyte
|| mmo_zbyte
< 32)
234 mmo_load(loader_phys
, mmo_cur_loc
, mmo_tet
);
237 } while (!mmo_postamble
);
239 for (mmo_j
= mmo_zbyte
; mmo_j
< 256; mmo_j
++) {
243 mmo_tmp
= (uint64_t)mmo_tet
<< 32;
246 env
->regs
[mmo_j
] = mmo_tmp
;
248 /* XXX: there's more to read... */
251 *entry_point
= 0x100ull
;
256 fprintf(stderr
, "Error reading MMO file\n");
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
{
279 const char *kernel_filename
;
280 const char *kernel_cmdline
;
281 const char *initrd_filename
;
282 target_phys_addr_t loader_start
;
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
;
293 mmix_load_kernel(env
, env
->boot_info
);
297 static void set_kernel_args(struct mmix_boot_info
*info
,
298 int initrd_size
, void *base
)
304 void mmix_load_kernel(CPUState
*env
, struct mmix_boot_info
*info
)
315 /* Load the kernel. */
316 if (!info
->kernel_filename
) {
317 fprintf(stderr
, "Kernel image must be specified\n");
321 if (!env
->boot_info
) {
322 if (info
->nb_cpus
== 0)
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
,
340 if (kernel_size
< 0) {
341 kernel_size
= load_uimage(info
->kernel_filename
, &entry
, NULL
,
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
;
350 if (kernel_size
< 0) {
351 fprintf(stderr
, "qemu: could not load kernel '%s'\n",
352 info
->kernel_filename
);
356 /* Jump to the entry point. */
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
);
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
);
382 void irq_info(Monitor
*mon
)
387 void pic_info(Monitor
*mon
)
393 } mmixplatform_state
;
397 static struct mmix_boot_info mmix_binfo
= {
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
)
409 ram_addr_t ram_offset
, secondary_ram_offset
;
411 env
= cpu_init(cpu_model
);
413 fprintf(stderr
, "Unable to find CPU definition\n");
418 ram_offset
= qemu_ram_alloc(ram_size
/ 2);
419 cpu_register_physical_memory(0, ram_size
/ 2, ram_offset
| IO_MEM_RAM
);
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,