summaryrefslogtreecommitdiff
path: root/e820_bios.S
diff options
context:
space:
mode:
Diffstat (limited to 'e820_bios.S')
-rw-r--r--e820_bios.S202
1 files changed, 202 insertions, 0 deletions
diff --git a/e820_bios.S b/e820_bios.S
new file mode 100644
index 0000000..833cd31
--- /dev/null
+++ b/e820_bios.S
@@ -0,0 +1,202 @@
+/*
+ * 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