summaryrefslogtreecommitdiff
path: root/e820_bios.S
diff options
context:
space:
mode:
authorBin Gao <bin.gao@intel.com>2013-03-30 00:27:10 -0700
committerPatrick Tjin <pattjin@google.com>2014-07-21 20:22:40 -0700
commit923fa8dbef1ea905fca31f008bdcfac9a6c33001 (patch)
tree2ff8a10a062373213beb9874daf8a77f754216a8 /e820_bios.S
parent8a13ab75e9709abcf6fb1ec105111f922abdae75 (diff)
downloadbootstub-923fa8dbef1ea905fca31f008bdcfac9a6c33001.tar.gz
bootstub: get system memory map by int 15h on Baytrail platform
BZ: 96847 There is no SFI MMAP table any more for Baytrail platform. Now we can get system memory map information by int 15h which returns an e820 table with memory map entries. We have to switch to real mode to call int 15h then switch back to protected mode. This patch implements the real mode int 15 call in assembly language but exported a C style function: int get_e820_by_bios(void *e820_buf); See details in e820_bios.S. Change-Id: I33dbeaaa58da217e74e015f0d911896500043d17 Signed-off-by: Bin Gao <bin.gao@intel.com> Reviewed-on: http://android.intel.com:8080/99216 Reviewed-by: Balestriere, VianneyX <vianneyx.balestriere@intel.com> Tested-by: Balestriere, VianneyX <vianneyx.balestriere@intel.com>
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