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