qemu/pc-bios/optionrom/multiboot.S
Paolo Bonzini c6e052f080 multiboot: fix e801 memory map
The e801 memory sizes in the multiboot structures hard-code the available
low memory to 640.  However, the value should not include the size of the
EBDA.  Fill the value in the option ROM, getting the size of low memory
from the BIOS.

Cc: Alexander Graf <agraf@suse.de>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
2012-11-30 08:27:47 -06:00

194 lines
4.2 KiB
ArmAsm

/*
* Multiboot Option ROM
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <http://www.gnu.org/licenses/>.
*
* Copyright Novell Inc, 2009
* Authors: Alexander Graf <agraf@suse.de>
*/
#include "optionrom.h"
#define BOOT_ROM_PRODUCT "multiboot loader"
#define MULTIBOOT_MAGIC 0x2badb002
#define GS_PROT_JUMP 0
#define GS_GDT_DESC 6
BOOT_ROM_START
run_multiboot:
cli
cld
mov %cs, %eax
shl $0x4, %eax
/* set up a long jump descriptor that is PC relative */
/* move stack memory to %gs */
mov %ss, %ecx
shl $0x4, %ecx
mov %esp, %ebx
add %ebx, %ecx
sub $0x20, %ecx
sub $0x30, %esp
shr $0x4, %ecx
mov %cx, %gs
/* now push the indirect jump descriptor there */
mov (prot_jump), %ebx
add %eax, %ebx
movl %ebx, %gs:GS_PROT_JUMP
mov $8, %bx
movw %bx, %gs:GS_PROT_JUMP + 4
/* fix the gdt descriptor to be PC relative */
movw (gdt_desc), %bx
movw %bx, %gs:GS_GDT_DESC
movl (gdt_desc+2), %ebx
add %eax, %ebx
movl %ebx, %gs:GS_GDT_DESC + 2
xor %eax, %eax
mov %eax, %es
/* Read the bootinfo struct into RAM */
read_fw_blob(FW_CFG_INITRD)
/* FS = bootinfo_struct */
read_fw FW_CFG_INITRD_ADDR
shr $4, %eax
mov %ax, %fs
/* Account for the EBDA in the multiboot structure's e801
* map.
*/
int $0x12
cwtl
movl %eax, %fs:4
/* ES = mmap_addr */
mov %fs:48, %eax
shr $4, %eax
mov %ax, %es
/* Initialize multiboot mmap structs using int 0x15(e820) */
xor %ebx, %ebx
/* mmap start after first size */
movl $4, %edi
mmap_loop:
/* entry size (mmap struct) & max buffer size (int15) */
movl $20, %ecx
/* store entry size */
/* old as(1) doesn't like this insn so emit the bytes instead:
movl %ecx, %es:-4(%edi)
*/
.dc.b 0x26,0x67,0x66,0x89,0x4f,0xfc
/* e820 */
movl $0x0000e820, %eax
/* 'SMAP' magic */
movl $0x534d4150, %edx
int $0x15
mmap_check_entry:
/* last entry? then we're done */
jb mmap_done
and %bx, %bx
jz mmap_done
/* valid entry, so let's loop on */
mmap_store_entry:
/* %ax = entry_number * 24 */
mov $24, %ax
mul %bx
mov %ax, %di
movw %di, %fs:0x2c
/* %di = 4 + (entry_number * 24) */
add $4, %di
jmp mmap_loop
mmap_done:
real_to_prot:
/* Load the GDT before going into protected mode */
lgdt:
data32 lgdt %gs:GS_GDT_DESC
/* get us to protected mode now */
movl $1, %eax
movl %eax, %cr0
/* the LJMP sets CS for us and gets us to 32-bit */
ljmp:
data32 ljmp *%gs:GS_PROT_JUMP
prot_mode:
.code32
/* initialize all other segments */
movl $0x10, %eax
movl %eax, %ss
movl %eax, %ds
movl %eax, %es
movl %eax, %fs
movl %eax, %gs
/* Read the kernel and modules into RAM */
read_fw_blob(FW_CFG_KERNEL)
/* Jump off to the kernel */
read_fw FW_CFG_KERNEL_ENTRY
mov %eax, %ecx
/* EBX contains a pointer to the bootinfo struct */
read_fw FW_CFG_INITRD_ADDR
movl %eax, %ebx
/* EAX has to contain the magic */
movl $MULTIBOOT_MAGIC, %eax
ljmp2:
jmp *%ecx
/* Variables */
.align 4, 0
prot_jump: .long prot_mode
.short 8
.align 4, 0
gdt:
/* 0x00 */
.byte 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
/* 0x08: code segment (base=0, limit=0xfffff, type=32bit code exec/read, DPL=0, 4k) */
.byte 0xff, 0xff, 0x00, 0x00, 0x00, 0x9a, 0xcf, 0x00
/* 0x10: data segment (base=0, limit=0xfffff, type=32bit data read/write, DPL=0, 4k) */
.byte 0xff, 0xff, 0x00, 0x00, 0x00, 0x92, 0xcf, 0x00
/* 0x18: code segment (base=0, limit=0x0ffff, type=16bit code exec/read/conf, DPL=0, 1b) */
.byte 0xff, 0xff, 0x00, 0x00, 0x00, 0x9e, 0x00, 0x00
/* 0x20: data segment (base=0, limit=0x0ffff, type=16bit data read/write, DPL=0, 1b) */
.byte 0xff, 0xff, 0x00, 0x00, 0x00, 0x92, 0x00, 0x00
gdt_desc:
.short (5 * 8) - 1
.long gdt
BOOT_ROM_END