diff --git a/hw/fw_cfg.h b/hw/fw_cfg.h index 359d45afe9a7e9c11b8b66804243763d6d0a54dc..1e004b7070501850cee715c06fff41b6146ca680 100644 --- a/hw/fw_cfg.h +++ b/hw/fw_cfg.h @@ -17,7 +17,10 @@ #define FW_CFG_NUMA 0x0d #define FW_CFG_BOOT_MENU 0x0e #define FW_CFG_MAX_CPUS 0x0f -#define FW_CFG_MAX_ENTRY 0x10 +#define FW_CFG_KERNEL_ENTRY 0x10 +#define FW_CFG_KERNEL_DATA 0x11 +#define FW_CFG_INITRD_DATA 0x12 +#define FW_CFG_MAX_ENTRY 0x13 #define FW_CFG_WRITE_CHANNEL 0x4000 #define FW_CFG_ARCH_LOCAL 0x8000 diff --git a/hw/pc.c b/hw/pc.c index bf4718e6829d6e339a1cf9b5decc38ae09cbc2b1..55bd1a48b2c9c0cf46e96b74e11355748a454d17 100644 --- a/hw/pc.c +++ b/hw/pc.c @@ -603,6 +603,8 @@ static int load_multiboot(void *fw_cfg, uint32_t mb_mod_end; uint8_t bootinfo[0x500]; uint32_t cmdline = 0x200; + uint8_t *mb_kernel_data; + uint8_t *mb_bootinfo_data; /* Ok, let's see if it is a multiboot image. The header is 12x32bit long, so the latest entry may be 8192 - 48. */ @@ -643,6 +645,12 @@ static int load_multiboot(void *fw_cfg, mh_load_addr = mh_entry_addr = elf_entry; mb_kernel_size = kernel_size; + mb_kernel_data = qemu_malloc(mb_kernel_size); + if (rom_copy(mb_kernel_data, elf_entry, kernel_size) != kernel_size) { + fprintf(stderr, "Error while fetching elf kernel from rom\n"); + exit(1); + } + #ifdef DEBUG_MULTIBOOT fprintf(stderr, "qemu: loading multiboot-elf kernel (%#x bytes) with entry %#zx\n", mb_kernel_size, (size_t)mh_entry_addr); @@ -656,7 +664,6 @@ static int load_multiboot(void *fw_cfg, uint32_t mh_bss_end_addr = ldl_p(header+i+24); #endif uint32_t mb_kernel_text_offset = i - (mh_header_addr - mh_load_addr); - uint8_t *kernel; mh_entry_addr = ldl_p(header+i+28); mb_kernel_size = get_file_size(f) - mb_kernel_text_offset; @@ -676,12 +683,9 @@ static int load_multiboot(void *fw_cfg, mb_kernel_size, mh_load_addr); #endif - kernel = qemu_malloc(mb_kernel_size); + mb_kernel_data = qemu_malloc(mb_kernel_size); fseek(f, mb_kernel_text_offset, SEEK_SET); - fread(kernel, 1, mb_kernel_size, f); - rom_add_blob_fixed(kernel_filename, kernel, mb_kernel_size, - mh_load_addr); - qemu_free(kernel); + fread(mb_kernel_data, 1, mb_kernel_size, f); fclose(f); } @@ -732,9 +736,14 @@ static int load_multiboot(void *fw_cfg, exit(1); } mb_mod_end = mb_mod_start + mb_mod_length; - rom_add_file_fixed(initrd_filename, mb_mod_start); - mb_mod_count++; + + /* append module data at the end of last module */ + mb_kernel_data = qemu_realloc(mb_kernel_data, + mh_load_addr - mb_mod_end); + load_image(initrd_filename, + mb_kernel_data + mb_mod_start - mh_load_addr); + stl_p(bootinfo + mb_mod_info + 0, mb_mod_start); stl_p(bootinfo + mb_mod_info + 4, mb_mod_start + mb_mod_length); stl_p(bootinfo + mb_mod_info + 12, 0x0); /* reserved */ @@ -774,13 +783,21 @@ static int load_multiboot(void *fw_cfg, fprintf(stderr, "multiboot: mh_entry_addr = %#x\n", mh_entry_addr); #endif + /* save bootinfo off the stack */ + mb_bootinfo_data = qemu_malloc(sizeof(bootinfo)); + memcpy(mb_bootinfo_data, bootinfo, sizeof(bootinfo)); + /* Pass variables to option rom */ - fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_ADDR, mh_entry_addr); - fw_cfg_add_i32(fw_cfg, FW_CFG_INITRD_ADDR, mb_bootinfo); - fw_cfg_add_i32(fw_cfg, FW_CFG_INITRD_SIZE, mmap_addr); + fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_ENTRY, mh_entry_addr); + fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_ADDR, mh_load_addr); + fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_SIZE, mb_mod_end - mh_load_addr); + fw_cfg_add_bytes(fw_cfg, FW_CFG_KERNEL_DATA, mb_kernel_data, + mb_mod_end - mh_load_addr); - rom_add_blob_fixed("multiboot-info", bootinfo, sizeof(bootinfo), - mb_bootinfo); + fw_cfg_add_i32(fw_cfg, FW_CFG_INITRD_ADDR, mb_bootinfo); + fw_cfg_add_i32(fw_cfg, FW_CFG_INITRD_SIZE, sizeof(bootinfo)); + fw_cfg_add_bytes(fw_cfg, FW_CFG_INITRD_DATA, mb_bootinfo_data, + sizeof(bootinfo)); option_rom[nb_option_roms] = "multiboot.bin"; nb_option_roms++; diff --git a/pc-bios/optionrom/multiboot.S b/pc-bios/optionrom/multiboot.S index e6cbefdc923ce4c23ab2e115467b4fb5b6e8e5b2..dafac7392edf2c710b8b961f33a10ddba8c7ea11 100644 --- a/pc-bios/optionrom/multiboot.S +++ b/pc-bios/optionrom/multiboot.S @@ -26,6 +26,14 @@ #define MULTIBOOT_MAGIC 0x2badb002 +#define GS_PROT_JUMP 0 +#define GS_GDT_DESC 6 + +/* Break the translation block flow so -d cpu shows us values */ +#define DEBUG_HERE \ + jmp 1f; \ + 1: + /* Read a variable from the fw_cfg device. Clobbers: %edx Out: %eax */ @@ -44,12 +52,31 @@ bswap %eax .endm +/* + * Read a blob from the fw_cfg device. + * Requires _ADDR, _SIZE and _DATA values for the parameter. + * + * Clobbers: %eax, %edx, %es, %ecx, %edi + */ +#define read_fw_blob(var) \ + read_fw var ## _ADDR; \ + mov %eax, %edi; \ + read_fw var ## _SIZE; \ + mov %eax, %ecx; \ + mov $var ## _DATA, %ax; \ + mov $BIOS_CFG_IOPORT_CFG, %edx; \ + outw %ax, (%dx); \ + mov $BIOS_CFG_IOPORT_DATA, %dx; \ + cld; \ + DEBUG_HERE \ + rep insb (%dx), %es:(%edi); + .code16 .text .global _start _start: .short 0xaa55 - .byte 1 /* (_end - _start) / 512 */ + .byte (_end - _start) / 512 push %eax push %ds @@ -57,10 +84,6 @@ _start: xor %ax, %ax mov %ax, %ds - /* save old int 19 */ - mov (0x19*4), %eax - mov %eax, %cs:old_int19 - /* install our int 19 handler */ movw $int19_handler, (0x19*4) mov %cs, (0x19*4+2) @@ -84,15 +107,34 @@ run_multiboot: mov %cs, %eax shl $0x4, %eax - /* fix the gdt descriptor to be PC relative */ - mov (gdt_desc+2), %ebx - add %eax, %ebx - mov %ebx, (gdt_desc+2) + /* set up a long jump descriptor that is PC relative */ - /* fix the prot mode indirect jump to be PC relative */ + /* move stack memory to %gs */ + mov %ss, %ecx + shl $0x4, %ecx + mov %esp, %ebx + add %ebx, %ecx + sub $0x20, %ecx + sub $0x30, %esp + shr $0x4, %ecx + mov %cx, %gs + + /* now push the indirect jump decriptor there */ mov (prot_jump), %ebx add %eax, %ebx - mov %ebx, (prot_jump) + movl %ebx, %gs:GS_PROT_JUMP + mov $8, %bx + movw %bx, %gs:GS_PROT_JUMP + 4 + + /* fix the gdt descriptor to be PC relative */ + movw (gdt_desc), %bx + movw %bx, %gs:GS_GDT_DESC + movl (gdt_desc+2), %ebx + add %eax, %ebx + movl %ebx, %gs:GS_GDT_DESC + 2 + + /* Read the bootinfo struct into RAM */ + read_fw_blob(FW_CFG_INITRD) /* FS = bootinfo_struct */ read_fw FW_CFG_INITRD_ADDR @@ -100,7 +142,7 @@ run_multiboot: mov %ax, %fs /* ES = mmap_addr */ - read_fw FW_CFG_INITRD_SIZE + mov %eax, %fs:0x48 shr $4, %eax mov %ax, %es @@ -144,7 +186,7 @@ mmap_done: real_to_prot: /* Load the GDT before going into protected mode */ lgdt: - data32 lgdt %cs:gdt_desc + data32 lgdt %gs:GS_GDT_DESC /* get us to protected mode now */ movl $1, %eax @@ -152,7 +194,7 @@ lgdt: /* the LJMP sets CS for us and gets us to 32-bit */ ljmp: - data32 ljmp *%cs:prot_jump + data32 ljmp *%gs:GS_PROT_JUMP prot_mode: .code32 @@ -165,8 +207,11 @@ prot_mode: movl %eax, %fs movl %eax, %gs + /* Read the kernel and modules into RAM */ + read_fw_blob(FW_CFG_KERNEL) + /* Jump off to the kernel */ - read_fw FW_CFG_KERNEL_ADDR + read_fw FW_CFG_KERNEL_ENTRY mov %eax, %ecx /* EBX contains a pointer to the bootinfo struct */ @@ -180,8 +225,6 @@ ljmp2: /* Variables */ .align 4, 0 -old_int19: .long 0 - prot_jump: .long prot_mode .short 8