1f16408dfSAlexander Graf/* 2f16408dfSAlexander Graf * Multiboot Option ROM 3f16408dfSAlexander Graf * 4f16408dfSAlexander Graf * This program is free software; you can redistribute it and/or modify 5f16408dfSAlexander Graf * it under the terms of the GNU General Public License as published by 6f16408dfSAlexander Graf * the Free Software Foundation; either version 2 of the License, or 7f16408dfSAlexander Graf * (at your option) any later version. 8f16408dfSAlexander Graf * 9f16408dfSAlexander Graf * This program is distributed in the hope that it will be useful, 10f16408dfSAlexander Graf * but WITHOUT ANY WARRANTY; without even the implied warranty of 11f16408dfSAlexander Graf * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12f16408dfSAlexander Graf * GNU General Public License for more details. 13f16408dfSAlexander Graf * 14f16408dfSAlexander Graf * You should have received a copy of the GNU General Public License 158167ee88SBlue Swirl * along with this program; if not, see <http://www.gnu.org/licenses/>. 16f16408dfSAlexander Graf * 17f16408dfSAlexander Graf * Copyright Novell Inc, 2009 18f16408dfSAlexander Graf * Authors: Alexander Graf <agraf@suse.de> 19f16408dfSAlexander Graf */ 20f16408dfSAlexander Graf 21dd4b2659SAlexander Graf#include "optionrom.h" 22f16408dfSAlexander Graf 2375b9f690SGleb Natapov#define BOOT_ROM_PRODUCT "multiboot loader" 2475b9f690SGleb Natapov 25f16408dfSAlexander Graf#define MULTIBOOT_MAGIC 0x2badb002 26f16408dfSAlexander Graf 2777873196SAlexander Graf#define GS_PROT_JUMP 0 2877873196SAlexander Graf#define GS_GDT_DESC 6 2977873196SAlexander Graf 3077873196SAlexander Graf 31dd4b2659SAlexander GrafBOOT_ROM_START 32f16408dfSAlexander Graf 33f16408dfSAlexander Grafrun_multiboot: 34f16408dfSAlexander Graf 35f16408dfSAlexander Graf cli 36f16408dfSAlexander Graf cld 37f16408dfSAlexander Graf 38f16408dfSAlexander Graf mov %cs, %eax 39f16408dfSAlexander Graf shl $0x4, %eax 40f16408dfSAlexander Graf 4177873196SAlexander Graf /* set up a long jump descriptor that is PC relative */ 42f16408dfSAlexander Graf 4377873196SAlexander Graf /* move stack memory to %gs */ 4477873196SAlexander Graf mov %ss, %ecx 4577873196SAlexander Graf shl $0x4, %ecx 4677873196SAlexander Graf mov %esp, %ebx 4777873196SAlexander Graf add %ebx, %ecx 4877873196SAlexander Graf sub $0x20, %ecx 4977873196SAlexander Graf sub $0x30, %esp 5077873196SAlexander Graf shr $0x4, %ecx 5177873196SAlexander Graf mov %cx, %gs 5277873196SAlexander Graf 53e7d81004SStefan Weil /* now push the indirect jump descriptor there */ 54f16408dfSAlexander Graf mov (prot_jump), %ebx 55f16408dfSAlexander Graf add %eax, %ebx 5677873196SAlexander Graf movl %ebx, %gs:GS_PROT_JUMP 5777873196SAlexander Graf mov $8, %bx 5877873196SAlexander Graf movw %bx, %gs:GS_PROT_JUMP + 4 5977873196SAlexander Graf 6077873196SAlexander Graf /* fix the gdt descriptor to be PC relative */ 6177873196SAlexander Graf movw (gdt_desc), %bx 6277873196SAlexander Graf movw %bx, %gs:GS_GDT_DESC 6377873196SAlexander Graf movl (gdt_desc+2), %ebx 6477873196SAlexander Graf add %eax, %ebx 6577873196SAlexander Graf movl %ebx, %gs:GS_GDT_DESC + 2 6677873196SAlexander Graf 6753ea95deSAdam Lackorzynski xor %eax, %eax 6853ea95deSAdam Lackorzynski mov %eax, %es 6953ea95deSAdam Lackorzynski 7077873196SAlexander Graf /* Read the bootinfo struct into RAM */ 71*48972f8cSMarcus Hähnel read_fw_blob_dma(FW_CFG_INITRD) 72f16408dfSAlexander Graf 73f16408dfSAlexander Graf /* FS = bootinfo_struct */ 74f16408dfSAlexander Graf read_fw FW_CFG_INITRD_ADDR 75f16408dfSAlexander Graf shr $4, %eax 76f16408dfSAlexander Graf mov %ax, %fs 77f16408dfSAlexander Graf 78c6e052f0SPaolo Bonzini /* Account for the EBDA in the multiboot structure's e801 79c6e052f0SPaolo Bonzini * map. 80c6e052f0SPaolo Bonzini */ 81c6e052f0SPaolo Bonzini int $0x12 82c6e052f0SPaolo Bonzini cwtl 83c6e052f0SPaolo Bonzini movl %eax, %fs:4 84c6e052f0SPaolo Bonzini 85f16408dfSAlexander Graf /* ES = mmap_addr */ 8653ea95deSAdam Lackorzynski mov %fs:48, %eax 87f16408dfSAlexander Graf shr $4, %eax 88f16408dfSAlexander Graf mov %ax, %es 89f16408dfSAlexander Graf 90f16408dfSAlexander Graf /* Initialize multiboot mmap structs using int 0x15(e820) */ 91f16408dfSAlexander Graf xor %ebx, %ebx 92390fb6b4SKevin Wolf /* Start storing mmap data at %es:0 */ 93390fb6b4SKevin Wolf xor %edi, %edi 94f16408dfSAlexander Graf 95f16408dfSAlexander Grafmmap_loop: 96390fb6b4SKevin Wolf /* The multiboot entry size has offset -4, so leave some space */ 97390fb6b4SKevin Wolf add $4, %di 98f16408dfSAlexander Graf /* entry size (mmap struct) & max buffer size (int15) */ 99f16408dfSAlexander Graf movl $20, %ecx 100f16408dfSAlexander Graf /* e820 */ 101f16408dfSAlexander Graf movl $0x0000e820, %eax 102f16408dfSAlexander Graf /* 'SMAP' magic */ 103f16408dfSAlexander Graf movl $0x534d4150, %edx 104f16408dfSAlexander Graf int $0x15 105f16408dfSAlexander Graf 106f16408dfSAlexander Grafmmap_check_entry: 107390fb6b4SKevin Wolf /* Error or last entry already done? */ 108f16408dfSAlexander Graf jb mmap_done 109f16408dfSAlexander Graf 110f16408dfSAlexander Grafmmap_store_entry: 111390fb6b4SKevin Wolf /* store entry size */ 112390fb6b4SKevin Wolf /* old as(1) doesn't like this insn so emit the bytes instead: 113390fb6b4SKevin Wolf movl %ecx, %es:-4(%edi) 114390fb6b4SKevin Wolf */ 115390fb6b4SKevin Wolf .dc.b 0x26,0x67,0x66,0x89,0x4f,0xfc 116390fb6b4SKevin Wolf 117390fb6b4SKevin Wolf /* %edi += entry_size, store as mbs_mmap_length */ 118390fb6b4SKevin Wolf add %ecx, %edi 119f16408dfSAlexander Graf movw %di, %fs:0x2c 120390fb6b4SKevin Wolf 121390fb6b4SKevin Wolf /* Continuation value 0 means last entry */ 122390fb6b4SKevin Wolf test %ebx, %ebx 123390fb6b4SKevin Wolf jnz mmap_loop 124f16408dfSAlexander Graf 125f16408dfSAlexander Grafmmap_done: 12626a8ec07SKevin Wolf /* Calculate upper_mem field: The amount of memory between 1 MB and 12726a8ec07SKevin Wolf the first upper memory hole. Get it from the mmap. */ 12826a8ec07SKevin Wolf xor %di, %di 12926a8ec07SKevin Wolf mov $0x100000, %edx 13026a8ec07SKevin Wolfupper_mem_entry: 13126a8ec07SKevin Wolf cmp %fs:0x2c, %di 13226a8ec07SKevin Wolf je upper_mem_done 13326a8ec07SKevin Wolf add $4, %di 13426a8ec07SKevin Wolf 13526a8ec07SKevin Wolf /* Skip if type != 1 */ 13626a8ec07SKevin Wolf cmpl $1, %es:16(%di) 13726a8ec07SKevin Wolf jne upper_mem_next 13826a8ec07SKevin Wolf 13926a8ec07SKevin Wolf /* Skip if > 4 GB */ 14026a8ec07SKevin Wolf movl %es:4(%di), %eax 14126a8ec07SKevin Wolf test %eax, %eax 14226a8ec07SKevin Wolf jnz upper_mem_next 14326a8ec07SKevin Wolf 14426a8ec07SKevin Wolf /* Check for contiguous extension (base <= %edx < base + length) */ 14526a8ec07SKevin Wolf movl %es:(%di), %eax 14626a8ec07SKevin Wolf cmp %eax, %edx 14726a8ec07SKevin Wolf jb upper_mem_next 14826a8ec07SKevin Wolf addl %es:8(%di), %eax 14926a8ec07SKevin Wolf cmp %eax, %edx 15026a8ec07SKevin Wolf jae upper_mem_next 15126a8ec07SKevin Wolf 15226a8ec07SKevin Wolf /* If so, update %edx, and restart the search (mmap isn't ordered) */ 15326a8ec07SKevin Wolf mov %eax, %edx 15426a8ec07SKevin Wolf xor %di, %di 15526a8ec07SKevin Wolf jmp upper_mem_entry 15626a8ec07SKevin Wolf 15726a8ec07SKevin Wolfupper_mem_next: 15826a8ec07SKevin Wolf addl %es:-4(%di), %edi 15926a8ec07SKevin Wolf jmp upper_mem_entry 16026a8ec07SKevin Wolf 16126a8ec07SKevin Wolfupper_mem_done: 16226a8ec07SKevin Wolf sub $0x100000, %edx 16326a8ec07SKevin Wolf shr $10, %edx 16426a8ec07SKevin Wolf mov %edx, %fs:0x8 16526a8ec07SKevin Wolf 166f16408dfSAlexander Grafreal_to_prot: 167f16408dfSAlexander Graf /* Load the GDT before going into protected mode */ 168f16408dfSAlexander Graflgdt: 16977873196SAlexander Graf data32 lgdt %gs:GS_GDT_DESC 170f16408dfSAlexander Graf 171f16408dfSAlexander Graf /* get us to protected mode now */ 172f16408dfSAlexander Graf movl $1, %eax 173f16408dfSAlexander Graf movl %eax, %cr0 174f16408dfSAlexander Graf 175f16408dfSAlexander Graf /* the LJMP sets CS for us and gets us to 32-bit */ 176f16408dfSAlexander Grafljmp: 17777873196SAlexander Graf data32 ljmp *%gs:GS_PROT_JUMP 178f16408dfSAlexander Graf 179f16408dfSAlexander Grafprot_mode: 180f16408dfSAlexander Graf.code32 181f16408dfSAlexander Graf 182f16408dfSAlexander Graf /* initialize all other segments */ 183f16408dfSAlexander Graf movl $0x10, %eax 184f16408dfSAlexander Graf movl %eax, %ss 185f16408dfSAlexander Graf movl %eax, %ds 186f16408dfSAlexander Graf movl %eax, %es 187f16408dfSAlexander Graf movl %eax, %fs 188f16408dfSAlexander Graf movl %eax, %gs 189f16408dfSAlexander Graf 19077873196SAlexander Graf /* Read the kernel and modules into RAM */ 191*48972f8cSMarcus Hähnel read_fw_blob_dma(FW_CFG_KERNEL) 19277873196SAlexander Graf 193f16408dfSAlexander Graf /* Jump off to the kernel */ 19477873196SAlexander Graf read_fw FW_CFG_KERNEL_ENTRY 195f16408dfSAlexander Graf mov %eax, %ecx 196f16408dfSAlexander Graf 197f16408dfSAlexander Graf /* EBX contains a pointer to the bootinfo struct */ 198f16408dfSAlexander Graf read_fw FW_CFG_INITRD_ADDR 199f16408dfSAlexander Graf movl %eax, %ebx 200f16408dfSAlexander Graf 201f16408dfSAlexander Graf /* EAX has to contain the magic */ 202f16408dfSAlexander Graf movl $MULTIBOOT_MAGIC, %eax 203f16408dfSAlexander Grafljmp2: 204f16408dfSAlexander Graf jmp *%ecx 205f16408dfSAlexander Graf 206f16408dfSAlexander Graf/* Variables */ 207f16408dfSAlexander Graf.align 4, 0 208f16408dfSAlexander Grafprot_jump: .long prot_mode 209f16408dfSAlexander Graf .short 8 210f16408dfSAlexander Graf 211f16408dfSAlexander Graf.align 4, 0 212f16408dfSAlexander Grafgdt: 213f16408dfSAlexander Graf /* 0x00 */ 214f16408dfSAlexander Graf.byte 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 215f16408dfSAlexander Graf 216f16408dfSAlexander Graf /* 0x08: code segment (base=0, limit=0xfffff, type=32bit code exec/read, DPL=0, 4k) */ 217f16408dfSAlexander Graf.byte 0xff, 0xff, 0x00, 0x00, 0x00, 0x9a, 0xcf, 0x00 218f16408dfSAlexander Graf 219f16408dfSAlexander Graf /* 0x10: data segment (base=0, limit=0xfffff, type=32bit data read/write, DPL=0, 4k) */ 220f16408dfSAlexander Graf.byte 0xff, 0xff, 0x00, 0x00, 0x00, 0x92, 0xcf, 0x00 221f16408dfSAlexander Graf 222f16408dfSAlexander Graf /* 0x18: code segment (base=0, limit=0x0ffff, type=16bit code exec/read/conf, DPL=0, 1b) */ 223f16408dfSAlexander Graf.byte 0xff, 0xff, 0x00, 0x00, 0x00, 0x9e, 0x00, 0x00 224f16408dfSAlexander Graf 225f16408dfSAlexander Graf /* 0x20: data segment (base=0, limit=0x0ffff, type=16bit data read/write, DPL=0, 1b) */ 226f16408dfSAlexander Graf.byte 0xff, 0xff, 0x00, 0x00, 0x00, 0x92, 0x00, 0x00 227f16408dfSAlexander Graf 228f16408dfSAlexander Grafgdt_desc: 229f16408dfSAlexander Graf.short (5 * 8) - 1 230f16408dfSAlexander Graf.long gdt 231f16408dfSAlexander Graf 232dd4b2659SAlexander GrafBOOT_ROM_END 233