/* * 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" #define BOOT_ROM_PRODUCT "Linux loader" 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. */ /* Reserve space on the stack for our GDT descriptor. */ mov %esp, %ebp sub $16, %esp /* Now create the GDT descriptor */ movw $((3 * 8) - 1), -16(%bp) mov %cs, %eax movzwl %ax, %eax shl $4, %eax addl $gdt, %eax movl %eax, -14(%bp) /* And load the GDT */ data32 lgdt -16(%bp) mov %ebp, %esp /* Get us to protected mode now */ mov $1, %eax mov %eax, %cr0 /* So we can set ES to a 32-bit segment */ mov $0x10, %eax mov %eax, %es /* We're now running in 16-bit CS, but 32-bit ES! */ /* Load kernel and initrd */ read_fw_blob_addr32(FW_CFG_KERNEL) read_fw_blob_addr32(FW_CFG_INITRD) read_fw_blob_addr32(FW_CFG_CMDLINE) read_fw_blob_addr32(FW_CFG_SETUP) /* And now jump into Linux! */ mov $0, %eax mov %eax, %cr0 /* ES = CS */ mov %cs, %ax mov %ax, %es 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