diff options
author | Avi Kivity <avi@redhat.com> | 2009-11-22 15:21:19 +0200 |
---|---|---|
committer | Avi Kivity <avi@redhat.com> | 2009-11-22 15:21:19 +0200 |
commit | eaf2bd3047dc61a1ac20ec9752a50aab6c6b2417 (patch) | |
tree | 8e6aab276137be57b3e4b13095f4e2329d566ca6 /pc-bios | |
parent | Merge commit '1945120112e93aa96af6d6004b36599f783ac563' into upstream-merge (diff) | |
parent | Convert linux bootrom to external rom and fw_cfg (diff) | |
download | qemu-kvm-eaf2bd3047dc61a1ac20ec9752a50aab6c6b2417.tar.gz qemu-kvm-eaf2bd3047dc61a1ac20ec9752a50aab6c6b2417.tar.bz2 qemu-kvm-eaf2bd3047dc61a1ac20ec9752a50aab6c6b2417.zip |
Merge commit '57a46d0579951d7abbcbe86766f73afa93a5d370' into upstream-merge
* commit '57a46d0579951d7abbcbe86766f73afa93a5d370':
Convert linux bootrom to external rom and fw_cfg
Move common option rom code to header file
Convert multiboot to fw_cfg backed data storage
Introduce rom_copy
fw_cfg: change cur_offset to 32 bits
Conflicts:
pc-bios/optionrom/Makefile
Signed-off-by: Avi Kivity <avi@redhat.com>
Diffstat (limited to 'pc-bios')
-rw-r--r-- | pc-bios/linuxboot.bin | bin | 0 -> 1025 bytes | |||
-rw-r--r-- | pc-bios/optionrom/Makefile | 4 | ||||
-rw-r--r-- | pc-bios/optionrom/linuxboot.S | 140 | ||||
-rw-r--r-- | pc-bios/optionrom/multiboot.S | 108 | ||||
-rw-r--r-- | pc-bios/optionrom/optionrom.h | 107 |
5 files changed, 289 insertions, 70 deletions
diff --git a/pc-bios/linuxboot.bin b/pc-bios/linuxboot.bin Binary files differnew file mode 100644 index 000000000..d8f0ea80a --- /dev/null +++ b/pc-bios/linuxboot.bin diff --git a/pc-bios/optionrom/Makefile b/pc-bios/optionrom/Makefile index 67ecc6374..84c77018d 100644 --- a/pc-bios/optionrom/Makefile +++ b/pc-bios/optionrom/Makefile @@ -13,7 +13,9 @@ CFLAGS += -I$(SRC_PATH) CFLAGS += $(call cc-option, $(CFLAGS), -fno-stack-protector) QEMU_CFLAGS = $(CFLAGS) -build-all: multiboot.bin extboot.bin vapic.bin +build-all: multiboot.bin linuxboot.bin + +build-all: extboot.bin vapic.bin %.img: %.o $(call quiet-command,$(LD) -Ttext 0 -e _start -s -o $@ $<," Building $(TARGET_DIR)$@") diff --git a/pc-bios/optionrom/linuxboot.S b/pc-bios/optionrom/linuxboot.S new file mode 100644 index 000000000..b3c90e33c --- /dev/null +++ b/pc-bios/optionrom/linuxboot.S @@ -0,0 +1,140 @@ +/* + * Linux Boot Option ROM + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <http://www.gnu.org/licenses/>. + * + * Copyright Novell Inc, 2009 + * Authors: Alexander Graf <agraf@suse.de> + * + * Based on code in hw/pc.c. + */ + +#include "optionrom.h" + +BOOT_ROM_START + +run_linuxboot: + + cli + cld + + jmp copy_kernel +boot_kernel: + + read_fw FW_CFG_SETUP_ADDR + + mov %eax, %ebx + shr $4, %ebx + + /* All segments contain real_addr */ + mov %bx, %ds + mov %bx, %es + mov %bx, %fs + mov %bx, %gs + mov %bx, %ss + + /* CX = CS we want to jump to */ + add $0x20, %bx + mov %bx, %cx + + /* SP = cmdline_addr-real_addr-16 */ + read_fw FW_CFG_CMDLINE_ADDR + mov %eax, %ebx + read_fw FW_CFG_SETUP_ADDR + sub %eax, %ebx + sub $16, %ebx + mov %ebx, %esp + + /* Build indirect lret descriptor */ + pushw %cx /* CS */ + xor %ax, %ax + pushw %ax /* IP = 0 */ + + /* Clear registers */ + xor %eax, %eax + xor %ebx, %ebx + xor %ecx, %ecx + xor %edx, %edx + xor %edi, %edi + xor %ebp, %ebp + + /* Jump to Linux */ + lret + + +copy_kernel: + + /* We need to load the kernel into memory we can't access in 16 bit + mode, so let's get into 32 bit mode, write the kernel and jump + back again. */ + + /* Set DS to SS+SP - 0x10, so we can write our GDT descriptor there */ + mov %ss, %eax + shl $4, %eax + add %esp, %eax + sub $0x10, %eax + shr $4, %eax + + /* Now create the GDT descriptor */ + mov %cs, %eax + shl $4, %eax + movw $((3 * 8) - 1), %bx + movw %bx, %gs:0 + movl $gdt, %ebx + add %eax, %ebx + movl %ebx, %gs:2 + + /* And load the GDT */ + data32 lgdt %gs:0 + + /* Get us to protected mode now */ + mov $1, %eax + mov %eax, %cr0 + + /* So we can set DS to a 32-bit segment */ + mov $0x10, %eax + mov %eax, %ds + + /* We're now running in 16-bit CS, but 32-bit DS! */ + + /* Load kernel and initrd */ + read_fw_blob(FW_CFG_KERNEL) + read_fw_blob(FW_CFG_INITRD) + read_fw_blob(FW_CFG_CMDLINE) + read_fw_blob(FW_CFG_SETUP) + + /* And now jump into Linux! */ + mov $0, %eax + mov %eax, %cr0 + + /* DS = CS */ + mov %cs, %ax + mov %ax, %ds + + jmp boot_kernel + +/* Variables */ + +.align 4, 0 +gdt: + /* 0x00 */ +.byte 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + + /* 0x08: code segment (base=0, limit=0xfffff, type=32bit code exec/read, DPL=0, 4k) */ +.byte 0xff, 0xff, 0x00, 0x00, 0x00, 0x9a, 0xcf, 0x00 + + /* 0x10: data segment (base=0, limit=0xfffff, type=32bit data read/write, DPL=0, 4k) */ +.byte 0xff, 0xff, 0x00, 0x00, 0x00, 0x92, 0xcf, 0x00 + +BOOT_ROM_END diff --git a/pc-bios/optionrom/multiboot.S b/pc-bios/optionrom/multiboot.S index e6cbefdc9..be5c9fcf3 100644 --- a/pc-bios/optionrom/multiboot.S +++ b/pc-bios/optionrom/multiboot.S @@ -18,63 +18,15 @@ * Authors: Alexander Graf <agraf@suse.de> */ -#define NO_QEMU_PROTOS -#include "../../hw/fw_cfg.h" - -#define BIOS_CFG_IOPORT_CFG 0x510 -#define BIOS_CFG_IOPORT_DATA 0x511 +#include "optionrom.h" #define MULTIBOOT_MAGIC 0x2badb002 -/* Read a variable from the fw_cfg device. - Clobbers: %edx - Out: %eax */ -.macro read_fw VAR - mov $\VAR, %ax - mov $BIOS_CFG_IOPORT_CFG, %dx - outw %ax, (%dx) - mov $BIOS_CFG_IOPORT_DATA, %dx - inb (%dx), %al - shl $8, %eax - inb (%dx), %al - shl $8, %eax - inb (%dx), %al - shl $8, %eax - inb (%dx), %al - bswap %eax -.endm - -.code16 -.text - .global _start -_start: - .short 0xaa55 - .byte 1 /* (_end - _start) / 512 */ - push %eax - push %ds - - /* setup ds so we can access the IVT */ - 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) - - pop %ds - pop %eax - lret - -int19_handler: - /* DS = CS */ - movw %cs, %ax - movw %ax, %ds - - /* fall through */ +#define GS_PROT_JUMP 0 +#define GS_GDT_DESC 6 + + +BOOT_ROM_START run_multiboot: @@ -84,15 +36,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 */ + + /* 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 - /* fix the prot mode indirect jump to be PC relative */ + /* 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 +71,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 +115,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 +123,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 +136,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 +154,6 @@ ljmp2: /* Variables */ .align 4, 0 -old_int19: .long 0 - prot_jump: .long prot_mode .short 8 @@ -206,6 +178,4 @@ gdt_desc: .short (5 * 8) - 1 .long gdt -.align 512, 0 -_end: - +BOOT_ROM_END diff --git a/pc-bios/optionrom/optionrom.h b/pc-bios/optionrom/optionrom.h new file mode 100644 index 000000000..34d69af89 --- /dev/null +++ b/pc-bios/optionrom/optionrom.h @@ -0,0 +1,107 @@ +/* + * Common Option ROM Functions + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <http://www.gnu.org/licenses/>. + * + * Copyright Novell Inc, 2009 + * Authors: Alexander Graf <agraf@suse.de> + */ + + +#define NO_QEMU_PROTOS +#include "../../hw/fw_cfg.h" + +#define BIOS_CFG_IOPORT_CFG 0x510 +#define BIOS_CFG_IOPORT_DATA 0x511 + +/* 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 + */ +.macro read_fw VAR + mov $\VAR, %ax + mov $BIOS_CFG_IOPORT_CFG, %dx + outw %ax, (%dx) + mov $BIOS_CFG_IOPORT_DATA, %dx + inb (%dx), %al + shl $8, %eax + inb (%dx), %al + shl $8, %eax + inb (%dx), %al + shl $8, %eax + inb (%dx), %al + 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; \ + rep insb (%dx), %es:(%edi); + +#define OPTION_ROM_START \ + .code16; \ + .text; \ + .global _start; \ + _start:; \ + .short 0xaa55; \ + .byte (_end - _start) / 512; + +#define BOOT_ROM_START \ + OPTION_ROM_START \ + push %eax; \ + push %ds; \ + \ + /* setup ds so we can access the IVT */ \ + xor %ax, %ax; \ + mov %ax, %ds; \ + \ + /* install our int 19 handler */ \ + movw $int19_handler, (0x19*4); \ + mov %cs, (0x19*4+2); \ + \ + pop %ds; \ + pop %eax; \ + lret; \ + \ + int19_handler:; \ + /* DS = CS */ \ + movw %cs, %ax; \ + movw %ax, %ds; + +#define OPTION_ROM_END \ + .align 512, 0; \ + _end: + +#define BOOT_ROM_END \ + OPTION_ROM_END + |