Convert multiboot to fw_cfg backed data storage

Right now we load the guest kernel to RAM, fire off the BIOS, hope it
doesn't clobber memory and run an option rom that jumps into the kernel.

That breaks with SeaBIOS, as that clears memory. So let's read all
kernel, module etc. data using the fw_cfg interface when in the int19
handler.

This patch implements said mechanism for multiboot.

Signed-off-by: Alexander Graf <agraf@suse.de>
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
This commit is contained in:
Alexander Graf 2009-11-12 21:53:12 +01:00 committed by Anthony Liguori
parent 235f86ef01
commit 77873196f3
3 changed files with 95 additions and 32 deletions

View file

@ -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