[BACK]Return to realprot.S CVS log [TXT][DIR] Up to [cvs.NetBSD.org] / src / sys / arch / i386 / stand / lib

Annotation of src/sys/arch/i386/stand/lib/realprot.S, Revision 1.9.4.1

1.9.4.1 ! rmind       1: /*     $NetBSD$        */
1.1       dsl         2:
                      3: /*-
                      4:  * Copyright (c) 2003 The NetBSD Foundation, Inc.
                      5:  * All rights reserved.
                      6:  *
                      7:  * This code is derived from software contributed to The NetBSD Foundation
                      8:  * by David Laight.
                      9:  *
                     10:  * Redistribution and use in source and binary forms, with or without
                     11:  * modification, are permitted provided that the following conditions
                     12:  * are met:
                     13:  * 1. Redistributions of source code must retain the above copyright
                     14:  *    notice, this list of conditions and the following disclaimer.
                     15:  * 2. Redistributions in binary form must reproduce the above copyright
                     16:  *    notice, this list of conditions and the following disclaimer in the
                     17:  *    documentation and/or other materials provided with the distribution.
                     18:  *
                     19:  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
                     20:  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
                     21:  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
                     22:  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
                     23:  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
                     24:  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
                     25:  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
                     26:  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
                     27:  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
                     28:  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
                     29:  * POSSIBILITY OF SUCH DAMAGE.
                     30:  */
                     31:
                     32: /*
                     33:  * Loosely based on code from stand/lib/libcrt/bootsect/start_bootsect.S
                     34:  */
                     35:
                     36: #include <machine/asm.h>
                     37:
                     38: #define        CR0_PE          1
                     39:
                     40:        .text
                     41:        .align  16
                     42: gdt:
                     43:        .word   0, 0
                     44:        .byte   0, 0x00, 0x00, 0
                     45:
                     46:        /* kernel code segment */
                     47:        .globl flatcodeseg
                     48: flatcodeseg = . - gdt
                     49:        .word   0xffff, 0
                     50:        .byte   0, 0x9f, 0xcf, 0
                     51:
                     52:        /* kernel data segment */
                     53:        .globl flatdataseg
                     54: flatdataseg = . - gdt
                     55:        .word   0xffff, 0
                     56:        .byte   0, 0x93, 0xcf, 0
                     57:
                     58:        /* boot code segment, base will be patched */
                     59: bootcodeseg = . - gdt
                     60:        .word   0xffff, 0
                     61:        .byte   0, 0x9e, 0x4f, 0
                     62:
                     63:        /* boot data segment, base will be patched */
                     64: bootdataseg = . - gdt
                     65:        .word   0xffff, 0
1.8       jmcneill   66:        .byte   0, 0x92, 0xcf, 0
1.1       dsl        67:
                     68:        /* 16 bit real mode, base will be patched */
                     69: bootrealseg = . - gdt
                     70:        .word   0xffff, 0
                     71:        .byte   0, 0x9e, 0x00, 0
                     72:
                     73:        /* limits (etc) for data segment in real mode */
                     74: bootrealdata = . - gdt
                     75:        .word   0xffff, 0
                     76:        .byte   0, 0x92, 0x00, 0
                     77: gdtlen = . - gdt
                     78:
                     79:        .align  16
                     80: gdtarg:
                     81:        .word   gdtlen-1                /* limit */
                     82:        .long   0                       /* physical addr, will be inserted */
                     83:
                     84: toreal:        .word   xreal                   /* off:seg address for indirect jump */
                     85: ourseg:        .word   0                       /* real mode code and data segment */
                     86:
                     87: stkseg:        .word   0                       /* real mode stack segment */
                     88: stkdif:        .long   0                       /* diff. between real and prot sp */
                     89:
                     90:        .global gdt_fixup
                     91: gdt_fixup:
                     92:        .code16
1.9.4.1 ! rmind      93:        pushl   %eax
        !            94:        pushl   %edx
1.1       dsl        95:
                     96:        xorl    %eax, %eax
                     97:        mov     %cs, %ax
                     98:        mov     %ax, ourseg
                     99:        /* sort out stuff for %ss != %ds */
1.9.4.1 ! rmind     100:        xorl    %edx, %edx
1.1       dsl       101:        movw    %ss, %dx
                    102:        movw    %dx, stkseg
1.9.4.1 ! rmind     103:        subl    %eax, %edx
        !           104:        shll    $4, %edx
1.1       dsl       105:        movl    %edx, stkdif
                    106:
                    107:        /* fix up GDT entries for bootstrap */
                    108:        mov     %ax, %dx
                    109:        shll    $4, %eax
                    110:        shr     $12, %dx
                    111:
                    112: #define FIXUP(gdt_index) \
                    113:        movw    %ax, gdt+gdt_index+2; \
                    114:        movb    %dl, gdt+gdt_index+4
                    115:
                    116:        FIXUP(bootcodeseg)
                    117:        FIXUP(bootrealseg)
                    118:        FIXUP(bootdataseg)
                    119:
                    120:        /* fix up GDT pointer */
                    121:        addl    $gdt, %eax
                    122:        movl    %eax, gdtarg+2
                    123:
1.9.4.1 ! rmind     124:        popl    %edx
        !           125:        popl    %eax
1.1       dsl       126:        ret
                    127:
                    128: /*
                    129:  * real_to_prot()
                    130:  *
1.3       wiz       131:  * Switch CPU to 32bit protected mode to execute C.
1.1       dsl       132:  *
                    133:  * NB: Call with the 32bit calll instruction so that a 32 bit
                    134:  *     return address is pushed.
                    135:  *
                    136:  * All registers are preserved, %ss:%esp will point to the same
                    137:  * place as %ss:%sp did, although the actual value of %esp might
                    138:  * be changed.
                    139:  *
                    140:  * Interrupts are disabled while we are in 32bit mode to save us
                    141:  * having to setup a different IDT.  This code is only used during
                    142:  * the boot process and it doesn't use any interrupts.
                    143:  */
                    144: ENTRY(real_to_prot)
                    145:        .code16
                    146:        pushl   %eax
                    147:        cli
                    148:
                    149:        lgdt    %cs:gdtarg              /* Global descriptor table */
                    150:
                    151:        movl    %cr0, %eax
                    152:        or      $CR0_PE, %ax
1.2       dsl       153:        movl    %eax, %cr0              /* Enter 'protected mode' */
1.1       dsl       154:
                    155:        ljmp    $bootcodeseg, $1f       /* Jump into a 32bit segment */
                    156: 1:
                    157:
                    158:        .code32
                    159:        /*  Set all the segment registers to map the same area as the code */
                    160:        mov     $bootdataseg, %eax
                    161:        mov     %ax, %ds
                    162:        mov     %ax, %es
                    163:        mov     %ax, %ss
                    164:        addl    stkdif, %esp            /* Allow for real %ss != %ds */
                    165:
                    166:        popl    %eax
                    167:        ret
                    168:
                    169: /*
                    170:  * prot_to_real()
                    171:  *
1.3       wiz       172:  * Switch CPU back to 16bit real mode in order to call system bios functions.
1.1       dsl       173:  *
                    174:  * All registers are preserved, except that %sp may be changed so that
                    175:  * %ss:%sp points to the same memory.
                    176:  * Note that %ebp is preserved and will not reference the correct part
                    177:  * of the stack.
                    178:  *
                    179:  * Interrupts are enabled while in real mode.
                    180:  *
                    181:  * Based on the descripton in section 14.5 of the 80386 Programmer's
                    182:  * reference book.
                    183:  */
1.4       gavan     184: /*
                    185:  * EPIA_HACK
                    186:  *
1.9       dsl       187:  * VIA C3 processors (Eden, Samuel 2) don't seem to correctly switch back to
                    188:  * executing 16 bit code after the switch to real mode and subsequent jump.
1.4       gavan     189:  *
                    190:  * It is speculated that the CPU is prefetching and decoding branch
                    191:  * targets and not invalidating this buffer on the long jump.
1.9       dsl       192:  * Further investication indicates that the caching of return addresses
                    193:  * is most likely the problem.
1.4       gavan     194:  *
1.9       dsl       195:  * Previous versions just used some extra call/ret and a few NOPs, these
                    196:  * only helped a bit, but booting compressed kernels would still fail.
1.4       gavan     197:  *
1.9       dsl       198:  * Trashing the return address stack (by doing 'call' without matched 'ret')
                    199:  * Seems to fix things completely. 1 iteration isn't enough, 16 is plenty.
1.4       gavan     200:  */
1.1       dsl       201: ENTRY(prot_to_real)
1.9       dsl       202:        .code32
                    203:        pushl   %eax
1.4       gavan     204: #ifdef EPIA_HACK
1.9       dsl       205:        push    %ecx
                    206:        push    $0x10
                    207:        pop     %ecx
                    208: 1:     call    trash_return_cache
                    209:        loop    1b
                    210:        pop     %ecx
1.4       gavan     211: #endif
1.1       dsl       212:
                    213:        /*
                    214:         * Load the segment registers while still in protected mode.
                    215:         * Otherwise the control bits don't get changed.
                    216:         * The correct base addresses are loaded later.
                    217:         */
1.5       junyoung  218:        movw    $bootrealdata, %ax
1.1       dsl       219:        movw    %ax, %ds
                    220:        movw    %ax, %es
                    221:        movw    %ax, %ss
                    222:
                    223:        /*
                    224:         * Load %cs with a segment that has the correct attributes for
                    225:         * 16bit operation.
                    226:         */
                    227:        ljmp    $bootrealseg, $1f
                    228: 1:
                    229:
                    230:        .code16
                    231:        movl    %cr0, %eax
                    232:        and     $~CR0_PE, %eax
                    233:        movl    %eax, %cr0              /* Disable potected mode */
                    234:
                    235:        /* Jump far indirect to load real mode %cs */
                    236:        ljmp    *%cs:toreal
                    237: xreal:
                    238:        /*
1.3       wiz       239:         * CPU is now in real mode, load the other segment registers
1.1       dsl       240:         * with their correct base addresses.
                    241:         */
                    242:        mov     %cs, %ax
                    243:        mov     %ax, %ds
                    244:        mov     %ax, %es
                    245:        /*
                    246:         * If stack was above 64k, 16bit %ss needs to be different from
                    247:         * 32bit %ss (and the other segment registers).
                    248:         */
                    249:        mov     stkseg, %ax
                    250:        mov     %ax, %ss
                    251:        subl    stkdif, %esp
                    252:
                    253:        /* Check we are returning to an address below 64k */
                    254:        push    %bp
                    255:        movw    %sp, %bp
                    256:        movw    2/*bp*/ + 4/*eax*/ + 2(%bp), %ax        /* high bits ret addr */
                    257:        test    %ax, %ax
                    258:        jne     1f
                    259:        pop     %bp
                    260:
                    261:        sti
                    262:        popl    %eax
                    263:        retl
                    264:
                    265: 1:     movw    $3f, %si
                    266:        call    message
                    267:        movl    2/*bp*/ + 4/*eax*/(%bp), %eax           /*  return address */
                    268:        call    dump_eax
                    269:        int     $0x18
                    270: 2:     sti
                    271:        hlt
                    272:        jmp     2b
                    273: 3:     .asciz  "prot_to_real can't return to "
                    274:
                    275:        .global dump_eax_buff
                    276: dump_eax_buff:
                    277:        . = . + 16
                    278:
1.4       gavan     279: #ifdef EPIA_HACK
1.9       dsl       280: trash_return_cache:
                    281:        .code32
                    282:        pop     %eax
                    283:        jmp     *%eax
1.4       gavan     284: #endif
                    285:
1.1       dsl       286: /* vtophys(void *)
                    287:  * convert boot time 'linear' address to a physical one
                    288:  */
                    289:
                    290: ENTRY(vtophys)
                    291:        .code32
                    292:        xorl    %eax, %eax
                    293:        movw    ourseg, %ax
                    294:        shll    $4, %eax
                    295:        addl    4(%esp), %eax
                    296:        ret

CVSweb <webmaster@jp.NetBSD.org>