1/* 2 * Linux Boot Option ROM 3 * 4 * This program is free software; you can redistribute it and/or modify 5 * it under the terms of the GNU General Public License as published by 6 * the Free Software Foundation; either version 2 of the License, or 7 * (at your option) any later version. 8 * 9 * This program is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 * GNU General Public License for more details. 13 * 14 * You should have received a copy of the GNU General Public License 15 * along with this program; if not, see <http://www.gnu.org/licenses/>. 16 * 17 * Copyright Novell Inc, 2009 18 * Authors: Alexander Graf <agraf@suse.de> 19 * 20 * Based on code in hw/pc.c. 21 */ 22 23#include "optionrom.h" 24 25#define BOOT_ROM_PRODUCT "Linux loader" 26 27BOOT_ROM_START 28 29run_linuxboot: 30 31 cli 32 cld 33 34 jmp copy_kernel 35boot_kernel: 36 37 read_fw FW_CFG_SETUP_ADDR 38 39 mov %eax, %ebx 40 shr $4, %ebx 41 42 /* All segments contain real_addr */ 43 mov %bx, %ds 44 mov %bx, %es 45 mov %bx, %fs 46 mov %bx, %gs 47 mov %bx, %ss 48 49 /* CX = CS we want to jump to */ 50 add $0x20, %bx 51 mov %bx, %cx 52 53 /* SP = cmdline_addr-real_addr-16 */ 54 read_fw FW_CFG_CMDLINE_ADDR 55 mov %eax, %ebx 56 read_fw FW_CFG_SETUP_ADDR 57 sub %eax, %ebx 58 sub $16, %ebx 59 mov %ebx, %esp 60 61 /* Build indirect lret descriptor */ 62 pushw %cx /* CS */ 63 xor %ax, %ax 64 pushw %ax /* IP = 0 */ 65 66 /* Clear registers */ 67 xor %eax, %eax 68 xor %ebx, %ebx 69 xor %ecx, %ecx 70 xor %edx, %edx 71 xor %edi, %edi 72 xor %ebp, %ebp 73 74 /* Jump to Linux */ 75 lret 76 77 78copy_kernel: 79 80 /* We need to load the kernel into memory we can't access in 16 bit 81 mode, so let's get into 32 bit mode, write the kernel and jump 82 back again. */ 83 84 /* Reserve space on the stack for our GDT descriptor. */ 85 mov %esp, %ebp 86 sub $16, %esp 87 88 /* Now create the GDT descriptor */ 89 movw $((3 * 8) - 1), -16(%bp) 90 mov %cs, %eax 91 movzwl %ax, %eax 92 shl $4, %eax 93 addl $gdt, %eax 94 movl %eax, -14(%bp) 95 96 /* And load the GDT */ 97 data32 lgdt -16(%bp) 98 mov %ebp, %esp 99 100 /* Get us to protected mode now */ 101 mov $1, %eax 102 mov %eax, %cr0 103 104 /* So we can set ES to a 32-bit segment */ 105 mov $0x10, %eax 106 mov %eax, %es 107 108 /* We're now running in 16-bit CS, but 32-bit ES! */ 109 110 /* Load kernel and initrd */ 111 read_fw_blob_addr32(FW_CFG_KERNEL) 112 read_fw_blob_addr32(FW_CFG_INITRD) 113 read_fw_blob_addr32(FW_CFG_CMDLINE) 114 read_fw_blob_addr32(FW_CFG_SETUP) 115 116 /* And now jump into Linux! */ 117 mov $0, %eax 118 mov %eax, %cr0 119 120 /* ES = CS */ 121 mov %cs, %ax 122 mov %ax, %es 123 124 jmp boot_kernel 125 126/* Variables */ 127 128.align 4, 0 129gdt: 130 /* 0x00 */ 131.byte 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 132 133 /* 0x08: code segment (base=0, limit=0xfffff, type=32bit code exec/read, DPL=0, 4k) */ 134.byte 0xff, 0xff, 0x00, 0x00, 0x00, 0x9a, 0xcf, 0x00 135 136 /* 0x10: data segment (base=0, limit=0xfffff, type=32bit data read/write, DPL=0, 4k) */ 137.byte 0xff, 0xff, 0x00, 0x00, 0x00, 0x92, 0xcf, 0x00 138 139BOOT_ROM_END 140