Bin Gao | 923fa8d | 2013-03-30 00:27:10 -0700 | [diff] [blame] | 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@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 |