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 25BOOT_ROM_START 26 27run_linuxboot: 28 29 cli 30 cld 31 32 jmp copy_kernel 33boot_kernel: 34 35 read_fw FW_CFG_SETUP_ADDR 36 37 mov %eax, %ebx 38 shr $4, %ebx 39 40 /* All segments contain real_addr */ 41 mov %bx, %ds 42 mov %bx, %es 43 mov %bx, %fs 44 mov %bx, %gs 45 mov %bx, %ss 46 47 /* CX = CS we want to jump to */ 48 add $0x20, %bx 49 mov %bx, %cx 50 51 /* SP = cmdline_addr-real_addr-16 */ 52 read_fw FW_CFG_CMDLINE_ADDR 53 mov %eax, %ebx 54 read_fw FW_CFG_SETUP_ADDR 55 sub %eax, %ebx 56 sub $16, %ebx 57 mov %ebx, %esp 58 59 /* Build indirect lret descriptor */ 60 pushw %cx /* CS */ 61 xor %ax, %ax 62 pushw %ax /* IP = 0 */ 63 64 /* Clear registers */ 65 xor %eax, %eax 66 xor %ebx, %ebx 67 xor %ecx, %ecx 68 xor %edx, %edx 69 xor %edi, %edi 70 xor %ebp, %ebp 71 72 /* Jump to Linux */ 73 lret 74 75 76copy_kernel: 77 78 /* We need to load the kernel into memory we can't access in 16 bit 79 mode, so let's get into 32 bit mode, write the kernel and jump 80 back again. */ 81 82 /* Reserve space on the stack for our GDT descriptor. */ 83 mov %esp, %ebp 84 sub $16, %esp 85 86 /* Now create the GDT descriptor */ 87 movw $((3 * 8) - 1), -16(%bp) 88 mov %cs, %eax 89 movzwl %ax, %eax 90 shl $4, %eax 91 addl $gdt, %eax 92 movl %eax, -14(%bp) 93 94 /* And load the GDT */ 95 data32 lgdt -16(%bp) 96 mov %ebp, %esp 97 98 /* Get us to protected mode now */ 99 mov $1, %eax 100 mov %eax, %cr0 101 102 /* So we can set ES to a 32-bit segment */ 103 mov $0x10, %eax 104 mov %eax, %es 105 106 /* We're now running in 16-bit CS, but 32-bit ES! */ 107 108 /* Load kernel and initrd */ 109 read_fw_blob_addr32(FW_CFG_KERNEL) 110 read_fw_blob_addr32(FW_CFG_INITRD) 111 read_fw_blob_addr32(FW_CFG_CMDLINE) 112 read_fw_blob_addr32(FW_CFG_SETUP) 113 114 /* And now jump into Linux! */ 115 mov $0, %eax 116 mov %eax, %cr0 117 118 /* ES = CS */ 119 mov %cs, %ax 120 mov %ax, %es 121 122 jmp boot_kernel 123 124/* Variables */ 125 126.align 4, 0 127gdt: 128 /* 0x00 */ 129.byte 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 130 131 /* 0x08: code segment (base=0, limit=0xfffff, type=32bit code exec/read, DPL=0, 4k) */ 132.byte 0xff, 0xff, 0x00, 0x00, 0x00, 0x9a, 0xcf, 0x00 133 134 /* 0x10: data segment (base=0, limit=0xfffff, type=32bit data read/write, DPL=0, 4k) */ 135.byte 0xff, 0xff, 0x00, 0x00, 0x00, 0x92, 0xcf, 0x00 136 137BOOT_ROM_END 138