1/* 2 * This file is part of the coreboot project. 3 * 4 * Copyright (C) 2009 coresystems GmbH 5 * 6 * This program is free software; you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License as published by 8 * the Free Software Foundation; version 2 of the License. 9 * 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU General Public License for more details. 14 * 15 * You should have received a copy of the GNU General Public License 16 * along with this program; if not, write to the Free Software 17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. 18 */ 19 20#define REALMODE_BASE 0x600 21#define RELOCATED(x) (x - __realmode_code + REALMODE_BASE) 22 23/* CR0 bits */ 24#define PE (1 << 0) 25 26/* This is the intXX interrupt handler stub code. It gets copied 27 * to the IDT and to some fixed addresses in the F segment. Before 28 * the code can used, it gets patched up by the C function copying 29 * it: byte 3 (the $0 in movb $0, %al) is overwritten with the int#. 30 */ 31 32 .code16 33 .globl __idt_handler 34__idt_handler: 35 pushal 36 movb $0, %al /* This instruction gets modified */ 37 ljmp $0, $__interrupt_handler_16bit 38 .globl __idt_handler_size 39__idt_handler_size = ( . - __idt_handler) 40 41 42/* In order to be independent of coreboot's position in RAM 43 * we relocate a part of the code to the low megabyte, so the 44 * CPU can use it in real-mode. This code lives at __realmode_code. 45 */ 46 .globl __realmode_code 47__realmode_code: 48 49/* Realmode IDT pointer structure. */ 50 .globl __realmode_idt 51__realmode_idt = RELOCATED(.) 52 .word 1023 /* 16-bit limit */ 53 .long 0 /* 24-bit base */ 54 .word 0 55 56/* Preserve old stack */ 57__stack = RELOCATED(.) 58 .long 0 59 60 .code32 61 .globl __run_optionrom 62__run_optionrom = RELOCATED(.) 63 /* save all registers to the stack */ 64 pushal 65 66 /* Move the protected mode stack to a safe place */ 67 mov %esp, __stack 68 69 /* Get devfn into %ecx */ 70 movl %esp, %ebp 71 // FIXME: Should this function be called with regparm=0? 72 movl 8(%ebp), %ecx 73 74 /* Activate the right segment descriptor real mode. */ 75 ljmp $0x28, $RELOCATED(1f) 761: 77.code16 78 /* 16 bit code from here on... */ 79 80 /* Load the segment registers w/ properly configured 81 * segment descriptors. They will retain these 82 * configurations (limits, writability, etc.) once 83 * protected mode is turned off. 84 */ 85 mov $0x30, %ax 86 mov %ax, %ds 87 mov %ax, %es 88 mov %ax, %fs 89 mov %ax, %gs 90 mov %ax, %ss 91 92 /* Turn off protection */ 93 movl %cr0, %eax 94 andl $~PE, %eax 95 movl %eax, %cr0 96 97 /* Now really going into real mode */ 98 ljmp $0, $RELOCATED(1f) 991: 100 /* Setup a stack: Put the stack at the end of page zero. 101 * That way we can easily share it between real and 102 * protected, since the 16-bit ESP at segment 0 will 103 * work for any case. */ 104 mov $0x0, %ax 105 mov %ax, %ss 106 movl $0x1000, %eax 107 movl %eax, %esp 108 109 /* Load our 16 bit idt */ 110 xor %ax, %ax 111 mov %ax, %ds 112 lidt __realmode_idt 113 114 /* Set all segments to 0x0000, ds to 0x0040 */ 115 mov %ax, %es 116 mov %ax, %fs 117 mov %ax, %gs 118 mov $0x40, %ax 119 mov %ax, %ds 120 mov %cx, %ax // restore ax 121 122 /* ************************************ */ 123 // TODO this will not work for non-VGA option ROMs 124 /* run VGA BIOS at 0xc000:0003 */ 125 lcall $0xc000, $0x0003 126 /* ************************************ */ 127 128 /* If we got here, just about done. 129 * Need to get back to protected mode 130 */ 131 movl %cr0, %eax 132 orl $PE, %eax 133 movl %eax, %cr0 134 135 /* Now that we are in protected mode 136 * jump to a 32 bit code segment. 137 */ 138 data32 ljmp $0x10, $RELOCATED(1f) 1391: 140 .code32 141 movw $0x18, %ax 142 mov %ax, %ds 143 mov %ax, %es 144 mov %ax, %fs 145 mov %ax, %gs 146 mov %ax, %ss 147 148 /* restore proper idt */ 149 lidt idtarg 150 151 /* and exit */ 152 mov __stack, %esp 153 popal 154 ret 155 156 .globl __run_interrupt 157__run_interrupt = RELOCATED(.) 158 159 /* paranoia -- does ecx get saved? not sure. This is 160 * the easiest safe thing to do. */ 161 pushal 162 /* save the stack */ 163 mov %esp, __stack 164 165 166 /* This configures CS properly for real mode. */ 167 ljmp $0x28, $RELOCATED(1f) 1681: 169 .code16 /* 16 bit code from here on... */ 170 171 // CONFIG_DEBUG 172 movb $0xec, %al 173 outb %al, $0x80 174 175 /* Load the segment registers w/ properly configured segment 176 * descriptors. They will retain these configurations (limits, 177 * writability, etc.) once protected mode is turned off. 178 */ 179 mov $0x30, %ax 180 mov %ax, %ds 181 mov %ax, %es 182 mov %ax, %fs 183 mov %ax, %gs 184 mov %ax, %ss 185 186 /* Turn off protected mode */ 187 movl %cr0, %eax 188 andl $~PE, %eax 189 movl %eax, %cr0 190 191 /* Now really going into real mode */ 192 data32 ljmp $0, $RELOCATED(1f) 1931: 194 195 /* put the stack at the end of page zero. 196 * that way we can easily share it between real and protected, 197 * since the 16-bit ESP at segment 0 will work for any case. 198 */ 199 /* setup a stack */ 200 mov $0x0, %ax 201 mov %ax, %ss 202 movl $0x1000, %eax 203 movl %eax, %esp 204 205 /* Load 16-bit intXX IDT */ 206 xor %ax, %ax 207 mov %ax, %ds 208 lidt __realmode_idt 209 210 /* Set all segments to 0x0000 */ 211 mov %ax, %ds 212 mov %ax, %es 213 mov %ax, %fs 214 mov %ax, %gs 215 216 /* Call VGA BIOS int10 function 0x4f14 to enable main console 217 * Epia-M does not always autosence the main console so forcing 218 * it on is good. 219 */ 220 221 /* Ask VGA option rom to enable main console */ 222 movw $0x4f14,%ax 223 movw $0x8003,%bx 224 movw $1, %cx 225 movw $0, %dx 226 movw $0, %di 227 int $0x10 228 229 /* Ok, the job is done, now go back to protected mode coreboot */ 230 movl %cr0, %eax 231 orl $PE, %eax 232 movl %eax, %cr0 233 234 /* Now that we are in protected mode jump to a 32-bit code segment. */ 235 data32 ljmp $0x10, $RELOCATED(1f) 2361: 237 .code32 238 movw $0x18, %ax 239 mov %ax, %ds 240 mov %ax, %es 241 mov %ax, %fs 242 mov %ax, %gs 243 mov %ax, %ss 244 245 /* restore coreboot's 32-bit IDT */ 246 lidt idtarg 247 248 /* Exit */ 249 mov __stack, %esp 250 popal 251 ret 252 253/* This is the 16-bit interrupt entry point called by the IDT stub code. 254 * Before this code code is called, %eax is pushed to the stack, and the 255 * interrupt number is loaded into %al 256 */ 257 .code16 258__interrupt_handler_16bit = RELOCATED(.) 259 push %ds 260 push %es 261 push %fs 262 push %gs 263 264 /* Clean up the interrupt number. We could have done this in the stub, 265 * but it would have cost 2 more bytes per stub entry. 266 */ 267 andl $0xff, %eax 268 pushl %eax /* ... and make it the first parameter */ 269 270 /* Switch to protected mode */ 271 movl %cr0, %eax 272 orl $PE, %eax 273 movl %eax, %cr0 274 275 /* ... and jump to a 32 bit code segment. */ 276 data32 ljmp $0x10, $RELOCATED(1f) 2771: 278 .code32 279 movw $0x18, %ax 280 mov %ax, %ds 281 mov %ax, %es 282 mov %ax, %fs 283 mov %ax, %gs 284 mov %ax, %ss 285 286 lidt idtarg 287 288 /* Call the C interrupt handler */ 289 movl $interrupt_handler, %eax 290 call *%eax 291 292 /* Now return to real mode ... */ 293 ljmp $0x28, $RELOCATED(1f) 2941: 295 .code16 296 /* Load the segment registers with properly configured segment 297 * descriptors. They will retain these configurations (limits, 298 * writability, etc.) once protected mode is turned off. 299 */ 300 mov $0x30, %ax 301 mov %ax, %ds 302 mov %ax, %es 303 mov %ax, %fs 304 mov %ax, %gs 305 mov %ax, %ss 306 307 /* Disable Protected Mode */ 308 movl %cr0, %eax 309 andl $~PE, %eax 310 movl %eax, %cr0 311 312 /* Now really going into real mode */ 313 ljmp $0, $RELOCATED(1f) 3141: 315 /* Restore real-mode stack segment */ 316 mov $0x0, %ax 317 mov %ax, %ss 318 319 /* Restore 16-bit IDT */ 320 xor %ax, %ax 321 mov %ax, %ds 322 lidt __realmode_idt 323 324 /* Set up our segment registers to segment 0x0000 */ 325 mov %ax, %es 326 mov %ax, %fs 327 mov %ax, %gs 328 mov $0x40, %ax 329 mov %ax, %ds 330 331 /* Restore all registers, including those 332 * manipulated by the C handler 333 */ 334 popl %eax 335 pop %gs 336 pop %fs 337 pop %es 338 pop %ds 339 popal 340 iret 341 342 .globl __realmode_code_size 343__realmode_code_size = (. - __realmode_code) 344 345 .code32 346

