start_dos.S revision 1.2 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