You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
202 lines
4.3 KiB
202 lines
4.3 KiB
/* |
|
* 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
|
|
|