unstack - fix ipcvecs
[minix.git] / sys / arch / i386 / stand / lib / crt / dos / start_dos.S
blob38eb43ad9eec24ede2c04012d9a511c8a6af0c9b
1 /*      $NetBSD: start_dos.S,v 1.10 2010/12/20 01:12:44 jakllsch 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  */
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  */
41   Copyright 1988, 1989, 1990, 1991, 1992 
42    by Intel Corporation, Santa Clara, California.
44                 All Rights Reserved
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.
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.
63 #include <machine/asm.h>
66 CR0_PE          =       0x1
68         .data
69         .globl _C_LABEL(ourseg)
70 _C_LABEL(ourseg):
71         .long   0
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
85 #ifdef SUPPORT_LINUX    /* additional dummy */
86         .word   0, 0
87         .byte   0, 0x00, 0x00, 0
88 #endif
90         /* kernel code segment */
91         .globl flatcodeseg
92 flatcodeseg = . - gdt
93         .word   0xffff, 0
94         .byte   0, 0x9f, 0xcf, 0
96         /* kernel data segment */
97         .globl flatdataseg
98 flatdataseg = . - gdt
99         .word   0xffff, 0
100         .byte   0, 0x93, 0xcf, 0
102         /* boot code segment, base will be patched */
103 bootcodeseg = . - gdt
104         .word   0xffff, 0
105         .byte   0, 0x9e, 0x40, 0
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
117         /* 16 bit real mode, base will be patched */
118 bootrealseg = . - gdt
119         .word   0xffff, 0
120         .byte   0, 0x9e, 0x00, 0
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
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 */
137         .text
138 ENTRY(start)
139         .code16
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"
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
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
167         mov     %cs, %ax
168         shll    $4, %eax
169         shldl   $16, %eax, %ebx
170         FIXUP(bootcodeseg)
171         FIXUP(bootrealseg)
172         FIXUP(bootdataseg)
174         /* fix up GDT pointer */
175         addl    $gdt, %eax
176         movl    %eax, gdtarg+2
178         /* change to protected mode */
179         calll   _C_LABEL(real_to_prot)
180         .code32
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
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
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
209         # load the gdtr
210         lgdtl   %cs:gdtarg
212         # set the PE bit of CR0
213         movl    %cr0, %eax
214         orl     $CR0_PE, %eax
215         movl    %eax, %cr0 
217         # make intrasegment jump to flush the processor pipeline and
218         # reload CS register
219         ljmp    $bootcodeseg, $xprot
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
233         popl    %eax
234         ret
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.
249         movl    _C_LABEL(ourseg), %eax
250         movw    %ax, xreal-2
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
262         # Change to use16 mode.
263         ljmp    $bootrealseg, $x16
265 x16:
266         .code16
267         # clear the PE bit of CR0
268         movl    %cr0, %eax
269         andl    $~CR0_PE, %eax
270         movl    %eax, %cr0
272         # Here we have an 16 bits intersegment jump.
273         ljmp    $0, $xreal              /* segment patched above */
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
296         sti
297         popl    %eax
298         retl
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 "
308 /**************************************************************************
309 ___MAIN - Dummy to keep GCC happy
310 **************************************************************************/
311 ENTRY(__main)
312         ret
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
325         cld
327         # set %es to point at the flat segment
328         movl    $flatdataseg, %eax
329         mov     %ax, %es
331         movl    8(%ebp), %edi           # destination
332         movl    12(%ebp), %ecx          # count
333         xorl    %eax, %eax              # value
335         rep
336         stosb
338         popl    %edi
339         popl    %es
340         popl    %ebp
341         ret
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
355         cld
357         # set %es to point at the flat segment
358         movl    $flatdataseg, %eax
359         mov     %ax, %es
361         movl    8(%ebp), %esi           # source
362         movl    12(%ebp), %edi          # destination
363         movl    16(%ebp), %ecx          # count
365         rep
366         movsb
368         popl    %edi
369         popl    %esi
370         popl    %es
371         popl    %ebp
372         ret
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
386         cld
388         # set %ds to point at the flat segment
389         movl    $flatdataseg, %eax
390         mov     %ax, %ds
392         movl    8(%ebp), %esi           # source
393         movl    12(%ebp), %edi          # destination
394         movl    16(%ebp), %ecx          # count
396         rep
397         movsb
399         popl    %edi
400         popl    %esi
401         popl    %ds
402         popl    %ebp
403         ret
405 ENTRY(vtophys)
406         .code32
407         movl    _C_LABEL(ourseg), %eax
408         shll    $4, %eax
409         addl    4(%esp), %eax
410         ret
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
425 2:      movb    $0x86, %ah
426         mov     $16, %cx
427         int     $0x15                   /* delay about a second */
428         popal
429         ret
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
460         .globl  _C_LABEL(trace_word)
461 _C_LABEL(trace_word):
462         .code32
463         movl    4(%esp), %edx
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
473         .globl  _C_LABEL(trace_str)
474 _C_LABEL(trace_str):
475         .code32
476         pushl   %esi
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
488 #ifdef XMS
490 /* pointer to XMS driver, 0 if no XMS used */
492         .data
493 _C_LABEL(xmsdrv):
494         .long   0
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
507         call    _C_LABEL(prot_to_real)  # enter real mode
508         .code16
510         movw    $0x4300, %ax
511         int     $0x2f                   /* check if XMS installed */
512         cmpb    $0x80, %al
513         jnz     noxms
515         movw    $0x4310, %ax
516         int     $0x2f                   /* get driver address */
518         movw    %bx, _C_LABEL(xmsdrv)   /* save es:bx to _xmsdrv */
519         movw    %es, _C_LABEL(xmsdrv) + 2
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
528 noxms:          /* no XMS manager found */
529         mov     $0, %dx
531 xdone:
532         calll   _C_LABEL(real_to_prot) # back to protected mode
533         .code32
535         xorl    %eax, %eax
536         movw    %dx, %ax
538         popl    %edi
539         popl    %esi
540         popl    %es
541         popl    %edx
542         popl    %ebx
543         popl    %ebp
544         ret
547         Allocate a block of XMS memory with the requested size
548                 void *xmsalloc(long int kBytes);
550         Depends on _xmsdrv being set by getextmem() before first call
551         to this function.
553         Return value: a physical address.
555 ENTRY(xmsalloc)
556         .code32
557         pushl   %ebp
558         movl    %esp, %ebp
559         pushl   %ebx
560         pushl   %edx
561         pushl   %esi
562         pushl   %edi
564         movl    0x8(%ebp), %edx # Kbytes needed
566         call    _C_LABEL(prot_to_real)  # enter real mode
567         .code16
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
574         calll   _C_LABEL(real_to_prot) # back to protected mode
575         .code32
577         movl    %edx, %eax
578         shl     $16, %eax
579         movw    %bx, %ax        # result in %eax
581         popl    %edi
582         popl    %esi
583         popl    %edx
584         popl    %ebx
585         popl    %ebp
586         ret
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
600         cld
602         # set %es to point at the flat segment
603         movl    $flatdataseg, %eax
604         mov     %ax, %es
606         movl    8(%ebp), %esi           # source
607         movl    12(%ebp), %edi          # destination
608         movl    16(%ebp), %ecx          # count
610         es
611         rep
612         movsb
614         popl    %edi
615         popl    %esi
616         popl    %es
617         popl    %ebp
618         ret
620 #endif