Break up vl.h.
[qemu] / hw / arm_boot.c
1 /*
2  * ARM kernel loader.
3  *
4  * Copyright (c) 2006-2007 CodeSourcery.
5  * Written by Paul Brook
6  *
7  * This code is licenced under the GPL.
8  */
9
10 #include "hw.h"
11 #include "arm-misc.h"
12 #include "sysemu.h"
13
14 #define KERNEL_ARGS_ADDR 0x100
15 #define KERNEL_LOAD_ADDR 0x00010000
16 #define INITRD_LOAD_ADDR 0x00800000
17
18 /* The worlds second smallest bootloader.  Set r0-r2, then jump to kernel.  */
19 static uint32_t bootloader[] = {
20   0xe3a00000, /* mov     r0, #0 */
21   0xe3a01000, /* mov     r1, #0x?? */
22   0xe3811c00, /* orr     r1, r1, #0x??00 */
23   0xe59f2000, /* ldr     r2, [pc, #0] */
24   0xe59ff000, /* ldr     pc, [pc, #0] */
25   0, /* Address of kernel args.  Set by integratorcp_init.  */
26   0  /* Kernel entry point.  Set by integratorcp_init.  */
27 };
28
29 /* Entry point for secondary CPUs.  Enable interrupt controller and
30    Issue WFI until start address is written to system controller.  */
31 static uint32_t smpboot[] = {
32   0xe3a00201, /* mov     r0, #0x10000000 */
33   0xe3800601, /* orr     r0, r0, #0x001000000 */
34   0xe3a01001, /* mov     r1, #1 */
35   0xe5801100, /* str     r1, [r0, #0x100] */
36   0xe3a00201, /* mov     r0, #0x10000000 */
37   0xe3800030, /* orr     r0, #0x30 */
38   0xe320f003, /* wfi */
39   0xe5901000, /* ldr     r1, [r0] */
40   0xe3110003, /* tst     r1, #3 */
41   0x1afffffb, /* bne     <wfi> */
42   0xe12fff11  /* bx      r1 */
43 };
44
45 static void main_cpu_reset(void *opaque)
46 {
47     CPUState *env = opaque;
48
49     cpu_reset(env);
50     if (env->kernel_filename)
51         arm_load_kernel(env, env->ram_size, env->kernel_filename,
52                         env->kernel_cmdline, env->initrd_filename,
53                         env->board_id, env->loader_start);
54
55     /* TODO:  Reset secondary CPUs.  */
56 }
57
58 static void set_kernel_args(uint32_t ram_size, int initrd_size,
59                             const char *kernel_cmdline,
60                             target_phys_addr_t loader_start)
61 {
62     uint32_t *p;
63
64     p = (uint32_t *)(phys_ram_base + KERNEL_ARGS_ADDR);
65     /* ATAG_CORE */
66     stl_raw(p++, 5);
67     stl_raw(p++, 0x54410001);
68     stl_raw(p++, 1);
69     stl_raw(p++, 0x1000);
70     stl_raw(p++, 0);
71     /* ATAG_MEM */
72     stl_raw(p++, 4);
73     stl_raw(p++, 0x54410002);
74     stl_raw(p++, ram_size);
75     stl_raw(p++, loader_start);
76     if (initrd_size) {
77         /* ATAG_INITRD2 */
78         stl_raw(p++, 4);
79         stl_raw(p++, 0x54420005);
80         stl_raw(p++, loader_start + INITRD_LOAD_ADDR);
81         stl_raw(p++, initrd_size);
82     }
83     if (kernel_cmdline && *kernel_cmdline) {
84         /* ATAG_CMDLINE */
85         int cmdline_size;
86
87         cmdline_size = strlen(kernel_cmdline);
88         memcpy (p + 2, kernel_cmdline, cmdline_size + 1);
89         cmdline_size = (cmdline_size >> 2) + 1;
90         stl_raw(p++, cmdline_size + 2);
91         stl_raw(p++, 0x54410009);
92         p += cmdline_size;
93     }
94     /* ATAG_END */
95     stl_raw(p++, 0);
96     stl_raw(p++, 0);
97 }
98
99 static void set_kernel_args_old(uint32_t ram_size, int initrd_size,
100                                 const char *kernel_cmdline,
101                                 target_phys_addr_t loader_start)
102 {
103     uint32_t *p;
104     unsigned char *s;
105
106     /* see linux/include/asm-arm/setup.h */
107     p = (uint32_t *)(phys_ram_base + KERNEL_ARGS_ADDR);
108     /* page_size */
109     stl_raw(p++, 4096);
110     /* nr_pages */
111     stl_raw(p++, ram_size / 4096);
112     /* ramdisk_size */
113     stl_raw(p++, 0);
114 #define FLAG_READONLY   1
115 #define FLAG_RDLOAD     4
116 #define FLAG_RDPROMPT   8
117     /* flags */
118     stl_raw(p++, FLAG_READONLY | FLAG_RDLOAD | FLAG_RDPROMPT);
119     /* rootdev */
120     stl_raw(p++, (31 << 8) | 0);        /* /dev/mtdblock0 */
121     /* video_num_cols */
122     stl_raw(p++, 0);
123     /* video_num_rows */
124     stl_raw(p++, 0);
125     /* video_x */
126     stl_raw(p++, 0);
127     /* video_y */
128     stl_raw(p++, 0);
129     /* memc_control_reg */
130     stl_raw(p++, 0);
131     /* unsigned char sounddefault */
132     /* unsigned char adfsdrives */
133     /* unsigned char bytes_per_char_h */
134     /* unsigned char bytes_per_char_v */
135     stl_raw(p++, 0);
136     /* pages_in_bank[4] */
137     stl_raw(p++, 0);
138     stl_raw(p++, 0);
139     stl_raw(p++, 0);
140     stl_raw(p++, 0);
141     /* pages_in_vram */
142     stl_raw(p++, 0);
143     /* initrd_start */
144     if (initrd_size)
145         stl_raw(p++, loader_start + INITRD_LOAD_ADDR);
146     else
147         stl_raw(p++, 0);
148     /* initrd_size */
149     stl_raw(p++, initrd_size);
150     /* rd_start */
151     stl_raw(p++, 0);
152     /* system_rev */
153     stl_raw(p++, 0);
154     /* system_serial_low */
155     stl_raw(p++, 0);
156     /* system_serial_high */
157     stl_raw(p++, 0);
158     /* mem_fclk_21285 */
159     stl_raw(p++, 0);
160     /* zero unused fields */
161     memset(p, 0, 256 + 1024 -
162            (p - ((uint32_t *)(phys_ram_base + KERNEL_ARGS_ADDR))));
163     s = phys_ram_base + KERNEL_ARGS_ADDR + 256 + 1024;
164     if (kernel_cmdline)
165         strcpy (s, kernel_cmdline);
166     else
167         stb_raw(s, 0);
168 }
169
170 void arm_load_kernel(CPUState *env, int ram_size, const char *kernel_filename,
171                      const char *kernel_cmdline, const char *initrd_filename,
172                      int board_id, target_phys_addr_t loader_start)
173 {
174     int kernel_size;
175     int initrd_size;
176     int n;
177     int is_linux = 0;
178     uint64_t elf_entry;
179     target_ulong entry;
180
181     /* Load the kernel.  */
182     if (!kernel_filename) {
183         fprintf(stderr, "Kernel image must be specified\n");
184         exit(1);
185     }
186
187     if (!env->kernel_filename) {
188         env->ram_size = ram_size;
189         env->kernel_filename = kernel_filename;
190         env->kernel_cmdline = kernel_cmdline;
191         env->initrd_filename = initrd_filename;
192         env->board_id = board_id;
193         env->loader_start = loader_start;
194         qemu_register_reset(main_cpu_reset, env);
195     }
196     /* Assume that raw images are linux kernels, and ELF images are not.  */
197     kernel_size = load_elf(kernel_filename, 0, &elf_entry, NULL, NULL);
198     entry = elf_entry;
199     if (kernel_size < 0) {
200         kernel_size = load_uboot(kernel_filename, &entry, &is_linux);
201     }
202     if (kernel_size < 0) {
203         kernel_size = load_image(kernel_filename,
204                                  phys_ram_base + KERNEL_LOAD_ADDR);
205         entry = loader_start + KERNEL_LOAD_ADDR;
206         is_linux = 1;
207     }
208     if (kernel_size < 0) {
209         fprintf(stderr, "qemu: could not load kernel '%s'\n", kernel_filename);
210         exit(1);
211     }
212     if (!is_linux) {
213         /* Jump to the entry point.  */
214         env->regs[15] = entry & 0xfffffffe;
215         env->thumb = entry & 1;
216     } else {
217         if (initrd_filename) {
218             initrd_size = load_image(initrd_filename,
219                                      phys_ram_base + INITRD_LOAD_ADDR);
220             if (initrd_size < 0) {
221                 fprintf(stderr, "qemu: could not load initrd '%s'\n",
222                         initrd_filename);
223                 exit(1);
224             }
225         } else {
226             initrd_size = 0;
227         }
228         bootloader[1] |= board_id & 0xff;
229         bootloader[2] |= (board_id >> 8) & 0xff;
230         bootloader[5] = loader_start + KERNEL_ARGS_ADDR;
231         bootloader[6] = entry;
232         for (n = 0; n < sizeof(bootloader) / 4; n++)
233             stl_raw(phys_ram_base + (n * 4), bootloader[n]);
234         for (n = 0; n < sizeof(smpboot) / 4; n++)
235             stl_raw(phys_ram_base + ram_size + (n * 4), smpboot[n]);
236         if (old_param)
237             set_kernel_args_old(ram_size, initrd_size,
238                                 kernel_cmdline, loader_start);
239         else
240             set_kernel_args(ram_size, initrd_size,
241                             kernel_cmdline, loader_start);
242     }
243 }