From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mailman by lists.gnu.org with tmda-scanned (Exim 4.43) id 1LU3DN-0007HG-Rv for qemu-devel@nongnu.org; Mon, 02 Feb 2009 13:08:09 -0500 Received: from exim by lists.gnu.org with spam-scanned (Exim 4.43) id 1LU3DM-0007Gr-Vj for qemu-devel@nongnu.org; Mon, 02 Feb 2009 13:08:09 -0500 Received: from [199.232.76.173] (port=41749 helo=monty-python.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1LU3DM-0007Gl-Jy for qemu-devel@nongnu.org; Mon, 02 Feb 2009 13:08:08 -0500 Received: from mr01.hansenet.de ([213.191.74.10]:59995) by monty-python.gnu.org with esmtp (Exim 4.60) (envelope-from ) id 1LU3DL-0002nZ-JO for qemu-devel@nongnu.org; Mon, 02 Feb 2009 13:08:08 -0500 Message-ID: <49873680.2040603@exactcode.de> Date: Mon, 02 Feb 2009 19:08:00 +0100 From: Rene Rebe MIME-Version: 1.0 Content-Type: text/plain; charset=ISO-8859-1; format=flowed Content-Transfer-Encoding: Quoted-Printable Subject: [Qemu-devel] [PATCH] Add multi-boot kernel loading support Reply-To: qemu-devel@nongnu.org List-Id: qemu-devel.nongnu.org List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , To: qemu-devel@nongnu.org, Alexander Graf Hi all, Alexander Graf implemented multi-boot kernel loading during his work to run Darwin inside Qemu/KVM. As the boot loader expects to load the kernel in an EFI environment a custom booter is used to load the kernel using a legacy BIOS. This is a port of the patch to the new extload / INT 19 machinery (including minor cleanups). Signed-off-by: Ren=E9 Rebe Index: elf_ops.h =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D --- elf_ops.h (revision 6501) +++ elf_ops.h (working copy) @@ -195,6 +195,10 @@ } if (ELF_MACHINE !=3D ehdr.e_machine) +#if (ELF_MACHINE =3D=3D EM_X86_64) && !defined(CONFIG_USER_ONLY) + /* x86_64 systems can run i386 code as well */ + if(ehdr.e_machine !=3D EM_386) +#endif goto fail; if (pentry) Index: hw/pc.c =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D --- hw/pc.c (revision 6501) +++ hw/pc.c (working copy) @@ -533,6 +533,438 @@ return size; } +/* Generate an initial boot sector which sets state and jump to + a specified vector */ +static void generate_bootsect_multiboot(uint8_t *option_rom, + uint32_t mh_entry_addr, uint32_t= bootinfo) +{ + uint8_t rom[512], *p, *reloc, *pgdt, *pmmaploop; + uint8_t sum; + uint32_t ip; + int i; + int mmaploop; + + memset(rom, 0, sizeof(rom)); + + p =3D rom; + /* Make sure we have an option rom signature */ + *p++ =3D 0x55; + *p++ =3D 0xaa; + + /* ROM size in sectors*/ + *p++ =3D 1; + + /* Hook int19 */ + + *p++ =3D 0x50; /* push ax */ + *p++ =3D 0x1e; /* push ds */ + *p++ =3D 0x31; *p++ =3D 0xc0; /* xor ax, ax */ + *p++ =3D 0x8e; *p++ =3D 0xd8; /* mov ax, ds */ + + *p++ =3D 0xc7; *p++ =3D 0x06; /* movvw _start,0x64 */ + *p++ =3D 0x64; *p++ =3D 0x00; + reloc =3D p; + *p++ =3D 0x00; *p++ =3D 0x00; + + *p++ =3D 0x8c; *p++ =3D 0x0e; /* mov cs,0x66 */ + *p++ =3D 0x66; *p++ =3D 0x00; + + *p++ =3D 0x1f; /* pop ds */ + *p++ =3D 0x58; /* pop ax */ + *p++ =3D 0xcb; /* lret */ + + /* Actual code */ + *reloc =3D (p - rom); + + *p++ =3D 0xfa; /* CLI */ + *p++ =3D 0xfc; /* CLD */ + + /* 660f011528000000 lgdt [0x28] */ + *p++ =3D 0x66; /* 32-bit operand size */ + *p++ =3D 0x67; /* 32-bit addr size */ + *p++ =3D 0x0f; /* LGDT [0x128] */ + *p++ =3D 0x01; + *p++ =3D 0x15; + pgdt=3Dp; /* we calculate the gdt position later */ + p+=3D4; + + /* Initialize multiboot mmap structs using the 0x15(e820) */ + *p++ =3D 0x31; /* XOR BX,BX */ + *p++ =3D 0xdb; + + *p++ =3D 0x66; /* 32-bit operand size */ + *p++ =3D 0x67; /* 32-bit addr size */ + *p++ =3D 0xbf; /* MOV EDI,0x9004 */ + *p++ =3D 0x04; + *p++ =3D 0x90; + *p++ =3D 0x00; + *p++ =3D 0x00; + + pmmaploop =3D p; + *p++ =3D 0x66; /* 32-bit operand size */ + *p++ =3D 0x67; /* 32-bit addr size */ + *p++ =3D 0xb8; /* MOV EAX,0x20 */ + *p++ =3D 0x20; + *p++ =3D 0x00; + *p++ =3D 0x00; + *p++ =3D 0x00; + + *p++ =3D 0x66; /* 32-bit operand size */ + *p++ =3D 0x67; /* 32-bit addr size */ + *p++ =3D 0x89; /* MOV -4(EDI),EAX */ + *p++ =3D 0x47; + *p++ =3D 0xfc; + + *p++ =3D 0x66; /* 32-bit operand size */ + *p++ =3D 0x67; /* 32-bit addr size */ + *p++ =3D 0xb8; /* MOV EAX,0x0000e820 */ + *p++ =3D 0x20; + *p++ =3D 0xe8; + *p++ =3D 0x00; + *p++ =3D 0x00; + + *p++ =3D 0x66; /* 32-bit operand size */ + *p++ =3D 0x67; /* 32-bit addr size */ + *p++ =3D 0xba; /* MOV EDX,0x534d4150 */ + *p++ =3D 0x50; + *p++ =3D 0x41; + *p++ =3D 0x4d; + *p++ =3D 0x53; + + *p++ =3D 0x66; /* 32-bit operand size */ + *p++ =3D 0x67; /* 32-bit addr size */ + *p++ =3D 0xb9; /* MOV ECX,0x20 */ + *p++ =3D 0x20; + *p++ =3D 0x00; + *p++ =3D 0x00; + *p++ =3D 0x00; + + *p++ =3D 0xcd; /* INT 0x15 */ + *p++ =3D 0x15; + + *p++ =3D 0x66; /* 32-bit operand size */ + *p++ =3D 0x67; /* 32-bit addr size */ + *p++ =3D 0xb8; /* MOV EAX, 0x24 */ + *p++ =3D 0x24; + *p++ =3D 0x00; + *p++ =3D 0x00; + *p++ =3D 0x00; + + *p++ =3D 0xf7; /* MUL AX, BX */ + *p++ =3D 0xe3; + + *p++ =3D 0x66; /* 32-bit operand size */ + *p++ =3D 0x67; /* 32-bit addr size */ + *p++ =3D 0x21; /* AND EBX, EBX */ + *p++ =3D 0xdb; + + /* don't store if bx =3D 0 */ + *p++ =3D 0x66; /* 32-bit operand size */ + *p++ =3D 0x67; /* 32-bit addr size */ + *p++ =3D 0x0f; /* JZ next instruction */ + *p++ =3D 0x84; + *p++ =3D 0x07; + *p++ =3D 0x00; + *p++ =3D 0x00; + *p++ =3D 0x00; + + /* store the amount of blocks in the bootinfo struct */ + *p++ =3D 0x66; /* 32-bit operand size */ + *p++ =3D 0x67; /* 32-bit addr size */ + *p++ =3D 0xa3; /* MOV [bootinfo+0x2c], EAX */ + *p++ =3D (bootinfo+0x2c); + *p++ =3D (bootinfo+0x2c) >> 8; + *p++ =3D (bootinfo+0x2c) >> 16; + *p++ =3D (bootinfo+0x2c) >> 24; + + *p++ =3D 0x66; /* 32-bit operand size */ + *p++ =3D 0x67; /* 32-bit addr size */ + *p++ =3D 0x05; /* ADD EAX, 0x9004 */ + *p++ =3D 0x04; + *p++ =3D 0x90; + *p++ =3D 0x00; + *p++ =3D 0x00; + + *p++ =3D 0x89; /* MOV DI, AX */ + *p++ =3D 0xc7; + + *p++ =3D 0x66; /* 32-bit operand size */ + *p++ =3D 0x67; /* 32-bit addr size */ + *p++ =3D 0x21; /* AND EBX, EBX */ + *p++ =3D 0xdb; + + /* process next entry */ + *p++ =3D 0x66; /* 32-bit operand size */ + *p++ =3D 0x67; /* 32-bit addr size */ + *p++ =3D 0x0f; /* JNZ mmaploop */ + *p++ =3D 0x85; + mmaploop =3D (int)((long)pmmaploop) - ((long)p) - 4; + *p++ =3D mmaploop; + *p++ =3D mmaploop >> 8; + *p++ =3D mmaploop >> 16; + *p++ =3D mmaploop >> 24; + + /* get us to protected mode now */ + + *p++ =3D 0x66; + *p++ =3D 0xb8; /* MOV EAX,0x01 */ + *p++ =3D 0x01; + *p++ =3D 0x00; + *p++ =3D 0x00; + *p++ =3D 0x00; + + *p++ =3D 0x0f; /* MOV CR0,EAX */ + *p++ =3D 0x22; + *p++ =3D 0xc0; + + /* the JMP sets CS for us and gets us to 32-bit */ + ip =3D 0x000d0000 + (p - rom) + 8; /* set i to the IP after the JMP = */ + *p++ =3D 0x66; /* 32-bit operand size */ + *p++ =3D 0xea; /* JMP */ + *p++ =3D ip; /* IP */ + *p++ =3D ip >> 8; + *p++ =3D ip >> 16; + *p++ =3D ip >> 24; + *p++ =3D 0x08; + *p++ =3D 0x00; + + /* initialize all other segments */ + *p++ =3D 0xb8; /* MOV EAX,0x10 */ + *p++ =3D 0x10; + *p++ =3D 0x00; + *p++ =3D 0x00; + *p++ =3D 0x00; + for (i =3D 0; i < 6; i++) { + if (i =3D=3D 1) /* Skip CS */ + continue; + + *p++ =3D 0x8e; /* MOV ,EAX */ + *p++ =3D 0xc0 + (i << 3); + } + + /* EBX contains a pointer to the bootinfo struct */ + *p++ =3D 0xbb; /* MOV EBX,imm32 */ + *p++ =3D bootinfo; + *p++ =3D bootinfo >> 8; + *p++ =3D bootinfo >> 16; + *p++ =3D bootinfo >> 24; + + /* EAX has to contain the following magic */ + *p++ =3D 0xb8; /* MOV EAX,0x2badb002 */ + *p++ =3D 0x02; + *p++ =3D 0xb0; + *p++ =3D 0xad; + *p++ =3D 0x2b; + + /* Jump off to the kernel */ + *p++ =3D 0xea; /* JMP */ + *p++ =3D mh_entry_addr; /* IP */ + *p++ =3D mh_entry_addr >> 8; + *p++ =3D mh_entry_addr >> 16; + *p++ =3D mh_entry_addr >> 24; + *p++ =3D 0x08; + *p++ =3D 0x00; + + { /* GDT loading */ + uint32_t gdt_base =3D 0x000d0000 + (p - rom); /* 0x00007c00 is t= he first IP */ + uint32_t gdtr =3D gdt_base + 0x28; + uint8_t gdt[] =3D { /* GDT base: 0x00000100 */ + /* 0x00 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + /* 0x08: code segment (base=3D0, limit=3D0xfffff, type=3D32b= it code exec/read, DPL=3D0, 4k) */ + 0xff, 0xff, 0x00, 0x00, 0x00, 0x9a, 0xcf, 0x00, + /* 0x10: data segment (base=3D0, limit=3D0xfffff, type=3D32b= it data read/write, DPL=3D0, 4k) */ + 0xff, 0xff, 0x00, 0x00, 0x00, 0x92, 0xcf, 0x00, + /* 0x18: code segment (base=3D0, limit=3D0x0ffff, type=3D16b= it code exec/read/conf, DPL=3D0, 1b) */ + 0xff, 0xff, 0x00, 0x00, 0x00, 0x9e, 0x00, 0x00, + /* 0x20: data segment (base=3D0, limit=3D0x0ffff, type=3D16b= it data read/write, DPL=3D0, 1b) */ + 0xff, 0xff, 0x00, 0x00, 0x00, 0x92, 0x00, 0x00, + /* 0x28: gdtdesc */ + 0x27, 0x00, gdt_base, gdt_base >> 8, gdt_base >> 16, gdt_bas= e >> 24 + }; + + memcpy(p, gdt, sizeof(gdt)); + p+=3Dsizeof(gdt); + *pgdt++ =3D gdtr; + *pgdt++ =3D gdtr >> 8; + *pgdt++ =3D gdtr >> 16; + *pgdt++ =3D gdtr >> 24; + } + + fprintf(stderr, "qemu: multiboot loader code is %d bytes long.\n", (= int)(p-rom)); + + /* sign rom */ + sum =3D 0; + for (i =3D 0; i < (sizeof(rom) - 1); i++) + sum +=3D rom[i]; + rom[sizeof(rom) - 1] =3D -sum; + + memcpy(option_rom, rom, sizeof(rom)); +} + +static int load_multiboot(uint8_t *option_rom, + FILE *f, + const char *kernel_filename, + const char *initrd_filename, + const char *kernel_cmdline, + uint8_t *header) +{ + int i, is_multiboot =3D 0; + uint32_t flags =3D 0; + uint32_t mh_entry_addr; + uint32_t mh_load_addr; + uint32_t mb_kernel_size; + uint32_t mb_bootinfo =3D 0x90000; + uint32_t tmp_size; + + /* Ok, let's see if it is a multiboot image */ + for(i =3D 0; i < 8144; i +=3D 4) { /* the header is 12x32bit long, s= o */ + /* the latest entry may be 8192 - 48 = */ + if(ldl_p(header+i) =3D=3D 0x1BADB002) { + uint32_t checksum =3D ldl_p(header+i+8); + flags =3D ldl_p(header+i+4); + checksum +=3D flags; + checksum +=3D (uint32_t)0x1BADB002; + if(!checksum) { + is_multiboot =3D 1; + break; + } + } + } + + if(!is_multiboot) return 0; /* no multiboot */ + fprintf(stderr, "qemu: I believe we found a multiboot image!\n"); + + if(flags & 0x00000004) { /* MULTIBOOT_HEADER_HAS_VBE */ + fprintf(stderr, "qemu: multiboot knows VBE. we don't.\n"); + } + if(!(flags & 0x00010000)) { /* MULTIBOOT_HEADER_HAS_ADDR */ + uint64_t elf_entry; + int kernel_size; + fclose(f); + kernel_size =3D load_elf(kernel_filename, 0, &elf_entry, NULL, N= ULL); + if(kernel_size < 0) { + fprintf(stderr, "Error while loading elf kernel\n"); + exit(1); + } + mh_load_addr =3D mh_entry_addr =3D elf_entry; + mb_kernel_size =3D kernel_size; + + fprintf(stderr, "qemu: loading multiboot-elf kernel (%#x bytes) = with entry %#zx\n", + mb_kernel_size, (size_t)mh_entry_addr); + } else { + /* Valid if mh_flags sets MULTIBOOT_HEADER_HAS_ADDR. */ + uint32_t mh_header_addr =3D ldl_p(header+i+12); + mh_load_addr =3D ldl_p(header+i+16); + uint32_t mh_load_end_addr =3D ldl_p(header+i+20); + uint32_t mh_bss_end_addr =3D ldl_p(header+i+24); + uint8_t *mb_kernel_addr =3D phys_ram_base + (mh_load_addr); + uint32_t mb_kernel_text_offset =3D i - (mh_header_addr - mh_load= _addr); + + mh_entry_addr =3D ldl_p(header+i+28); + mb_kernel_size =3D get_file_size(f) - mb_kernel_text_offset; + + /* Valid if mh_flags sets MULTIBOOT_HEADER_HAS_VBE. + uint32_t mh_mode_type =3D ldl_p(header+i+32); + uint32_t mh_width =3D ldl_p(header+i+36); + uint32_t mh_height =3D ldl_p(header+i+40); + uint32_t mh_depth =3D ldl_p(header+i+44); */ + + fprintf(stderr, "multiboot: mh_header_addr =3D %#x\n", mh_header= _addr); + fprintf(stderr, "multiboot: mh_load_addr =3D %#x\n", mh_load_add= r); + fprintf(stderr, "multiboot: mh_load_end_addr =3D %#x\n", mh_load= _end_addr); + fprintf(stderr, "multiboot: mh_bss_end_addr =3D %#x\n", mh_bss_e= nd_addr); + + fseek(f, mb_kernel_text_offset, SEEK_SET); + + fprintf(stderr, "qemu: loading multiboot kernel (%#x bytes) at %= #zx\n", + mb_kernel_size, mb_kernel_addr - phys_ram_base); + + if ((tmp_size=3Dfread(mb_kernel_addr, 1, mb_kernel_size, f)) !=3D= mb_kernel_size) { + fprintf(stderr, "qemu: read error on multiboot kernel '%s' (= %#x !=3D %#x)\n", kernel_filename, tmp_size, mb_kernel_size); + exit(1); + } + fclose(f); + } + + + /* load modules */ + + stl_p(phys_ram_base + mb_bootinfo + 20, 0x0); /* mods_count */ + if(initrd_filename) { + uint32_t mb_mod_info =3D mb_bootinfo + 0x100; + uint32_t mb_mod_cmdline =3D mb_bootinfo+ 0x300; + uint32_t mb_mod_start =3D mh_load_addr; + uint32_t mb_mod_length =3D mb_kernel_size; + char *next_initrd; + char *next_space; + int mb_mod_count =3D 0; + + do { + next_initrd =3D strchr(initrd_filename, ','); + if(next_initrd) + *next_initrd =3D '\0'; + /* if a space comes after the module filename, treat everyth= ing after that as parameters */ + strcpy(phys_ram_base + mb_mod_cmdline, initrd_filename); + stl_p(phys_ram_base + mb_mod_info + 8, mb_mod_cmdline); /* s= tring */ + mb_mod_cmdline +=3D strlen(initrd_filename) + 1; + if(next_space =3D strchr(initrd_filename, ' ')) + *next_space =3D '\0'; +printf("multiboot loading module: %s\n", initrd_filename); + f =3D fopen(initrd_filename, "rb"); + if(f) { + mb_mod_start =3D (mb_mod_start + mb_mod_length + (TARGET= _PAGE_SIZE - 1)) + & (TARGET_PAGE_MASK); + mb_mod_length =3D get_file_size(f); + + if ((tmp_size=3Dfread((phys_ram_base + mb_mod_start), 1,= mb_mod_length, f)) + !=3D mb_mod_length) { + fprintf(stderr, "qemu: read error on multiboot modul= e '%s' (%#x !=3D %#x)\n", + initrd_filename, tmp_size, mb_mod_length); + exit(1); + } + + mb_mod_count++; + stl_p(phys_ram_base + mb_mod_info + 0, mb_mod_start); + stl_p(phys_ram_base + mb_mod_info + 4, mb_mod_start + mb= _mod_length); +printf("mod_start: %#x\nmod_end: %#x\n", mb_mod_start, mb_mod_start + = mb_mod_length); + stl_p(phys_ram_base + mb_mod_info + 12, 0x0); /* reserve= d */ + } + initrd_filename =3D next_initrd+1; + mb_mod_info +=3D 16; + } while(next_initrd); + stl_p(phys_ram_base + mb_bootinfo + 20, mb_mod_count); /* mods_c= ount */ + stl_p(phys_ram_base + mb_bootinfo + 24, mb_bootinfo + 0x100); /*= mods_addr */ + } + + /* Commandline support */ + stl_p(phys_ram_base + mb_bootinfo + 16, mb_bootinfo + 0x200); + strcpy((char*)(phys_ram_base + mb_bootinfo + 0x200), kernel_cmdline)= ; + + /* the kernel is where we want it to be now */ + +#define MULTIBOOT_FLAGS_MEMORY (1 << 0) +#define MULTIBOOT_FLAGS_BOOT_DEVICE (1 << 1) +#define MULTIBOOT_FLAGS_CMDLINE (1 << 2) +#define MULTIBOOT_FLAGS_MODULES (1 << 3) +#define MULTIBOOT_FLAGS_MMAP (1 << 6) + stl_p(phys_ram_base + mb_bootinfo, MULTIBOOT_FLAGS_MEMORY + | MULTIBOOT_FLAGS_BOOT_DEVICE + | MULTIBOOT_FLAGS_CMDLINE + | MULTIBOOT_FLAGS_MODULES + | MULTIBOOT_FLAGS_MMAP); + stl_p(phys_ram_base + mb_bootinfo + 4, 640 * 1024); /* mem_lower */ + stl_p(phys_ram_base + mb_bootinfo + 8, ram_size); /* mem_upper */ + stl_p(phys_ram_base + mb_bootinfo + 12, 0x8001ffff); /* XXX: use the= -boot switch? */ + stl_p(phys_ram_base + mb_bootinfo + 48, 0x9000); /* mmap_addr */ + + fprintf(stderr, "multiboot: mh_entry_addr =3D %#x\n", mh_entry_addr)= ; + + generate_bootsect_multiboot(option_rom, mh_entry_addr, mb_bootinfo); + + return 1; /* yes, we are multiboot */ +} + static void load_linux(uint8_t *option_rom, const char *kernel_filename, const char *initrd_filename, @@ -544,7 +976,7 @@ uint16_t real_seg; int setup_size, kernel_size, initrd_size, cmdline_size; uint32_t initrd_max; - uint8_t header[1024]; + uint8_t header[8192]; target_phys_addr_t real_addr, prot_addr, cmdline_addr, initrd_addr; FILE *f, *fi; @@ -554,7 +986,7 @@ /* load the kernel header */ f =3D fopen(kernel_filename, "rb"); if (!f || !(kernel_size =3D get_file_size(f)) || - fread(header, 1, 1024, f) !=3D 1024) { + fread(header, 1, 8192, f) !=3D 8192) { fprintf(stderr, "qemu: could not load kernel '%s'\n", kernel_filename); exit(1); @@ -566,8 +998,14 @@ #endif if (ldl_p(header+0x202) =3D=3D 0x53726448) protocol =3D lduw_p(header+0x206); - else + else { + /* This looks like a multiboot kernel. If it is, let's stop + treating it like Linux. */ + if (load_multiboot(option_rom, f, kernel_filename, initrd_filename, + kernel_cmdline, header)) + return; protocol =3D 0; + } if (protocol < 0x200 || !(header[0x211] & 0x01)) { /* Low kernel */ @@ -660,7 +1098,7 @@ } /* store the finalized header and load the rest of the kernel */ - cpu_physical_memory_write(real_addr, header, 1024); + cpu_physical_memory_write(real_addr, header, 8192); setup_size =3D header[0x1f1]; if (setup_size =3D=3D 0) @@ -669,7 +1107,7 @@ setup_size =3D (setup_size+1)*512; kernel_size -=3D setup_size; /* Size of protected-mode code */ - if (!fread_targphys_ok(real_addr+1024, setup_size-1024, f) || + if (!fread_targphys_ok(real_addr+8192, setup_size-8192, f) || !fread_targphys_ok(prot_addr, kernel_size, f)) { fprintf(stderr, "qemu: read error on kernel '%s'\n", kernel_filename); --=20 Ren=E9 Rebe - ExactCODE GmbH - Europe, Germany, Berlin Gesch=E4ftsf=FChrer: Susanne Klaus, Ren=E9 Rebe Sitz: Berlin, Amtsgericht Charlottenburg HRB 105 123 B USt-IdNr.: DE251602478 http://exactcode.de | http://t2-project.org | http://rene.rebe.name