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