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@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@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
46Permission to use, copy, modify, and distribute this software and
47its documentation for any purpose and without fee is hereby
48granted, provided that the above copyright notice appears in all
49copies and that both the copyright notice and this permission notice
50appear in supporting documentation, and that the name of Intel
51not be used in advertising or publicity pertaining to distribution
52of the software without specific, written prior permission.
53
54INTEL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE
55INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS,
56IN NO EVENT SHALL INTEL BE LIABLE FOR ANY SPECIAL, INDIRECT, OR
57CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
58LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT,
59NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
60WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
61*/
62
63#include <machine/asm.h>
64
65
66CR0_PE		=	0x1
67
68	.data
69	.globl _C_LABEL(ourseg)
70_C_LABEL(ourseg):
71	.long	0
72
73/**************************************************************************
74GLOBAL DESCRIPTOR TABLE
75**************************************************************************/
76#ifdef __ELF__
77	.align	16
78#else
79	.align	4
80#endif
81gdt:
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
92flatcodeseg = . - gdt
93	.word	0xffff, 0
94	.byte	0, 0x9f, 0xcf, 0
95
96	/* kernel data segment */
97	.globl flatdataseg
98flatdataseg = . - gdt
99	.word	0xffff, 0
100	.byte	0, 0x93, 0xcf, 0
101
102	/* boot code segment, base will be patched */
103bootcodeseg = . - gdt
104	.word	0xffff, 0
105	.byte	0, 0x9e, 0x40, 0
106
107	/* boot data segment, base will be patched */
108bootdataseg = . - 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 */
118bootrealseg = . - gdt
119	.word	0xffff, 0
120	.byte	0, 0x9e, 0x00, 0
121
122	/* limits (etc) for data segment in real mode */
123bootrealdata = . - gdt
124	.word	0xffff, 0
125	.byte	0, 0x92, 0x00, 0
126gdtlen = . - gdt
127
128#ifdef __ELF__
129	.align	16
130#else
131	.align	4
132#endif
133gdtarg:
134	.word	gdtlen-1		/* limit */
135	.long	0			/* addr, will be inserted */
136
137	.text
138ENTRY(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
1481:	.asciz	"must be in real mode\r\n"
1492:
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)
191ENTRY(_rtt)
192	call	_C_LABEL(prot_to_real)
193	.code16
194ENTRY(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 */
203ENTRY(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
221xprot:
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 */
240ENTRY(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
265x16:
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
275xreal:
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
3001:	movw	$2f, %si
301	call	message
302	movl	2/*bp*/ + 4/*eax*/(%bp), %eax		/*  return address */
303	call	dump_eax
304	jmp	exit16
3052:	.asciz  "prot_to_real can't return to "
306
307
308/**************************************************************************
309___MAIN - Dummy to keep GCC happy
310**************************************************************************/
311ENTRY(__main)
312	ret
313
314/*
315 * pbzero(dst, cnt)
316 *	where dst is a physical address and cnt is the length
317 */
318ENTRY(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 */
347ENTRY(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 */
378ENTRY(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
405ENTRY(vtophys)
406	.code32
407	movl	_C_LABEL(ourseg), %eax
408	shll	$4, %eax
409	addl	4(%esp), %eax
410	ret
411
412message:
413	.code16
414	pushal
415message_1:
416	cld
4171:	lodsb
418	testb	%al, %al
419	jz	2f
420	movb	$0xe, %ah
421	movw	$1, %bx
422	int	$0x10
423	jmp	1b
424
4252:	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
434eax_buf:
435	.long	0, 0, 0, 0
436	.text
437ENTRY(dump_eax)
438	.code16
439	pushal
440	movw	$eax_buf, %si
441	mov	%si, %di
442	movw	$8, %cx
4431:	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
497ENTRY(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
528noxms:		/* no XMS manager found */
529	mov	$0, %dx
530
531xdone:
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*/
555ENTRY(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 */
592ENTRY(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