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