updated on Thu Jan 26 16:09:46 UTC 2012
[aur-mirror.git] / kvm-opensuse / kvm-qemu-multiboot.patch
blob41436cf2d32efd66a0525fcb9adee7d3ab8f63d8
1 Index: kvm-75/qemu/elf_ops.h
2 ===================================================================
3 --- kvm-75.orig/qemu/elf_ops.h
4 +++ kvm-75/qemu/elf_ops.h
5 @@ -156,6 +156,10 @@ static int glue(load_elf, SZ)(int fd, in
8 if (ELF_MACHINE != ehdr.e_machine)
9 +#if (ELF_MACHINE == EM_X86_64) && !CONFIG_USER_ONLY
10 + /* x86_64 systems can run i386 code as well */
11 + if(ehdr.e_machine != EM_386)
12 +#endif
13 goto fail;
15 if (pentry)
16 --- kvm-81/qemu/hw/pc.c.orig 2008-12-22 19:12:34.000000000 +0100
17 +++ kvm-81/qemu/hw/pc.c 2008-12-22 19:46:46.000000000 +0100
18 @@ -542,6 +542,438 @@
19 return size;
22 +/* Generate an initial boot sector which sets state and jump to
23 + a specified vector */
24 +static void generate_bootsect_multiboot(uint8_t *option_rom,
25 + uint32_t mh_entry_addr, uint32_t bootinfo)
27 + uint8_t rom[512], *p, *reloc, *pgdt, *pmmaploop;
28 + uint8_t sum;
29 + uint32_t ip;
30 + int i;
31 + int mmaploop;
33 + memset(rom, 0, sizeof(rom));
35 + p = rom;
36 + /* Make sure we have an option rom signature */
37 + *p++ = 0x55;
38 + *p++ = 0xaa;
40 + /* ROM size in sectors*/
41 + *p++ = 1;
43 + /* Hook int19 */
45 + *p++ = 0x50; /* push ax */
46 + *p++ = 0x1e; /* push ds */
47 + *p++ = 0x31; *p++ = 0xc0; /* xor ax, ax */
48 + *p++ = 0x8e; *p++ = 0xd8; /* mov ax, ds */
50 + *p++ = 0xc7; *p++ = 0x06; /* movvw _start,0x64 */
51 + *p++ = 0x64; *p++ = 0x00;
52 + reloc = p;
53 + *p++ = 0x00; *p++ = 0x00;
55 + *p++ = 0x8c; *p++ = 0x0e; /* mov cs,0x66 */
56 + *p++ = 0x66; *p++ = 0x00;
58 + *p++ = 0x1f; /* pop ds */
59 + *p++ = 0x58; /* pop ax */
60 + *p++ = 0xcb; /* lret */
62 + /* Actual code */
63 + *reloc = (p - rom);
65 + *p++ = 0xfa; /* CLI */
66 + *p++ = 0xfc; /* CLD */
68 + // 660f011528000000 lgdt [0x28]
69 + *p++ = 0x66; /* 32-bit operand size */
70 + *p++ = 0x67; /* 32-bit addr size */
71 + *p++ = 0x0f; /* LGDT [0x128] */
72 + *p++ = 0x01;
73 + *p++ = 0x15;
74 + pgdt=p; /* we calculate the gdt position later */
75 + p+=4;
77 + /* Initialize multiboot mmap structs using the 0x15(e820) */
78 + *p++ = 0x31; /* XOR BX,BX */
79 + *p++ = 0xdb;
81 + *p++ = 0x66; /* 32-bit operand size */
82 + *p++ = 0x67; /* 32-bit addr size */
83 + *p++ = 0xbf; /* MOV EDI,0x9004 */
84 + *p++ = 0x04;
85 + *p++ = 0x90;
86 + *p++ = 0x00;
87 + *p++ = 0x00;
89 + pmmaploop = p;
90 + *p++ = 0x66; /* 32-bit operand size */
91 + *p++ = 0x67; /* 32-bit addr size */
92 + *p++ = 0xb8; /* MOV EAX,0x20 */
93 + *p++ = 0x20;
94 + *p++ = 0x00;
95 + *p++ = 0x00;
96 + *p++ = 0x00;
98 + *p++ = 0x66; /* 32-bit operand size */
99 + *p++ = 0x67; /* 32-bit addr size */
100 + *p++ = 0x89; /* MOV -4(EDI),EAX */
101 + *p++ = 0x47;
102 + *p++ = 0xfc;
104 + *p++ = 0x66; /* 32-bit operand size */
105 + *p++ = 0x67; /* 32-bit addr size */
106 + *p++ = 0xb8; /* MOV EAX,0x0000e820 */
107 + *p++ = 0x20;
108 + *p++ = 0xe8;
109 + *p++ = 0x00;
110 + *p++ = 0x00;
112 + *p++ = 0x66; /* 32-bit operand size */
113 + *p++ = 0x67; /* 32-bit addr size */
114 + *p++ = 0xba; /* MOV EDX,0x534d4150 */
115 + *p++ = 0x50;
116 + *p++ = 0x41;
117 + *p++ = 0x4d;
118 + *p++ = 0x53;
120 + *p++ = 0x66; /* 32-bit operand size */
121 + *p++ = 0x67; /* 32-bit addr size */
122 + *p++ = 0xb9; /* MOV ECX,0x20 */
123 + *p++ = 0x20;
124 + *p++ = 0x00;
125 + *p++ = 0x00;
126 + *p++ = 0x00;
128 + *p++ = 0xcd; /* INT 0x15 */
129 + *p++ = 0x15;
131 + *p++ = 0x66; /* 32-bit operand size */
132 + *p++ = 0x67; /* 32-bit addr size */
133 + *p++ = 0xb8; /* MOV EAX, 0x24 */
134 + *p++ = 0x24;
135 + *p++ = 0x00;
136 + *p++ = 0x00;
137 + *p++ = 0x00;
139 + *p++ = 0xf7; /* MUL AX, BX */
140 + *p++ = 0xe3;
142 + *p++ = 0x66; /* 32-bit operand size */
143 + *p++ = 0x67; /* 32-bit addr size */
144 + *p++ = 0x21; /* AND EBX, EBX */
145 + *p++ = 0xdb;
147 + /* don't store if bx = 0 */
148 + *p++ = 0x66; /* 32-bit operand size */
149 + *p++ = 0x67; /* 32-bit addr size */
150 + *p++ = 0x0f; /* JZ next instruction */
151 + *p++ = 0x84;
152 + *p++ = 0x07;
153 + *p++ = 0x00;
154 + *p++ = 0x00;
155 + *p++ = 0x00;
157 + /* store the amount of blocks in the bootinfo struct */
158 + *p++ = 0x66; /* 32-bit operand size */
159 + *p++ = 0x67; /* 32-bit addr size */
160 + *p++ = 0xa3; /* MOV [bootinfo+0x2c], EAX */
161 + *p++ = (bootinfo+0x2c);
162 + *p++ = (bootinfo+0x2c) >> 8;
163 + *p++ = (bootinfo+0x2c) >> 16;
164 + *p++ = (bootinfo+0x2c) >> 24;
166 + *p++ = 0x66; /* 32-bit operand size */
167 + *p++ = 0x67; /* 32-bit addr size */
168 + *p++ = 0x05; /* ADD EAX, 0x9004 */
169 + *p++ = 0x04;
170 + *p++ = 0x90;
171 + *p++ = 0x00;
172 + *p++ = 0x00;
174 + *p++ = 0x89; /* MOV DI, AX */
175 + *p++ = 0xc7;
177 + *p++ = 0x66; /* 32-bit operand size */
178 + *p++ = 0x67; /* 32-bit addr size */
179 + *p++ = 0x21; /* AND EBX, EBX */
180 + *p++ = 0xdb;
182 + /* process next entry */
183 + *p++ = 0x66; /* 32-bit operand size */
184 + *p++ = 0x67; /* 32-bit addr size */
185 + *p++ = 0x0f; /* JNZ mmaploop */
186 + *p++ = 0x85;
187 + mmaploop = (int)((long)pmmaploop) - ((long)p) - 4;
188 + *p++ = mmaploop;
189 + *p++ = mmaploop >> 8;
190 + *p++ = mmaploop >> 16;
191 + *p++ = mmaploop >> 24;
193 + /* get us to protected mode now */
195 + *p++ = 0x66;
196 + *p++ = 0xb8; /* MOV EAX,0x01 */
197 + *p++ = 0x01;
198 + *p++ = 0x00;
199 + *p++ = 0x00;
200 + *p++ = 0x00;
202 + *p++ = 0x0f; /* MOV CR0,EAX */
203 + *p++ = 0x22;
204 + *p++ = 0xc0;
206 + /* the JMP sets CS for us and gets us to 32-bit */
207 + ip = 0x000d0000 + (p - rom) + 8; // set i to the IP after the JMP // XXX
208 + *p++ = 0x66; /* 32-bit operand size */
209 + *p++ = 0xea; /* JMP */
210 + *p++ = ip; /* IP */
211 + *p++ = ip >> 8;
212 + *p++ = ip >> 16;
213 + *p++ = ip >> 24;
214 + *p++ = 0x08;
215 + *p++ = 0x00;
217 + /* initialize all other segments */
218 + *p++ = 0xb8; /* MOV EAX,0x10 */
219 + *p++ = 0x10;
220 + *p++ = 0x00;
221 + *p++ = 0x00;
222 + *p++ = 0x00;
223 + for (i = 0; i < 6; i++) {
224 + if (i == 1) /* Skip CS */
225 + continue;
227 + *p++ = 0x8e; /* MOV <seg>,EAX */
228 + *p++ = 0xc0 + (i << 3);
231 + /* EBX contains a pointer to the bootinfo struct */
232 + *p++ = 0xbb; /* MOV EBX,imm32 */
233 + *p++ = bootinfo;
234 + *p++ = bootinfo >> 8;
235 + *p++ = bootinfo >> 16;
236 + *p++ = bootinfo >> 24;
238 + /* EAX has to contain the following magic */
239 + *p++ = 0xb8; /* MOV EAX,0x2badb002 */
240 + *p++ = 0x02;
241 + *p++ = 0xb0;
242 + *p++ = 0xad;
243 + *p++ = 0x2b;
245 + /* Jump off to the kernel */
246 + *p++ = 0xea; /* JMP */
247 + *p++ = mh_entry_addr; /* IP */
248 + *p++ = mh_entry_addr >> 8;
249 + *p++ = mh_entry_addr >> 16;
250 + *p++ = mh_entry_addr >> 24;
251 + *p++ = 0x08;
252 + *p++ = 0x00;
254 + { /* GDT loading */
255 + uint32_t gdt_base = 0x000d0000 + (p - rom); // 0x00007c00 is the first IP; // XXX
256 + uint32_t gdtr = gdt_base + 0x28;
257 + uint8_t gdt[] = { // GDT base: 0x00000100
258 + // 0x00
259 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
260 + // 0x08: code segment (base=0, limit=0xfffff, type=32bit code exec/read, DPL=0, 4k)
261 + 0xff, 0xff, 0x00, 0x00, 0x00, 0x9a, 0xcf, 0x00,
262 + // 0x10: data segment (base=0, limit=0xfffff, type=32bit data read/write, DPL=0, 4k)
263 + 0xff, 0xff, 0x00, 0x00, 0x00, 0x92, 0xcf, 0x00,
264 + // 0x18: code segment (base=0, limit=0x0ffff, type=16bit code exec/read/conf, DPL=0, 1b)
265 + 0xff, 0xff, 0x00, 0x00, 0x00, 0x9e, 0x00, 0x00,
266 + // 0x20: data segment (base=0, limit=0x0ffff, type=16bit data read/write, DPL=0, 1b)
267 + 0xff, 0xff, 0x00, 0x00, 0x00, 0x92, 0x00, 0x00,
268 + // 0x28: gdtdesc
269 + 0x27, 0x00, gdt_base, gdt_base >> 8, gdt_base >> 16, gdt_base >> 24
270 + };
272 + memcpy(p, gdt, sizeof(gdt));
273 + p+=sizeof(gdt);
274 + *pgdt++ = gdtr;
275 + *pgdt++ = gdtr >> 8;
276 + *pgdt++ = gdtr >> 16;
277 + *pgdt++ = gdtr >> 24;
280 + fprintf(stderr, "qemu: multiboot loader code is %d bytes long.\n", (int)(p-rom));
282 + /* sign rom */
283 + sum = 0;
284 + for (i = 0; i < (sizeof(rom) - 1); i++)
285 + sum += rom[i];
286 + rom[sizeof(rom) - 1] = -sum;
288 + memcpy(option_rom, rom, sizeof(rom));
291 +static int load_multiboot(uint8_t *option_rom,
292 + FILE *f,
293 + const char *kernel_filename,
294 + const char *initrd_filename,
295 + const char *kernel_cmdline,
296 + uint8_t *header)
298 + int i, is_multiboot = 0;
299 + uint32_t flags = 0;
300 + uint32_t mh_entry_addr;
301 + uint32_t mh_load_addr;
302 + uint32_t mb_kernel_size;
303 + uint32_t mb_bootinfo = 0x90000;
304 + uint32_t tmp_size;
306 + // Ok, let's see if it is a multiboot image
307 + for(i = 0; i < 8144; i += 4) { // the header is 12x32bit long, so
308 + // the latest entry may be 8192 - 48
309 + if(ldl_p(header+i) == 0x1BADB002) {
310 + uint32_t checksum = ldl_p(header+i+8);
311 + flags = ldl_p(header+i+4);
312 + checksum += flags;
313 + checksum += (uint32_t)0x1BADB002;
314 + if(!checksum) {
315 + is_multiboot = 1;
316 + break;
321 + if(!is_multiboot) return 0; // no multiboot
322 + fprintf(stderr, "qemu: I believe we found a multiboot image!\n");
324 + if(flags & 0x00000004) { // MULTIBOOT_HEADER_HAS_VBE
325 + fprintf(stderr, "qemu: multiboot knows VBE. we don't.\n");
326 + }
327 + if(!(flags & 0x00010000)) { // MULTIBOOT_HEADER_HAS_ADDR
328 + uint64_t elf_entry;
329 + int kernel_size;
330 + fclose(f);
331 + kernel_size = load_elf(kernel_filename, 0, &elf_entry, NULL, NULL);
332 + if(kernel_size < 0) {
333 + fprintf(stderr, "Error while loading elf kernel\n");
334 + exit(1);
336 + mh_load_addr = mh_entry_addr = elf_entry;
337 + mb_kernel_size = kernel_size;
339 + fprintf(stderr, "qemu: loading multiboot-elf kernel (%#x bytes) with entry %#zx\n",
340 + mb_kernel_size, (size_t)mh_entry_addr);
341 + } else {
342 + /* Valid if mh_flags sets MULTIBOOT_HEADER_HAS_ADDR. */
343 + uint32_t mh_header_addr = ldl_p(header+i+12);
344 + mh_load_addr = ldl_p(header+i+16);
345 + uint32_t mh_load_end_addr = ldl_p(header+i+20);
346 + uint32_t mh_bss_end_addr = ldl_p(header+i+24);
347 + uint8_t *mb_kernel_addr = phys_ram_base + (mh_load_addr);
348 + uint32_t mb_kernel_text_offset = i - (mh_header_addr - mh_load_addr);
350 + mh_entry_addr = ldl_p(header+i+28);
351 + mb_kernel_size = get_file_size(f) - mb_kernel_text_offset;
353 + /* Valid if mh_flags sets MULTIBOOT_HEADER_HAS_VBE.
354 + uint32_t mh_mode_type = ldl_p(header+i+32);
355 + uint32_t mh_width = ldl_p(header+i+36);
356 + uint32_t mh_height = ldl_p(header+i+40);
357 + uint32_t mh_depth = ldl_p(header+i+44); */
359 + fprintf(stderr, "multiboot: mh_header_addr = %#x\n", mh_header_addr);
360 + fprintf(stderr, "multiboot: mh_load_addr = %#x\n", mh_load_addr);
361 + fprintf(stderr, "multiboot: mh_load_end_addr = %#x\n", mh_load_end_addr);
362 + fprintf(stderr, "multiboot: mh_bss_end_addr = %#x\n", mh_bss_end_addr);
364 + fseek(f, mb_kernel_text_offset, SEEK_SET);
366 + fprintf(stderr, "qemu: loading multiboot kernel (%#x bytes) at %#zx\n",
367 + mb_kernel_size, mb_kernel_addr - phys_ram_base);
369 + if ((tmp_size=fread(mb_kernel_addr, 1, mb_kernel_size, f)) != mb_kernel_size) {
370 + fprintf(stderr, "qemu: read error on multiboot kernel '%s' (%#x != %#x)\n", kernel_filename, tmp_size, mb_kernel_size);
371 + exit(1);
373 + fclose(f);
377 + // load modules
379 + stl_p(phys_ram_base + mb_bootinfo + 20, 0x0); // mods_count
380 + if(initrd_filename) {
381 + uint32_t mb_mod_info = mb_bootinfo + 0x100;
382 + uint32_t mb_mod_cmdline = mb_bootinfo+ 0x300;
383 + uint32_t mb_mod_start = mh_load_addr;
384 + uint32_t mb_mod_length = mb_kernel_size;
385 + char *next_initrd;
386 + char *next_space;
387 + int mb_mod_count = 0;
389 + do {
390 + next_initrd = strchr(initrd_filename, ',');
391 + if(next_initrd)
392 + *next_initrd = '\0';
393 + /* if a space comes after the module filename, treat everything after that as parameters */
394 + strcpy(phys_ram_base + mb_mod_cmdline, initrd_filename);
395 + stl_p(phys_ram_base + mb_mod_info + 8, mb_mod_cmdline); // string
396 + mb_mod_cmdline += strlen(initrd_filename) + 1;
397 + if(next_space = strchr(initrd_filename, ' '))
398 + *next_space = '\0';
399 +printf("multiboot loading module: %s\n", initrd_filename);
400 + f = fopen(initrd_filename, "rb");
401 + if(f) {
402 + mb_mod_start = (mb_mod_start + mb_mod_length + (TARGET_PAGE_SIZE - 1))
403 + & (TARGET_PAGE_MASK);
404 + mb_mod_length = get_file_size(f);
406 + if ((tmp_size=fread((phys_ram_base + mb_mod_start), 1, mb_mod_length, f))
407 + != mb_mod_length) {
408 + fprintf(stderr, "qemu: read error on multiboot module '%s' (%#x != %#x)\n",
409 + initrd_filename, tmp_size, mb_mod_length);
410 + exit(1);
413 + mb_mod_count++;
414 + stl_p(phys_ram_base + mb_mod_info + 0, mb_mod_start);
415 + stl_p(phys_ram_base + mb_mod_info + 4, mb_mod_start + mb_mod_length);
416 +printf("mod_start: %#x\nmod_end: %#x\n", mb_mod_start, mb_mod_start + mb_mod_length);
417 + stl_p(phys_ram_base + mb_mod_info + 12, 0x0); // reserved
419 + initrd_filename = next_initrd+1;
420 + mb_mod_info += 16;
421 + } while(next_initrd);
422 + stl_p(phys_ram_base + mb_bootinfo + 20, mb_mod_count); // mods_count
423 + stl_p(phys_ram_base + mb_bootinfo + 24, mb_bootinfo + 0x100); // mods_addr
426 + /* Commandline support */
427 + stl_p(phys_ram_base + mb_bootinfo + 16, mb_bootinfo + 0x200);
428 + strcpy((char*)(phys_ram_base + mb_bootinfo + 0x200), kernel_cmdline);
430 + // the kernel is where we want it to be now
432 +#define MULTIBOOT_FLAGS_MEMORY (1 << 0)
433 +#define MULTIBOOT_FLAGS_BOOT_DEVICE (1 << 1)
434 +#define MULTIBOOT_FLAGS_CMDLINE (1 << 2)
435 +#define MULTIBOOT_FLAGS_MODULES (1 << 3)
436 +#define MULTIBOOT_FLAGS_MMAP (1 << 6)
437 + stl_p(phys_ram_base + mb_bootinfo, MULTIBOOT_FLAGS_MEMORY
438 + | MULTIBOOT_FLAGS_BOOT_DEVICE
439 + | MULTIBOOT_FLAGS_CMDLINE
440 + | MULTIBOOT_FLAGS_MODULES
441 + | MULTIBOOT_FLAGS_MMAP);
442 + stl_p(phys_ram_base + mb_bootinfo + 4, 640 * 1024); // mem_lower
443 + stl_p(phys_ram_base + mb_bootinfo + 8, ram_size); // mem_upper
444 + stl_p(phys_ram_base + mb_bootinfo + 12, 0x8001ffff); // XXX: use the -boot switch?
445 + stl_p(phys_ram_base + mb_bootinfo + 48, 0x9000); // mmap_addr
447 + fprintf(stderr, "multiboot: mh_entry_addr = %#x\n", mh_entry_addr);
449 + generate_bootsect_multiboot(option_rom, mh_entry_addr, mb_bootinfo);
451 + return 1; // yes, we are multiboot
454 static void load_linux(uint8_t *option_rom,
455 const char *kernel_filename,
456 const char *initrd_filename,
457 @@ -553,7 +985,7 @@
458 uint16_t real_seg;
459 int setup_size, kernel_size, initrd_size, cmdline_size;
460 uint32_t initrd_max;
461 - uint8_t header[1024];
462 + uint8_t header[8192];
463 target_phys_addr_t real_addr, prot_addr, cmdline_addr, initrd_addr;
464 FILE *f, *fi;
466 @@ -563,7 +995,7 @@
467 /* load the kernel header */
468 f = fopen(kernel_filename, "rb");
469 if (!f || !(kernel_size = get_file_size(f)) ||
470 - fread(header, 1, 1024, f) != 1024) {
471 + fread(header, 1, 8192, f) != 8192) {
472 fprintf(stderr, "qemu: could not load kernel '%s'\n",
473 kernel_filename);
474 exit(1);
475 @@ -573,10 +1005,15 @@
476 #if 0
477 fprintf(stderr, "header magic: %#x\n", ldl_p(header+0x202));
478 #endif
479 - if (ldl_p(header+0x202) == 0x53726448)
480 - protocol = lduw_p(header+0x206);
481 - else
482 - protocol = 0;
483 + if (ldl_p(header+0x202) == 0x53726448) {
484 + protocol = lduw_p(header+0x206);
485 + } else {
486 + // This looks like a multiboot kernel. If it is, let's stop
487 + // treating it like Linux.
488 + if(load_multiboot(option_rom,f,kernel_filename,initrd_filename, kernel_cmdline, header))
489 + return;
490 + protocol = 0;
493 if (protocol < 0x200 || !(header[0x211] & 0x01)) {
494 /* Low kernel */
495 @@ -669,7 +1106,7 @@
498 /* store the finalized header and load the rest of the kernel */
499 - cpu_physical_memory_write(real_addr, header, 1024);
500 + cpu_physical_memory_write(real_addr, header, 8192);
502 setup_size = header[0x1f1];
503 if (setup_size == 0)
504 @@ -678,7 +1115,7 @@
505 setup_size = (setup_size+1)*512;
506 kernel_size -= setup_size; /* Size of protected-mode code */
508 - if (!fread_targphys_ok(real_addr+1024, setup_size-1024, f) ||
509 + if (!fread_targphys_ok(real_addr+8192, setup_size-8192, f) ||
510 !fread_targphys_ok(prot_addr, kernel_size, f)) {
511 fprintf(stderr, "qemu: read error on kernel '%s'\n",
512 kernel_filename);