coreboot-v2/util/x86emu/x86_asm.S
<<
>>
Prefs
   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
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.