summaryrefslogtreecommitdiff
path: root/i386/dos/i16/i16_crt0.S
diff options
context:
space:
mode:
Diffstat (limited to 'i386/dos/i16/i16_crt0.S')
-rw-r--r--i386/dos/i16/i16_crt0.S274
1 files changed, 274 insertions, 0 deletions
diff --git a/i386/dos/i16/i16_crt0.S b/i386/dos/i16/i16_crt0.S
new file mode 100644
index 0000000..f21c6a6
--- /dev/null
+++ b/i386/dos/i16/i16_crt0.S
@@ -0,0 +1,274 @@
+/*
+ * Copyright (c) 1995-1994 The University of Utah and
+ * the Computer Systems Laboratory at the University of Utah (CSL).
+ * All rights reserved.
+ *
+ * Permission to use, copy, modify and distribute this software is hereby
+ * granted provided that (1) source code retains these copyright, permission,
+ * and disclaimer notices, and (2) redistributions including binaries
+ * reproduce the notices in supporting documentation, and (3) all advertising
+ * materials mentioning features or use of this software display the following
+ * acknowledgement: ``This product includes software developed by the
+ * Computer Systems Laboratory at the University of Utah.''
+ *
+ * THE UNIVERSITY OF UTAH AND CSL ALLOW FREE USE OF THIS SOFTWARE IN ITS "AS
+ * IS" CONDITION. THE UNIVERSITY OF UTAH AND CSL DISCLAIM ANY LIABILITY OF
+ * ANY KIND FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * CSL requests users of this software to return to csl-dist@cs.utah.edu any
+ * improvements that they make and grant CSL redistribution rights.
+ *
+ * Author: Bryan Ford, University of Utah CSL
+ */
+
+#include <mach/machine/asm.h>
+
+#include "config.h"
+#include "i16_crt0.h"
+
+ .code16
+ .text
+
+ENTRY(i16_entry)
+ /* DOS starts us up with our stack pointer pointing
+ to the very top of our BSS segment.
+ ds and es point to the PSP. */
+
+#define DELAY jmp 1f; 1: jmp 1f; 1: jmp 1f; 1:
+
+ /* Check to make sure we're running on a 386 or higher -
+ _without_ using any 32-bit instructions of course.
+ Tricky, since gas doesn't support 16-bit addressing modes. :-)
+ We can't produce any 16-bit relocations either,
+ because ELF doesn't support them.
+ This code is basically straight out of the Pentium manual,
+ except gassed of coursed. */
+ pushfw
+ DELAY
+ popw %bx
+ movw $0xfff,%ax
+ andw %bx,%ax
+ pushw %ax
+ DELAY
+ popfw
+ DELAY
+ pushfw
+ DELAY
+ popw %ax
+ and $0xf000,%ax
+ cmpw $0xf000,%ax
+
+ je 1f
+ orw $0xf000,%bx
+ pushw %bx
+ DELAY
+ popfw
+ DELAY
+ pushfw
+ DELAY
+ popw %ax
+ andw $0xf000,%ax
+ jnz 4f
+1:
+ /* Gak! We're running on an 8086/8088/80286! */
+ callw 5f
+ .ascii "This program requires a 386 or better.\r\n\0"
+5: popw %si
+ movw %cs,%ax
+ movw %ax,%ds
+ cld
+2: lodsb
+ orb %al,%al
+ jz 3f
+ movb $0x02,%ah
+ movb %al,%dl
+ int $0x21
+ jmp 2b
+3: movw $0x4c02,%ax
+ int $0x21
+4:
+ /* Now we can use 32-bit instructions all we want. */
+
+ /* Save the PSP segment address (dx). */
+ movw %ds,%dx
+
+ /* Find our real-mode code segment (ax). */
+ movw %cs,%ax
+
+#ifdef ENABLE_PAGE_ALIGNED_KERNEL
+ /* Move our code and data so that everything is on a page boundary.
+ Theoretically we _could_ go past the end of available memory,
+ since we're not checking, but it's enormously unlikely. */
+ std
+ movw %ax,%ds
+ addw $0xff,%ax
+ andw $0xff00,%ax
+ movw %ax,%es
+ movl $EXT(edata),%ecx
+ subl $EXT(i16_entry_2),%ecx
+ movl $EXT(edata)-1,%esi
+ movw %si,%di
+ rep
+ movsb
+
+ /* Start running at the new address. */
+ pushl $EXT(i16_entry_2)
+ movw %ax,2(%esp)
+ lretw
+
+ENTRY(i16_entry_2)
+ /* We're now page aligned. */
+#endif ENABLE_PAGE_ALIGNED_KERNEL
+
+ /* Load the data segment registers appropriately. */
+ movw %ax,%es
+ movw %ax,%ss
+
+ /* Start using a real stack. */
+ movl $EXT(crt0_stack)+CRT0_STACK_SIZE,%esp
+
+ /* Clear our BSS segment. */
+ movl $EXT(edata),%edi
+ movl $EXT(end),%ecx
+ subw %di,%cx
+ xorb %al,%al
+ cld
+ rep
+ stosb
+
+ /* Find the size of the environment array (si)
+ and the number of environment variables plus one (bx).
+ The PSP segment is still in dx. */
+ movw %dx,%ds
+ movw 0x2c,%ds
+ xorw %si,%si
+1: lodsb
+ orb %al,%al
+ jnz 1b
+ lodsb
+ orb %al,%al
+ jnz 1b
+
+ /* Allocate space for the environment array on the stack.
+ Also make sure the top 16 bits of ESP are cleared,
+ and that the stack pointer is longword aligned. */
+ subw %si,%sp
+ andl $0x0000fffc,%esp
+
+ /* Copy the environment array to the local stack.
+ We present it backwards, but big deal - shouldn't matter. */
+ xorl %edi,%edi
+ movw %sp,%di
+ xorl %esi,%esi
+ pushl %esi
+ jmp 3f
+2: pushl %edi
+ stosb
+1: lodsb
+ stosb
+ orb %al,%al
+ jnz 1b
+3: lodsb
+ orb %al,%al
+ jnz 2b
+ movl %esp,%cs:EXT(environ)
+
+ /* Copy the program name to the local stack;
+ it will be used as argv[0]. */
+ lodsw
+ movw %si,%bx
+1: pushw $0
+ lodsb
+ orb %al,%al
+ jz 2f
+ lodsb
+ orb %al,%al
+ jnz 1b
+2: movw %bx,%si
+ movw %sp,%di
+3: lodsb
+ stosb
+ orb %al,%al
+ jnz 3b
+ movl %esp,%ebp
+
+ /* Build argv[1..n] from the command tail in the PSP.
+ Count the arguments in ebx. */
+ movw %dx,%ds
+ xorl %ecx,%ecx
+ xorl %ebx,%ebx
+ movb 0x80,%cl /* get size of command tail */
+ incw %cx /* plus the return character */
+ movw $0x80,%si
+ addw %cx,%si /* si = ptr to return character */
+ movw %sp,%di
+ decw %di
+ subw %cx,%sp /* allocate space on the stack */
+ andw $0xfffc,%sp
+ pushl %ebx
+ std
+1: xorb %al,%al /* store a null terminator for this arg */
+ stosb
+ incl %ebx
+2: cmpw $0x80,%si
+ je 5f
+ lodsb /* scan backwards for the end of an arg */
+ cmpb $0x20,%al
+ jbe 2b
+3: stosb /* copy the arg */
+ cmpw $0x80,%si
+ je 4f
+ lodsb
+ cmpb $0x20,%al
+ ja 3b
+4: movw %di,%cx /* push an arg pointer */
+ incw %cx
+ pushl %ecx
+ jmp 1b
+5:
+
+ /* Push the argv[0] pointer. */
+ pushl %ebp
+
+ /* Push the argument and envirnonment parameters on the stack. */
+ movl %esp,%eax
+ pushl %cs:EXT(environ)
+ pushl %eax
+ pushl %ebx
+
+ /* Release all conventional memory above the top of our BSS.
+ The PSP segment is still in dx. */
+ movl $EXT(end)+15,%ebx
+ shrw $4,%bx
+ movw %cs,%ax
+ addw %ax,%bx
+ subw %dx,%bx
+ movw %dx,%es
+ movb $0x4a,%ah
+ int $0x21
+
+ /* Load the normal data segment registers. */
+ movw %cs,%ax
+ movw %ax,%ds
+ movw %ax,%es
+
+ /* GCC wants the direction flag cleared at all times. */
+ cld
+
+ /* Initialize the bss and run the program. */
+ call EXT(i16_main)
+
+ .globl EXT(crt0_stack)
+ .comm EXT(crt0_stack),CRT0_STACK_SIZE
+
+ .globl EXT(environ)
+ .comm EXT(environ),4
+
+
+ .data
+
+ .section .anno,"aw",@progbits
+ P2ALIGN(4)
+ .globl __ANNO_START__
+__ANNO_START__:
+