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 21f16408dfSAlexander Graf#define NO_QEMU_PROTOS 22f16408dfSAlexander Graf#include "../../hw/fw_cfg.h" 23f16408dfSAlexander Graf 24f16408dfSAlexander Graf#define BIOS_CFG_IOPORT_CFG 0x510 25f16408dfSAlexander Graf#define BIOS_CFG_IOPORT_DATA 0x511 26f16408dfSAlexander Graf 27f16408dfSAlexander Graf#define MULTIBOOT_MAGIC 0x2badb002 28f16408dfSAlexander Graf 29f16408dfSAlexander Graf/* Read a variable from the fw_cfg device. 30f16408dfSAlexander Graf Clobbers: %edx 31f16408dfSAlexander Graf Out: %eax */ 32f16408dfSAlexander Graf.macro read_fw VAR 33f16408dfSAlexander Graf mov $\VAR, %ax 34f16408dfSAlexander Graf mov $BIOS_CFG_IOPORT_CFG, %dx 35f16408dfSAlexander Graf outw %ax, (%dx) 36f16408dfSAlexander Graf mov $BIOS_CFG_IOPORT_DATA, %dx 37f16408dfSAlexander Graf inb (%dx), %al 38f16408dfSAlexander Graf shl $8, %eax 39f16408dfSAlexander Graf inb (%dx), %al 40f16408dfSAlexander Graf shl $8, %eax 41f16408dfSAlexander Graf inb (%dx), %al 42f16408dfSAlexander Graf shl $8, %eax 43f16408dfSAlexander Graf inb (%dx), %al 44f16408dfSAlexander Graf bswap %eax 45f16408dfSAlexander Graf.endm 46f16408dfSAlexander Graf 47f16408dfSAlexander Graf.code16 48f16408dfSAlexander Graf.text 49f16408dfSAlexander Graf .global _start 50f16408dfSAlexander Graf_start: 51f16408dfSAlexander Graf .short 0xaa55 528676188bSBlue Swirl .byte 1 /* (_end - _start) / 512 */ 53f16408dfSAlexander Graf push %eax 54f16408dfSAlexander Graf push %ds 55f16408dfSAlexander Graf 56f16408dfSAlexander Graf /* setup ds so we can access the IVT */ 57f16408dfSAlexander Graf xor %ax, %ax 58f16408dfSAlexander Graf mov %ax, %ds 59f16408dfSAlexander Graf 60f16408dfSAlexander Graf /* save old int 19 */ 61f16408dfSAlexander Graf mov (0x19*4), %eax 62f16408dfSAlexander Graf mov %eax, %cs:old_int19 63f16408dfSAlexander Graf 64f16408dfSAlexander Graf /* install our int 19 handler */ 65f16408dfSAlexander Graf movw $int19_handler, (0x19*4) 66f16408dfSAlexander Graf mov %cs, (0x19*4+2) 67f16408dfSAlexander Graf 68f16408dfSAlexander Graf pop %ds 69f16408dfSAlexander Graf pop %eax 70f16408dfSAlexander Graf lret 71f16408dfSAlexander Graf 72f16408dfSAlexander Grafint19_handler: 73f16408dfSAlexander Graf /* DS = CS */ 74f16408dfSAlexander Graf movw %cs, %ax 75f16408dfSAlexander Graf movw %ax, %ds 76f16408dfSAlexander Graf 77f16408dfSAlexander Graf /* fall through */ 78f16408dfSAlexander Graf 79f16408dfSAlexander Grafrun_multiboot: 80f16408dfSAlexander Graf 81f16408dfSAlexander Graf cli 82f16408dfSAlexander Graf cld 83f16408dfSAlexander Graf 84f16408dfSAlexander Graf mov %cs, %eax 85f16408dfSAlexander Graf shl $0x4, %eax 86f16408dfSAlexander Graf 87f16408dfSAlexander Graf /* fix the gdt descriptor to be PC relative */ 88f16408dfSAlexander Graf mov (gdt_desc+2), %ebx 89f16408dfSAlexander Graf add %eax, %ebx 90f16408dfSAlexander Graf mov %ebx, (gdt_desc+2) 91f16408dfSAlexander Graf 92f16408dfSAlexander Graf /* fix the prot mode indirect jump to be PC relative */ 93f16408dfSAlexander Graf mov (prot_jump), %ebx 94f16408dfSAlexander Graf add %eax, %ebx 95f16408dfSAlexander Graf mov %ebx, (prot_jump) 96f16408dfSAlexander Graf 97f16408dfSAlexander Graf /* FS = bootinfo_struct */ 98f16408dfSAlexander Graf read_fw FW_CFG_INITRD_ADDR 99f16408dfSAlexander Graf shr $4, %eax 100f16408dfSAlexander Graf mov %ax, %fs 101f16408dfSAlexander Graf 102f16408dfSAlexander Graf /* ES = mmap_addr */ 103f16408dfSAlexander Graf read_fw FW_CFG_INITRD_SIZE 104f16408dfSAlexander Graf shr $4, %eax 105f16408dfSAlexander Graf mov %ax, %es 106f16408dfSAlexander Graf 107f16408dfSAlexander Graf /* Initialize multiboot mmap structs using int 0x15(e820) */ 108f16408dfSAlexander Graf xor %ebx, %ebx 109f16408dfSAlexander Graf /* mmap start after first size */ 110f16408dfSAlexander Graf movl $4, %edi 111f16408dfSAlexander Graf 112f16408dfSAlexander Grafmmap_loop: 113f16408dfSAlexander Graf /* entry size (mmap struct) & max buffer size (int15) */ 114f16408dfSAlexander Graf movl $20, %ecx 115f16408dfSAlexander Graf /* store entry size */ 116*ff56954bSJuergen Lock /* old as(1) doesn't like this insn so emit the bytes instead: 117f16408dfSAlexander Graf movl %ecx, %es:-4(%edi) 118*ff56954bSJuergen Lock */ 119*ff56954bSJuergen Lock .dc.b 0x26,0x67,0x66,0x89,0x4f,0xfc 120f16408dfSAlexander Graf /* e820 */ 121f16408dfSAlexander Graf movl $0x0000e820, %eax 122f16408dfSAlexander Graf /* 'SMAP' magic */ 123f16408dfSAlexander Graf movl $0x534d4150, %edx 124f16408dfSAlexander Graf int $0x15 125f16408dfSAlexander Graf 126f16408dfSAlexander Grafmmap_check_entry: 127f16408dfSAlexander Graf /* last entry? then we're done */ 128f16408dfSAlexander Graf jb mmap_done 129f16408dfSAlexander Graf and %bx, %bx 130f16408dfSAlexander Graf jz mmap_done 131f16408dfSAlexander Graf /* valid entry, so let's loop on */ 132f16408dfSAlexander Graf 133f16408dfSAlexander Grafmmap_store_entry: 134f16408dfSAlexander Graf /* %ax = entry_number * 24 */ 135f16408dfSAlexander Graf mov $24, %ax 136f16408dfSAlexander Graf mul %bx 137f16408dfSAlexander Graf mov %ax, %di 138f16408dfSAlexander Graf movw %di, %fs:0x2c 139f16408dfSAlexander Graf /* %di = 4 + (entry_number * 24) */ 140f16408dfSAlexander Graf add $4, %di 141f16408dfSAlexander Graf jmp mmap_loop 142f16408dfSAlexander Graf 143f16408dfSAlexander Grafmmap_done: 144f16408dfSAlexander Grafreal_to_prot: 145f16408dfSAlexander Graf /* Load the GDT before going into protected mode */ 146f16408dfSAlexander Graflgdt: 147f16408dfSAlexander Graf data32 lgdt %cs:gdt_desc 148f16408dfSAlexander Graf 149f16408dfSAlexander Graf /* get us to protected mode now */ 150f16408dfSAlexander Graf movl $1, %eax 151f16408dfSAlexander Graf movl %eax, %cr0 152f16408dfSAlexander Graf 153f16408dfSAlexander Graf /* the LJMP sets CS for us and gets us to 32-bit */ 154f16408dfSAlexander Grafljmp: 155f16408dfSAlexander Graf data32 ljmp *%cs:prot_jump 156f16408dfSAlexander Graf 157f16408dfSAlexander Grafprot_mode: 158f16408dfSAlexander Graf.code32 159f16408dfSAlexander Graf 160f16408dfSAlexander Graf /* initialize all other segments */ 161f16408dfSAlexander Graf movl $0x10, %eax 162f16408dfSAlexander Graf movl %eax, %ss 163f16408dfSAlexander Graf movl %eax, %ds 164f16408dfSAlexander Graf movl %eax, %es 165f16408dfSAlexander Graf movl %eax, %fs 166f16408dfSAlexander Graf movl %eax, %gs 167f16408dfSAlexander Graf 168f16408dfSAlexander Graf /* Jump off to the kernel */ 169f16408dfSAlexander Graf read_fw FW_CFG_KERNEL_ADDR 170f16408dfSAlexander Graf mov %eax, %ecx 171f16408dfSAlexander Graf 172f16408dfSAlexander Graf /* EBX contains a pointer to the bootinfo struct */ 173f16408dfSAlexander Graf read_fw FW_CFG_INITRD_ADDR 174f16408dfSAlexander Graf movl %eax, %ebx 175f16408dfSAlexander Graf 176f16408dfSAlexander Graf /* EAX has to contain the magic */ 177f16408dfSAlexander Graf movl $MULTIBOOT_MAGIC, %eax 178f16408dfSAlexander Grafljmp2: 179f16408dfSAlexander Graf jmp *%ecx 180f16408dfSAlexander Graf 181f16408dfSAlexander Graf/* Variables */ 182f16408dfSAlexander Graf.align 4, 0 183f16408dfSAlexander Grafold_int19: .long 0 184f16408dfSAlexander Graf 185f16408dfSAlexander Grafprot_jump: .long prot_mode 186f16408dfSAlexander Graf .short 8 187f16408dfSAlexander Graf 188f16408dfSAlexander Graf.align 4, 0 189f16408dfSAlexander Grafgdt: 190f16408dfSAlexander Graf /* 0x00 */ 191f16408dfSAlexander Graf.byte 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 192f16408dfSAlexander Graf 193f16408dfSAlexander Graf /* 0x08: code segment (base=0, limit=0xfffff, type=32bit code exec/read, DPL=0, 4k) */ 194f16408dfSAlexander Graf.byte 0xff, 0xff, 0x00, 0x00, 0x00, 0x9a, 0xcf, 0x00 195f16408dfSAlexander Graf 196f16408dfSAlexander Graf /* 0x10: data segment (base=0, limit=0xfffff, type=32bit data read/write, DPL=0, 4k) */ 197f16408dfSAlexander Graf.byte 0xff, 0xff, 0x00, 0x00, 0x00, 0x92, 0xcf, 0x00 198f16408dfSAlexander Graf 199f16408dfSAlexander Graf /* 0x18: code segment (base=0, limit=0x0ffff, type=16bit code exec/read/conf, DPL=0, 1b) */ 200f16408dfSAlexander Graf.byte 0xff, 0xff, 0x00, 0x00, 0x00, 0x9e, 0x00, 0x00 201f16408dfSAlexander Graf 202f16408dfSAlexander Graf /* 0x20: data segment (base=0, limit=0x0ffff, type=16bit data read/write, DPL=0, 1b) */ 203f16408dfSAlexander Graf.byte 0xff, 0xff, 0x00, 0x00, 0x00, 0x92, 0x00, 0x00 204f16408dfSAlexander Graf 205f16408dfSAlexander Grafgdt_desc: 206f16408dfSAlexander Graf.short (5 * 8) - 1 207f16408dfSAlexander Graf.long gdt 208f16408dfSAlexander Graf 209f16408dfSAlexander Graf.align 512, 0 210f16408dfSAlexander Graf_end: 211f16408dfSAlexander Graf 212