Home | History | Annotate | Line # | Download | only in dosboot
start_dos.S revision 1.1
      1 /*	$NetBSD: start_dos.S,v 1.1 2024/06/29 13:45:14 rin Exp $	*/
      2 
      3 /*
      4  * startup for DOS .COM programs
      5  * with input from:
      6  * netbsd:sys/arch/i386/boot/start.S
      7  * Tor Egge's patches for NetBSD boot (pr port-i386/1002)
      8  * freebsd:sys/i386/boot/netboot/start2.S
      9  * XMS support by Martin Husemann
     10  */
     11 
     12 /*
     13  * Ported to boot 386BSD by Julian Elischer (julian (at) tfs.com) Sept 1992
     14  *
     15  * Mach Operating System
     16  * Copyright (c) 1992, 1991 Carnegie Mellon University
     17  * All Rights Reserved.
     18  *
     19  * Permission to use, copy, modify and distribute this software and its
     20  * documentation is hereby granted, provided that both the copyright
     21  * notice and this permission notice appear in all copies of the
     22  * software, derivative works or modified versions, and any portions
     23  * thereof, and that both notices appear in supporting documentation.
     24  *
     25  * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
     26  * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
     27  * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
     28  *
     29  * Carnegie Mellon requests users of this software to return to
     30  *
     31  *  Software Distribution Coordinator  or  Software.Distribution (at) CS.CMU.EDU
     32  *  School of Computer Science
     33  *  Carnegie Mellon University
     34  *  Pittsburgh PA 15213-3890
     35  *
     36  * any improvements or extensions that they make and grant Carnegie Mellon
     37  * the rights to redistribute these changes.
     38  */
     39 
     40 /*
     41   Copyright 1988, 1989, 1990, 1991, 1992
     42    by Intel Corporation, Santa Clara, California.
     43 
     44                 All Rights Reserved
     45 
     46 Permission to use, copy, modify, and distribute this software and
     47 its documentation for any purpose and without fee is hereby
     48 granted, provided that the above copyright notice appears in all
     49 copies and that both the copyright notice and this permission notice
     50 appear in supporting documentation, and that the name of Intel
     51 not be used in advertising or publicity pertaining to distribution
     52 of the software without specific, written prior permission.
     53 
     54 INTEL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE
     55 INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS,
     56 IN NO EVENT SHALL INTEL BE LIABLE FOR ANY SPECIAL, INDIRECT, OR
     57 CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
     58 LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT,
     59 NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
     60 WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
     61 */
     62 
     63 #include <machine/asm.h>
     64 
     65 
     66 CR0_PE		=	0x1
     67 
     68 	.data
     69 	.globl _C_LABEL(ourseg)
     70 _C_LABEL(ourseg):
     71 	.long	0
     72 
     73 /**************************************************************************
     74 GLOBAL DESCRIPTOR TABLE
     75 **************************************************************************/
     76 #ifdef __ELF__
     77 	.align	16
     78 #else
     79 	.align	4
     80 #endif
     81 gdt:
     82 	.word	0, 0
     83 	.byte	0, 0x00, 0x00, 0
     84 
     85 #ifdef SUPPORT_LINUX	/* additional dummy */
     86 	.word	0, 0
     87 	.byte	0, 0x00, 0x00, 0
     88 #endif
     89 
     90 	/* kernel code segment */
     91 	.globl flatcodeseg
     92 flatcodeseg = . - gdt
     93 	.word	0xffff, 0
     94 	.byte	0, 0x9f, 0xcf, 0
     95 
     96 	/* kernel data segment */
     97 	.globl flatdataseg
     98 flatdataseg = . - gdt
     99 	.word	0xffff, 0
    100 	.byte	0, 0x93, 0xcf, 0
    101 
    102 	/* boot code segment, base will be patched */
    103 bootcodeseg = . - gdt
    104 	.word	0xffff, 0
    105 	.byte	0, 0x9e, 0x40, 0
    106 
    107 	/* boot data segment, base will be patched */
    108 bootdataseg = . - gdt
    109 #ifdef HEAP_BELOW_64K
    110 	.word	0xffff, 0
    111 	.byte	0, 0x92, 0x00, 0
    112 #else
    113 	.word	0xffff, 0
    114 	.byte	0, 0x92, 0x4f, 0
    115 #endif
    116 
    117 	/* 16 bit real mode, base will be patched */
    118 bootrealseg = . - gdt
    119 	.word	0xffff, 0
    120 	.byte	0, 0x9e, 0x00, 0
    121 
    122 	/* limits (etc) for data segment in real mode */
    123 bootrealdata = . - gdt
    124 	.word	0xffff, 0
    125 	.byte	0, 0x92, 0x00, 0
    126 gdtlen = . - gdt
    127 
    128 #ifdef __ELF__
    129 	.align	16
    130 #else
    131 	.align	4
    132 #endif
    133 gdtarg:
    134 	.word	gdtlen-1		/* limit */
    135 	.long	0			/* addr, will be inserted */
    136 
    137 	.text
    138 ENTRY(start)
    139 	.code16
    140 
    141 	# Check we are in real mode
    142 	movl	%cr0, %eax
    143 	testl	$CR0_PE, %eax
    144 	jz	2f
    145 	mov	$1f, %si
    146 	call	message
    147 	ret
    148 1:	.asciz	"must be in real mode\r\n"
    149 2:
    150 
    151 	xorl	%eax, %eax
    152 	mov	%cs, %ax
    153 	mov	%ax, %ds
    154 	mov	%ax, %es
    155 	movl	%eax, _C_LABEL(ourseg)
    156 #ifdef STACK_START
    157 	add	$STACK_START / 16, %ax
    158 	mov	%ax, %ss
    159 	mov	$0xfffc, %sp
    160 #endif
    161 
    162 	/* fix up GDT entries for bootstrap */
    163 #define FIXUP(gdt_index) \
    164 	movw	%ax, gdt+gdt_index+2;	\
    165 	movb	%bl, gdt+gdt_index+4
    166 
    167 	mov	%cs, %ax
    168 	shll	$4, %eax
    169 	shldl	$16, %eax, %ebx
    170 	FIXUP(bootcodeseg)
    171 	FIXUP(bootrealseg)
    172 	FIXUP(bootdataseg)
    173 
    174 	/* fix up GDT pointer */
    175 	addl	$gdt, %eax
    176 	movl	%eax, gdtarg+2
    177 
    178 	/* change to protected mode */
    179 	calll	_C_LABEL(real_to_prot)
    180 	.code32
    181 
    182 	/* clear the bss */
    183 	movl	$_C_LABEL(edata), %edi
    184 	movl	$_C_LABEL(end), %ecx
    185 	subl	%edi, %ecx
    186 	xorb	%al, %al
    187 	rep
    188 	stosb
    189 
    190 	call	_C_LABEL(doscommain)
    191 ENTRY(_rtt)
    192 	call	_C_LABEL(prot_to_real)
    193 	.code16
    194 ENTRY(exit16)
    195 	sti
    196 	movb	$0x4c, %ah		/* return */
    197 	int	$0x21
    198 
    199 /*
    200  * real_to_prot()
    201  * 	transfer from real mode to protected mode.
    202  */
    203 ENTRY(real_to_prot)
    204 	.code16
    205 	pushl	%eax
    206 	# guarantee that interrupt is disabled when in prot mode
    207 	cli
    208 
    209 	# load the gdtr
    210 	lgdtl	%cs:gdtarg
    211 
    212 	# set the PE bit of CR0
    213 	movl	%cr0, %eax
    214 	orl	$CR0_PE, %eax
    215 	movl	%eax, %cr0
    216 
    217 	# make intrasegment jump to flush the processor pipeline and
    218 	# reload CS register
    219 	ljmp	$bootcodeseg, $xprot
    220 
    221 xprot:
    222 	.code32
    223 	# we are in USE32 mode now
    224 	# set up the protected mode segment registers : DS, SS, ES
    225 	movl	$bootdataseg, %eax
    226 	mov	%ax, %ds
    227 	mov	%ax, %es
    228 	mov	%ax, %ss
    229 #ifdef STACK_START
    230 	addl	$STACK_START, %esp
    231 #endif
    232 
    233 	popl	%eax
    234 	ret
    235 
    236 /*
    237  * prot_to_real()
    238  * 	transfer from protected mode to real mode
    239  */
    240 ENTRY(prot_to_real)
    241 	.code32
    242 	pushl	%eax
    243 	# set up a dummy stack frame for the second seg change.
    244 	# Adjust the intersegment jump instruction following
    245 	# the clearing of protected mode bit.
    246 	# This is self-modifying code, but we need a writable
    247 	# code segment, and an intersegment return does not give us that.
    248 
    249 	movl	_C_LABEL(ourseg), %eax
    250 	movw	%ax, xreal-2
    251 
    252 	/*
    253 	 * Load the segment registers while still in protected mode.
    254 	 * Otherwise the control bits don't get changed.
    255 	 * The correct values are loaded later.
    256 	 */
    257 	movw	$bootrealdata, %ax
    258 	movw	%ax, %ds
    259 	movw	%ax, %es
    260 	movw	%ax, %ss
    261 
    262 	# Change to use16 mode.
    263 	ljmp	$bootrealseg, $x16
    264 
    265 x16:
    266 	.code16
    267 	# clear the PE bit of CR0
    268 	movl	%cr0, %eax
    269 	andl 	$~CR0_PE, %eax
    270 	movl	%eax, %cr0
    271 
    272 	# Here we have an 16 bits intersegment jump.
    273 	ljmp	$0, $xreal		/* segment patched above */
    274 
    275 xreal:
    276 	# we are in real mode now
    277 	# set up the real mode segment registers : DS, SS, ES
    278 	mov	%cs, %ax
    279 	mov	%ax, %ds
    280 	mov	%ax, %es
    281 #ifdef STACK_START
    282 	add	$STACK_START / 16, %ax
    283 	mov	%ax, %ss
    284 	subl	$STACK_START, %esp
    285 #else
    286 	mov	%ax, %ss
    287 #endif
    288 	push	%bp
    289 	movw	%sp, %bp
    290 	/* check we are returning to an address below 64k */
    291 	movw	2/*bp*/ + 4/*eax*/ + 2(%bp), %ax	/* high bits ret addr */
    292 	test	%ax, %ax
    293 	jne	1f
    294 	pop	%bp
    295 
    296 	sti
    297 	popl	%eax
    298 	retl
    299 
    300 1:	movw	$2f, %si
    301 	call	message
    302 	movl	2/*bp*/ + 4/*eax*/(%bp), %eax		/*  return address */
    303 	call	dump_eax
    304 	jmp	exit16
    305 2:	.asciz  "prot_to_real can't return to "
    306 
    307 
    308 /**************************************************************************
    309 ___MAIN - Dummy to keep GCC happy
    310 **************************************************************************/
    311 ENTRY(__main)
    312 	ret
    313 
    314 /*
    315  * pbzero(dst, cnt)
    316  *	where dst is a physical address and cnt is the length
    317  */
    318 ENTRY(pbzero)
    319 	.code32
    320 	pushl	%ebp
    321 	movl	%esp, %ebp
    322 	pushl	%es
    323 	pushl	%edi
    324 
    325 	cld
    326 
    327 	# set %es to point at the flat segment
    328 	movl	$flatdataseg, %eax
    329 	mov	%ax, %es
    330 
    331 	movl	8(%ebp), %edi		# destination
    332 	movl	12(%ebp), %ecx		# count
    333 	xorl	%eax, %eax		# value
    334 
    335 	rep
    336 	stosb
    337 
    338 	popl	%edi
    339 	popl	%es
    340 	popl	%ebp
    341 	ret
    342 
    343 /*
    344  * vpbcopy(src, dst, cnt)
    345  *	where src is a virtual address and dst is a physical address
    346  */
    347 ENTRY(vpbcopy)
    348 	.code32
    349 	pushl	%ebp
    350 	movl	%esp, %ebp
    351 	pushl	%es
    352 	pushl	%esi
    353 	pushl	%edi
    354 
    355 	cld
    356 
    357 	# set %es to point at the flat segment
    358 	movl	$flatdataseg, %eax
    359 	mov	%ax, %es
    360 
    361 	movl	8(%ebp), %esi		# source
    362 	movl	12(%ebp), %edi		# destination
    363 	movl	16(%ebp), %ecx		# count
    364 
    365 	rep
    366 	movsb
    367 
    368 	popl	%edi
    369 	popl	%esi
    370 	popl	%es
    371 	popl	%ebp
    372 	ret
    373 
    374 /*
    375  * pvbcopy(src, dst, cnt)
    376  *	where src is a physical address and dst is a virtual address
    377  */
    378 ENTRY(pvbcopy)
    379 	.code32
    380 	pushl	%ebp
    381 	movl	%esp, %ebp
    382 	pushl	%ds
    383 	pushl	%esi
    384 	pushl	%edi
    385 
    386 	cld
    387 
    388 	# set %ds to point at the flat segment
    389 	movl	$flatdataseg, %eax
    390 	mov	%ax, %ds
    391 
    392 	movl	8(%ebp), %esi		# source
    393 	movl	12(%ebp), %edi		# destination
    394 	movl	16(%ebp), %ecx		# count
    395 
    396 	rep
    397 	movsb
    398 
    399 	popl	%edi
    400 	popl	%esi
    401 	popl	%ds
    402 	popl	%ebp
    403 	ret
    404 
    405 ENTRY(vtophys)
    406 	.code32
    407 	movl	_C_LABEL(ourseg), %eax
    408 	shll	$4, %eax
    409 	addl	4(%esp), %eax
    410 	ret
    411 
    412 message:
    413 	.code16
    414 	pushal
    415 message_1:
    416 	cld
    417 1:	lodsb
    418 	testb	%al, %al
    419 	jz	2f
    420 	movb	$0xe, %ah
    421 	movw	$1, %bx
    422 	int	$0x10
    423 	jmp	1b
    424 
    425 2:	movb	$0x86, %ah
    426 	mov	$16, %cx
    427 	int	$0x15			/* delay about a second */
    428 	popal
    429 	ret
    430 
    431 /* These are useful for debugging
    432  */
    433 	.data
    434 eax_buf:
    435 	.long	0, 0, 0, 0
    436 	.text
    437 ENTRY(dump_eax)
    438 	.code16
    439 	pushal
    440 	movw	$eax_buf, %si
    441 	mov	%si, %di
    442 	movw	$8, %cx
    443 1:	roll	$4, %eax
    444 	mov	%ax, %bx
    445 	andb	$0x0f, %al
    446 	addb	$0x30, %al			/* 30..3f - clear AF */
    447 #if 1 /* 5 bytes to generate real hex... */
    448 	daa					/* 30..39, 40..45 */
    449 	addb	$0xc0, %al			/* f0..f9, 00..05 */
    450 	adcb	$0x40, %al			/* 30..39, 41..45 */
    451 #endif
    452 	movb	%al, (%di)			/* %es != %ds, so can't ... */
    453 	inc	%di				/* ... use stosb */
    454 	mov	%bx, %ax
    455 	loop	1b
    456 	movw	$0x20, %ax			/* space + null */
    457 	movw	%ax, (%di)
    458 	jmp	message_1
    459 
    460 	.globl	_C_LABEL(trace_word)
    461 _C_LABEL(trace_word):
    462 	.code32
    463 	movl	4(%esp), %edx
    464 
    465 	call	_C_LABEL(prot_to_real)
    466 	.code16
    467 	movl	%edx, %eax
    468 	call	dump_eax
    469 	calll	_C_LABEL(real_to_prot)
    470 	.code32
    471 	ret
    472 
    473 	.globl	_C_LABEL(trace_str)
    474 _C_LABEL(trace_str):
    475 	.code32
    476 	pushl	%esi
    477 
    478 	call	_C_LABEL(prot_to_real)
    479 	.code16
    480 	mov	%sp, %si
    481 	mov	8(%si), %si
    482 	call	message
    483 	calll	_C_LABEL(real_to_prot)
    484 	.code32
    485 	popl	%esi
    486 	ret
    487 
    488 #ifdef XMS
    489 
    490 /* pointer to XMS driver, 0 if no XMS used */
    491 
    492 	.data
    493 _C_LABEL(xmsdrv):
    494 	.long	0
    495 
    496 	.text
    497 ENTRY(checkxms)
    498 	.code32
    499 	pushl	%ebp
    500 	movl	%esp, %ebp
    501 	pushl	%ebx
    502 	pushl	%edx
    503 	pushl	%es
    504 	pushl	%esi
    505 	pushl	%edi
    506 
    507 	call	_C_LABEL(prot_to_real)	# enter real mode
    508 	.code16
    509 
    510 	movw	$0x4300, %ax
    511 	int	$0x2f			/* check if XMS installed */
    512 	cmpb	$0x80, %al
    513 	jnz	noxms
    514 
    515 	movw	$0x4310, %ax
    516 	int	$0x2f			/* get driver address */
    517 
    518 	movw	%bx, _C_LABEL(xmsdrv)	/* save es:bx to _xmsdrv */
    519 	movw	%es, _C_LABEL(xmsdrv) + 2
    520 
    521 	movb	$0x08, %ah		/* XMS: query free extended memory */
    522 #if 0
    523 	movb	$0x00, %bl
    524 #endif
    525 	lcall	*_C_LABEL(xmsdrv)
    526 	jmp	xdone
    527 
    528 noxms:		/* no XMS manager found */
    529 	mov	$0, %dx
    530 
    531 xdone:
    532 	calll	_C_LABEL(real_to_prot) # back to protected mode
    533 	.code32
    534 
    535 	xorl	%eax, %eax
    536 	movw	%dx, %ax
    537 
    538 	popl	%edi
    539 	popl	%esi
    540 	popl	%es
    541 	popl	%edx
    542 	popl	%ebx
    543 	popl	%ebp
    544 	ret
    545 
    546 /*
    547 	Allocate a block of XMS memory with the requested size
    548 		void *xmsalloc(long int kBytes);
    549 
    550 	Depends on _xmsdrv being set by getextmem() before first call
    551 	to this function.
    552 
    553 	Return value: a physical address.
    554 */
    555 ENTRY(xmsalloc)
    556 	.code32
    557 	pushl	%ebp
    558 	movl	%esp, %ebp
    559 	pushl	%ebx
    560 	pushl	%edx
    561 	pushl	%esi
    562 	pushl	%edi
    563 
    564 	movl	0x8(%ebp), %edx # Kbytes needed
    565 
    566 	call	_C_LABEL(prot_to_real)	# enter real mode
    567 	.code16
    568 
    569 	movb	$0x09, %ah		# XMS allocate block
    570 	lcall	*_C_LABEL(xmsdrv)	# result: handle in %dx
    571 	movb	$0x0c, %ah		# XMS lock block
    572 	lcall	*_C_LABEL(xmsdrv)	# result: 32 bit physical addr in DX:BX
    573 
    574 	calll	_C_LABEL(real_to_prot) # back to protected mode
    575 	.code32
    576 
    577 	movl	%edx, %eax
    578 	shl	$16, %eax
    579 	movw	%bx, %ax	# result in %eax
    580 
    581 	popl	%edi
    582 	popl	%esi
    583 	popl	%edx
    584 	popl	%ebx
    585 	popl	%ebp
    586 	ret
    587 
    588 /*
    589  * ppbcopy(src, dst, cnt)
    590  *	where src and dst are physical addresses
    591  */
    592 ENTRY(ppbcopy)
    593 	.code32
    594 	pushl	%ebp
    595 	movl	%esp, %ebp
    596 	pushl	%es
    597 	pushl	%esi
    598 	pushl	%edi
    599 
    600 	cld
    601 
    602 	# set %es to point at the flat segment
    603 	movl	$flatdataseg, %eax
    604 	mov	%ax, %es
    605 
    606 	movl	8(%ebp), %esi		# source
    607 	movl	12(%ebp), %edi		# destination
    608 	movl	16(%ebp), %ecx		# count
    609 
    610 	es
    611 	rep
    612 	movsb
    613 
    614 	popl	%edi
    615 	popl	%esi
    616 	popl	%es
    617 	popl	%ebp
    618 	ret
    619 
    620 #endif
    621