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 */ 7177873196SAlexander Graf read_fw_blob(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 92*390fb6b4SKevin Wolf /* Start storing mmap data at %es:0 */ 93*390fb6b4SKevin Wolf xor %edi, %edi 94f16408dfSAlexander Graf 95f16408dfSAlexander Grafmmap_loop: 96*390fb6b4SKevin Wolf /* The multiboot entry size has offset -4, so leave some space */ 97*390fb6b4SKevin 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: 107*390fb6b4SKevin Wolf /* Error or last entry already done? */ 108f16408dfSAlexander Graf jb mmap_done 109f16408dfSAlexander Graf 110f16408dfSAlexander Grafmmap_store_entry: 111*390fb6b4SKevin Wolf /* store entry size */ 112*390fb6b4SKevin Wolf /* old as(1) doesn't like this insn so emit the bytes instead: 113*390fb6b4SKevin Wolf movl %ecx, %es:-4(%edi) 114*390fb6b4SKevin Wolf */ 115*390fb6b4SKevin Wolf .dc.b 0x26,0x67,0x66,0x89,0x4f,0xfc 116*390fb6b4SKevin Wolf 117*390fb6b4SKevin Wolf /* %edi += entry_size, store as mbs_mmap_length */ 118*390fb6b4SKevin Wolf add %ecx, %edi 119f16408dfSAlexander Graf movw %di, %fs:0x2c 120*390fb6b4SKevin Wolf 121*390fb6b4SKevin Wolf /* Continuation value 0 means last entry */ 122*390fb6b4SKevin Wolf test %ebx, %ebx 123*390fb6b4SKevin Wolf jnz mmap_loop 124f16408dfSAlexander Graf 125f16408dfSAlexander Grafmmap_done: 126f16408dfSAlexander Grafreal_to_prot: 127f16408dfSAlexander Graf /* Load the GDT before going into protected mode */ 128f16408dfSAlexander Graflgdt: 12977873196SAlexander Graf data32 lgdt %gs:GS_GDT_DESC 130f16408dfSAlexander Graf 131f16408dfSAlexander Graf /* get us to protected mode now */ 132f16408dfSAlexander Graf movl $1, %eax 133f16408dfSAlexander Graf movl %eax, %cr0 134f16408dfSAlexander Graf 135f16408dfSAlexander Graf /* the LJMP sets CS for us and gets us to 32-bit */ 136f16408dfSAlexander Grafljmp: 13777873196SAlexander Graf data32 ljmp *%gs:GS_PROT_JUMP 138f16408dfSAlexander Graf 139f16408dfSAlexander Grafprot_mode: 140f16408dfSAlexander Graf.code32 141f16408dfSAlexander Graf 142f16408dfSAlexander Graf /* initialize all other segments */ 143f16408dfSAlexander Graf movl $0x10, %eax 144f16408dfSAlexander Graf movl %eax, %ss 145f16408dfSAlexander Graf movl %eax, %ds 146f16408dfSAlexander Graf movl %eax, %es 147f16408dfSAlexander Graf movl %eax, %fs 148f16408dfSAlexander Graf movl %eax, %gs 149f16408dfSAlexander Graf 15077873196SAlexander Graf /* Read the kernel and modules into RAM */ 15177873196SAlexander Graf read_fw_blob(FW_CFG_KERNEL) 15277873196SAlexander Graf 153f16408dfSAlexander Graf /* Jump off to the kernel */ 15477873196SAlexander Graf read_fw FW_CFG_KERNEL_ENTRY 155f16408dfSAlexander Graf mov %eax, %ecx 156f16408dfSAlexander Graf 157f16408dfSAlexander Graf /* EBX contains a pointer to the bootinfo struct */ 158f16408dfSAlexander Graf read_fw FW_CFG_INITRD_ADDR 159f16408dfSAlexander Graf movl %eax, %ebx 160f16408dfSAlexander Graf 161f16408dfSAlexander Graf /* EAX has to contain the magic */ 162f16408dfSAlexander Graf movl $MULTIBOOT_MAGIC, %eax 163f16408dfSAlexander Grafljmp2: 164f16408dfSAlexander Graf jmp *%ecx 165f16408dfSAlexander Graf 166f16408dfSAlexander Graf/* Variables */ 167f16408dfSAlexander Graf.align 4, 0 168f16408dfSAlexander Grafprot_jump: .long prot_mode 169f16408dfSAlexander Graf .short 8 170f16408dfSAlexander Graf 171f16408dfSAlexander Graf.align 4, 0 172f16408dfSAlexander Grafgdt: 173f16408dfSAlexander Graf /* 0x00 */ 174f16408dfSAlexander Graf.byte 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 175f16408dfSAlexander Graf 176f16408dfSAlexander Graf /* 0x08: code segment (base=0, limit=0xfffff, type=32bit code exec/read, DPL=0, 4k) */ 177f16408dfSAlexander Graf.byte 0xff, 0xff, 0x00, 0x00, 0x00, 0x9a, 0xcf, 0x00 178f16408dfSAlexander Graf 179f16408dfSAlexander Graf /* 0x10: data segment (base=0, limit=0xfffff, type=32bit data read/write, DPL=0, 4k) */ 180f16408dfSAlexander Graf.byte 0xff, 0xff, 0x00, 0x00, 0x00, 0x92, 0xcf, 0x00 181f16408dfSAlexander Graf 182f16408dfSAlexander Graf /* 0x18: code segment (base=0, limit=0x0ffff, type=16bit code exec/read/conf, DPL=0, 1b) */ 183f16408dfSAlexander Graf.byte 0xff, 0xff, 0x00, 0x00, 0x00, 0x9e, 0x00, 0x00 184f16408dfSAlexander Graf 185f16408dfSAlexander Graf /* 0x20: data segment (base=0, limit=0x0ffff, type=16bit data read/write, DPL=0, 1b) */ 186f16408dfSAlexander Graf.byte 0xff, 0xff, 0x00, 0x00, 0x00, 0x92, 0x00, 0x00 187f16408dfSAlexander Graf 188f16408dfSAlexander Grafgdt_desc: 189f16408dfSAlexander Graf.short (5 * 8) - 1 190f16408dfSAlexander Graf.long gdt 191f16408dfSAlexander Graf 192dd4b2659SAlexander GrafBOOT_ROM_END 193