202 lines
4.3 KiB
ArmAsm
202 lines
4.3 KiB
ArmAsm
/*
|
|
* e820_bios.S: read e820 by int 15h call.
|
|
*
|
|
* The C language function exported by this file is:
|
|
* int get_e820_by_bios(void *e820_buf);
|
|
* @e820_buf: e820 mem map buffer, allocated by caller
|
|
* return: number of e820 entries
|
|
*
|
|
* Copyright (C) 2013 Intel Corporation.
|
|
* Author: Bin Gao <bin.gao@intel.com>
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify it
|
|
* under the terms and conditions of the GNU General Public License,
|
|
* version 2, as published by the Free Software Foundation.
|
|
*
|
|
* This program is distributed in the hope 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, write to the Free Software Foundation, Inc.,
|
|
* 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
|
|
*
|
|
*/
|
|
|
|
#include "bootstub.h"
|
|
|
|
/* Real mode low memory layout */
|
|
#define IDT_START 0x0
|
|
#define RELOCATED_START 0xa000
|
|
#define STACK_START 0xb000
|
|
#define DATA_START 0xb200
|
|
|
|
#define SAVED_GDTR_ADDR 0xb100
|
|
#define SAVED_IDTR_ADDR 0xb110
|
|
#define COUNT_ADDR 0xb120
|
|
#define TOTAL_COUNT_ADDR 0xb130
|
|
#define MIN_BUF_LEN 20
|
|
#define BUF_LEN 2048
|
|
#define MAX_NR_ENTRIES 128
|
|
|
|
#define SMAP 0x534d4150
|
|
#define E820 0xe820
|
|
|
|
.text
|
|
.section ".text.head","ax",@progbits
|
|
|
|
.code32
|
|
.globl get_e820_by_bios
|
|
get_e820_by_bios:
|
|
jmp start_32bit
|
|
|
|
.balign 16
|
|
idtr:
|
|
.word 0xffff
|
|
.long IDT_START
|
|
|
|
.balign 16
|
|
gdt:
|
|
.quad 0
|
|
.quad GDT_ENTRY(0x009b, 0, 0xffff)
|
|
.quad GDT_ENTRY(0x0093, 0, 0xffff)
|
|
gdtr:
|
|
.word 3*8-1
|
|
.long gdt
|
|
|
|
saved_esp:
|
|
.long 0
|
|
|
|
start_32bit:
|
|
pushal
|
|
pushfl
|
|
|
|
/* Save ESP, GDTR and IDTR registers */
|
|
movl $saved_esp, %eax
|
|
movl %esp, (%eax)
|
|
xorl %eax, %eax
|
|
sidtl SAVED_IDTR_ADDR(%eax)
|
|
sgdtl SAVED_GDTR_ADDR(%eax)
|
|
|
|
/* Relocate real mode codes to 64k segment */
|
|
movl $relocated_end + 4, %ecx
|
|
subl $relocated_start, %ecx
|
|
shrl $2, %ecx
|
|
movl $relocated_start, %esi
|
|
movl $RELOCATED_START, %edi
|
|
rep movsl
|
|
|
|
/* Set up real mode IDT */
|
|
lidtl %cs:idtr
|
|
|
|
/* Set up real mode GDT */
|
|
lgdtl %cs:gdtr
|
|
movl $16, %ecx
|
|
movl %ecx, %ds
|
|
movl %ecx, %es
|
|
movl %ecx, %fs
|
|
movl %ecx, %gs
|
|
movl %ecx, %ss
|
|
|
|
/* Switch to 16bit segment */
|
|
ljmpl $8, $RELOCATED_START
|
|
|
|
.code16
|
|
relocated_start:
|
|
reloc_base = .
|
|
|
|
/* Switch to real mode */
|
|
andb $0x10, %al
|
|
movl %eax, %cr0
|
|
ljmpw $0, $realmode_entry - relocated_start + RELOCATED_START
|
|
|
|
realmode_entry = .
|
|
/* In real mode now, set up segment selectors */
|
|
movl $0, %eax
|
|
movl %eax, %ds
|
|
movl %eax, %es
|
|
movl %eax, %ss
|
|
movl %eax, %gs
|
|
movl %eax, %fs
|
|
|
|
movl $STACK_START, %esp
|
|
|
|
/* Do int 15h call */
|
|
movl $COUNT_ADDR, %eax
|
|
movl $0, (%eax)
|
|
movl $TOTAL_COUNT_ADDR, %eax
|
|
movl $0, (%eax)
|
|
xorl %ebx, %ebx
|
|
movw $DATA_START, %di
|
|
again:
|
|
movw $E820, %ax
|
|
movw $BUF_LEN, %cx
|
|
movl $SMAP, %edx
|
|
int $0x15
|
|
jc error /* EFLGAS.CF is set */
|
|
cmpl $SMAP, %eax
|
|
jne error /* eax is not 'SMAP' */
|
|
cmpw $MIN_BUF_LEN, %cx
|
|
jl error /* returned buffer len < 20 */
|
|
cmpw $BUF_LEN, %cx
|
|
jg error /* returned buffer len > provided buffer len */
|
|
movl $TOTAL_COUNT_ADDR, %eax
|
|
addw %cx, (%eax)
|
|
movl $COUNT_ADDR, %eax
|
|
incl (%eax)
|
|
movl (%eax), %eax
|
|
cmpl $MAX_NR_ENTRIES, %eax /* max supported entries: 128 */
|
|
jge done
|
|
testl %ebx, %ebx /* ebx == 0: done, ebx != 0: continue */
|
|
je done
|
|
addw %cx, %di
|
|
jmp again
|
|
done:
|
|
jmp 2f
|
|
error:
|
|
movl $COUNT_ADDR, %eax
|
|
movl $~0, (%eax)
|
|
2:
|
|
|
|
/* Switch back to protected mode */
|
|
xorl %ebx, %ebx
|
|
lidtl SAVED_IDTR_ADDR(%ebx)
|
|
lgdtl SAVED_GDTR_ADDR(%ebx)
|
|
movl %cr0, %ebx
|
|
orb $1, %bl
|
|
movl %ebx, %cr0
|
|
.byte 0x66, 0xea /* opcode(JMP FAR) with operand size override */
|
|
.long resumed_protected_mode /* offset */
|
|
.word __BOOT_CS /* segment selector */
|
|
relocated_end = .
|
|
|
|
.code32
|
|
resumed_protected_mode:
|
|
cli /* in case real mode codes turn on interrrupt! */
|
|
/* Restore segment registers */
|
|
movl $__BOOT_DS, %ebx
|
|
movl %ebx, %ds
|
|
movl %ebx, %es
|
|
movl %ebx, %gs
|
|
movl %ebx, %fs
|
|
movl %ebx, %ss
|
|
|
|
/* Restore stack pointer */
|
|
movl $saved_esp, %eax
|
|
movl (%eax), %esp
|
|
|
|
/* Copy e820 data from our buffer to caller's buffer */
|
|
xorl %eax, %eax
|
|
movl TOTAL_COUNT_ADDR(%eax), %ecx
|
|
movl $DATA_START, %esi
|
|
movl 40(%esp), %edi
|
|
rep movsb
|
|
|
|
popfl
|
|
popal
|
|
|
|
/* Return number of e820 entries */
|
|
movl $COUNT_ADDR, %eax
|
|
movl (%eax), %eax
|
|
ret
|