Home | History | Annotate | Download | only in bootstub
      1 /*
      2  * e820_bios.S: read e820 by int 15h call.
      3  *
      4  * The C language function exported by this file is:
      5  * int get_e820_by_bios(void *e820_buf);
      6  * @e820_buf: e820 mem map buffer, allocated by caller
      7  * return: number of e820 entries
      8  *
      9  * Copyright (C) 2013 Intel Corporation.
     10  * Author: Bin Gao <bin.gao (at) intel.com>
     11  *
     12  * This program is free software; you can redistribute it and/or modify it
     13  * under the terms and conditions of the GNU General Public License,
     14  * version 2, as published by the Free Software Foundation.
     15  *
     16  * This program is distributed in the hope it will be useful, but WITHOUT
     17  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
     18  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
     19  * more details.
     20  *
     21  * You should have received a copy of the GNU General Public License along with
     22  * this program; if not, write to the Free Software Foundation, Inc.,
     23  * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
     24  *
     25  */
     26 
     27 #include "bootstub.h"
     28 
     29 /* Real mode low memory layout */
     30 #define IDT_START	0x0
     31 #define RELOCATED_START	0xa000
     32 #define	STACK_START	0xb000
     33 #define DATA_START	0xb200
     34 
     35 #define SAVED_GDTR_ADDR	0xb100
     36 #define SAVED_IDTR_ADDR	0xb110
     37 #define	COUNT_ADDR	0xb120
     38 #define	TOTAL_COUNT_ADDR	0xb130
     39 #define MIN_BUF_LEN	20
     40 #define	BUF_LEN		2048
     41 #define MAX_NR_ENTRIES	128
     42 
     43 #define SMAP	0x534d4150
     44 #define E820	0xe820
     45 
     46 .text
     47 .section ".text.head","ax",@progbits
     48 
     49 	.code32
     50 	.globl get_e820_by_bios
     51 get_e820_by_bios:
     52 	jmp	start_32bit
     53 
     54 	.balign 16
     55 idtr:
     56 	.word	0xffff
     57 	.long	IDT_START
     58 
     59 	.balign 16
     60 gdt:
     61 	.quad	0
     62 	.quad	GDT_ENTRY(0x009b, 0, 0xffff)
     63 	.quad	GDT_ENTRY(0x0093, 0, 0xffff)
     64 gdtr:
     65 	.word	3*8-1
     66 	.long	gdt
     67 
     68 saved_esp:
     69 	.long	0
     70 
     71 start_32bit:
     72 	pushal
     73 	pushfl
     74 
     75 	/* Save ESP, GDTR and IDTR registers */
     76         movl	$saved_esp, %eax
     77 	movl	%esp, (%eax)
     78 	xorl	%eax, %eax
     79 	sidtl	SAVED_IDTR_ADDR(%eax)
     80 	sgdtl	SAVED_GDTR_ADDR(%eax)
     81 
     82 	/* Relocate real mode codes to 64k segment */
     83 	movl    $relocated_end + 4, %ecx
     84 	subl	$relocated_start, %ecx
     85 	shrl	$2, %ecx
     86         movl    $relocated_start, %esi
     87         movl    $RELOCATED_START, %edi
     88         rep     movsl
     89 
     90 	/* Set up real mode IDT */
     91 	lidtl	%cs:idtr
     92 
     93 	/* Set up real mode GDT */
     94 	lgdtl	%cs:gdtr
     95 	movl	$16, %ecx
     96 	movl	%ecx, %ds
     97 	movl	%ecx, %es
     98 	movl	%ecx, %fs
     99 	movl	%ecx, %gs
    100 	movl	%ecx, %ss
    101 
    102 	/* Switch to 16bit segment */
    103 	ljmpl	$8, $RELOCATED_START
    104 
    105 	.code16
    106 relocated_start:
    107 reloc_base = .
    108 
    109 	/* Switch to real mode */
    110 	andb	$0x10, %al
    111 	movl	%eax, %cr0
    112 	ljmpw	$0, $realmode_entry - relocated_start + RELOCATED_START
    113 
    114 realmode_entry = .
    115 	/* In real mode now, set up segment selectors */
    116 	movl	$0, %eax
    117 	movl	%eax, %ds
    118 	movl	%eax, %es
    119 	movl	%eax, %ss
    120 	movl	%eax, %gs
    121 	movl	%eax, %fs
    122 
    123 	movl	$STACK_START, %esp
    124 
    125 	/* Do int 15h call */
    126 	movl	$COUNT_ADDR, %eax
    127 	movl	$0, (%eax)
    128 	movl	$TOTAL_COUNT_ADDR, %eax
    129 	movl	$0, (%eax)
    130 	xorl	%ebx, %ebx
    131 	movw	$DATA_START, %di
    132 again:
    133 	movw	$E820, %ax
    134 	movw	$BUF_LEN, %cx
    135 	movl	$SMAP, %edx
    136 	int	$0x15
    137 	jc	error	/* EFLGAS.CF is set */
    138 	cmpl	$SMAP, %eax
    139 	jne	error	/* eax is not 'SMAP' */
    140 	cmpw	$MIN_BUF_LEN, %cx
    141 	jl	error /* returned buffer len < 20 */
    142 	cmpw	$BUF_LEN, %cx
    143 	jg	error /* returned buffer len > provided buffer len */
    144 	movl	$TOTAL_COUNT_ADDR, %eax
    145 	addw	%cx, (%eax)
    146 	movl	$COUNT_ADDR, %eax
    147 	incl	(%eax)
    148 	movl	(%eax), %eax
    149 	cmpl	$MAX_NR_ENTRIES, %eax /* max supported entries: 128 */
    150 	jge	done
    151 	testl	%ebx, %ebx /* ebx == 0: done, ebx != 0: continue */
    152 	je	done
    153 	addw	%cx, %di
    154 	jmp	again
    155 done:
    156 	jmp	2f
    157 error:
    158 	movl	$COUNT_ADDR, %eax
    159 	movl	$~0, (%eax)
    160 2:
    161 
    162 	/* Switch back to protected mode */
    163 	xorl	%ebx, %ebx
    164 	lidtl	SAVED_IDTR_ADDR(%ebx)
    165 	lgdtl	SAVED_GDTR_ADDR(%ebx)
    166 	movl    %cr0, %ebx
    167 	orb	$1, %bl
    168 	movl    %ebx, %cr0
    169 	.byte	0x66, 0xea /* opcode(JMP FAR) with operand size override */
    170 	.long	resumed_protected_mode	/* offset */
    171 	.word	__BOOT_CS /* segment selector */
    172 relocated_end = .
    173 
    174 	.code32
    175 resumed_protected_mode:
    176 	cli /* in case real mode codes turn on interrrupt! */
    177 	/* Restore segment registers */
    178 	movl	$__BOOT_DS, %ebx
    179 	movl	%ebx, %ds
    180 	movl	%ebx, %es
    181 	movl	%ebx, %gs
    182 	movl	%ebx, %fs
    183 	movl	%ebx, %ss
    184 
    185 	/* Restore stack pointer */
    186 	movl	$saved_esp, %eax
    187 	movl	(%eax), %esp
    188 
    189 	/* Copy e820 data from our buffer to caller's buffer */
    190 	xorl	%eax, %eax
    191 	movl	TOTAL_COUNT_ADDR(%eax), %ecx
    192 	movl    $DATA_START, %esi
    193 	movl    40(%esp), %edi
    194 	rep     movsb
    195 
    196 	popfl
    197 	popal
    198 
    199 	/* Return number of e820 entries */
    200 	movl	$COUNT_ADDR, %eax
    201 	movl	(%eax), %eax
    202 	ret
    203