summaryrefslogtreecommitdiff
path: root/gpxe/contrib/baremetal/startmpcc.S
diff options
context:
space:
mode:
Diffstat (limited to 'gpxe/contrib/baremetal/startmpcc.S')
-rw-r--r--gpxe/contrib/baremetal/startmpcc.S756
1 files changed, 756 insertions, 0 deletions
diff --git a/gpxe/contrib/baremetal/startmpcc.S b/gpxe/contrib/baremetal/startmpcc.S
new file mode 100644
index 00000000..07486ce5
--- /dev/null
+++ b/gpxe/contrib/baremetal/startmpcc.S
@@ -0,0 +1,756 @@
+/* #defines because ljmp wants a number, probably gas bug */
+/* .equ KERN_CODE_SEG,_pmcs-_gdt */
+#define KERN_CODE_SEG 0x08
+ .equ KERN_DATA_SEG,_pmds-_gdt
+/* .equ REAL_CODE_SEG,_rmcs-_gdt */
+#define REAL_CODE_SEG 0x18
+ .equ REAL_DATA_SEG,_rmds-_gdt
+ .equ CR0_PE,1
+
+#ifdef GAS291
+#define DATA32 data32;
+#define ADDR32 addr32;
+#define LJMPI(x) ljmp x
+#else
+#define DATA32 data32
+#define ADDR32 addr32
+/* newer GAS295 require #define LJMPI(x) ljmp *x */
+#define LJMPI(x) ljmp x
+#endif
+
+#define PIC1_VBS 0x08 /* PIC1 interrupts start at vector 64 */
+#define PIC2_VBS 0x70 /* PIC1 interrupts start at vector 112 */
+
+/*
+ * NOTE: if you write a subroutine that is called from C code (gcc/egcs),
+ * then you only have to take care of %ebx, %esi, %edi and %ebp. These
+ * registers must not be altered under any circumstance. All other registers
+ * may be clobbered without any negative side effects. If you don't follow
+ * this rule then you'll run into strange effects that only occur on some
+ * gcc versions (because the register allocator may use different registers).
+ *
+ * All the data32 prefixes for the ljmp instructions are necessary, because
+ * the assembler emits code with a relocation address of 0. This means that
+ * all destinations are initially negative, which the assembler doesn't grok,
+ * because for some reason negative numbers don't fit into 16 bits. The addr32
+ * prefixes are there for the same reasons, because otherwise the memory
+ * references are only 16 bit wide. Theoretically they are all superfluous.
+ * One last note about prefixes: the data32 prefixes on all call _real_to_prot
+ * instructions could be removed if the _real_to_prot function is changed to
+ * deal correctly with 16 bit return addresses. I tried it, but failed.
+ */
+
+/**************************************************************************
+START - Where all the fun begins....
+**************************************************************************/
+/* this must be the first thing in the file because we enter from the top */
+ .global _start
+ .code32
+_start:
+ cli
+
+ /* load new IDT and GDT */
+ lgdt gdtarg
+ lidt Idt_Reg
+ /* flush prefetch queue, and reload %cs:%eip */
+ ljmp $KERN_CODE_SEG,$1f
+1:
+
+ /* reload other segment registers */
+ movl $KERN_DATA_SEG,%eax
+ movl %eax,%ds
+ movl %eax,%es
+ movl %eax,%ss
+ movl $stktop,%esp
+
+ /* program the PITs in order to stop them */
+ mov $0x30,%al
+ out %al,$0x43
+ out %al,$0x40
+ mov $0x70,%al
+ out %al,$0x43
+ out %al,$0x41
+ mov $0xf0,%al
+ out %al,$0x43
+ out %al,$0x42
+
+ call main
+ /* fall through */
+
+ .globl exit
+exit:
+2:
+ ljmp $KERN_CODE_SEG,$2b
+
+/**************************************************************************
+MEMSIZE - Determine size of extended memory
+**************************************************************************/
+ .globl memsize
+memsize:
+#if 0
+ pushl %ebx
+ pushl %esi
+ pushl %edi
+ call _prot_to_real
+ .code16
+ movw $0xe801,%ax
+ stc
+ int $0x15
+ jc 1f
+ andl $0xffff,%eax
+ andl $0xffff,%ebx
+ shll $6,%ebx
+ addl %ebx,%eax
+ jmp 2f
+1:
+ movw $0x8800,%ax
+ int $0x15
+ andl $0xffff,%eax
+2:
+ movl %eax,%esi
+ DATA32 call _real_to_prot
+ .code32
+ movl %esi,%eax
+ popl %edi
+ popl %esi
+ popl %ebx
+#else
+ mov $32768,%eax
+#endif
+ ret
+
+/**************************************************************************
+XSTART - Transfer control to the kernel just loaded
+**************************************************************************/
+ .code16
+
+ .globl _int08_handler
+_int08_handler:
+ movb $0x20, %al
+ outb %al, $0x20
+ iret
+
+ .globl _int10_handler
+_int10_handler:
+ cmp $0x3, %ah
+ jnz _int10_04
+ mov $0x0, %dx
+ mov $0x0, %cx
+ iret
+_int10_04:
+ cmp $0x4, %ah
+ jnz _int10_05
+ mov $0x0, %ah
+ iret
+_int10_05:
+ cmp $0x5, %ah
+ jnz _int10_08
+ mov $0x0, %al
+ iret
+_int10_08:
+ cmp $0x8, %ah
+ jnz _int10_0D
+ mov $0x20, %al
+ mov $0x7, %ah
+ iret
+_int10_0D:
+ cmp $0xD, %ah
+ jnz _int10_0F
+ mov $0x0, %al
+ iret
+_int10_0F:
+ cmp $0xF, %ah
+ jnz _int10_XX
+ mov $0xb, %al
+ mov $80, %ah
+ mov $0, %bh
+_int10_XX:
+ iret
+
+ .globl _int11_handler
+_int11_handler:
+ mov $0x22, %ax
+ iret
+
+ .globl _int12_handler
+_int12_handler:
+ mov $640, %ax
+ iret
+
+ .globl _int13_handler
+_int13_handler:
+ clc
+ mov $0, %ah
+ iret
+
+ .globl _int14_handler
+_int14_handler:
+ iret
+
+ .globl _int15_handler
+_int15_handler:
+ cmp $0xe801,%ax
+ jz _int15_008
+ cmp $0x0, %ah
+ jz _int15_000
+ cmp $0x1, %ah
+ jz _int15_000
+ cmp $0x2, %ah
+ jz _int15_000
+ cmp $0x3, %ah
+ jz _int15_000
+ cmp $0xf, %ah
+ jz _int15_000
+ cmp $0x21, %ah
+ jz _int15_000
+ cmp $0x40, %ah
+ jz _int15_000
+ cmp $0x41, %ah
+ jz _int15_000
+ cmp $0x42, %ah
+ jz _int15_000
+ cmp $0x43, %ah
+ jz _int15_000
+ cmp $0x44, %ah
+ jz _int15_000
+ cmp $0x80, %ah
+ jz _int15_001
+ cmp $0x81, %ah
+ jz _int15_001
+ cmp $0x82, %ah
+ jz _int15_002
+ cmp $0x83, %ah
+ jz _int15_003
+ cmp $0x84, %ah
+ jz _int15_000
+ cmp $0x85, %ah
+ jz _int15_004
+ cmp $0x86, %ah
+ jz _int15_003
+ cmp $0x87, %ah
+ jz _int15_005
+ cmp $0x88, %ah
+ jz _int15_006
+ cmp $0x89, %ah
+ jz _int15_005
+ cmp $0x90, %ah
+ jz _int15_007
+ cmp $0xc0, %ah
+ jz _int15_000
+ cmp $0xc1, %ah
+ jz _int15_000
+ cmp $0xc2, %ah
+ jz _int15_000
+ cmp $0xc3, %ah
+ jz _int15_000
+ cmp $0xc4, %ah
+ jz _int15_000
+ iret
+
+_int15_000:
+ mov $0x86, %ah
+ stc
+ iret
+
+_int15_001:
+ mov $0, %bx
+ mov $0, %cx
+ iret
+
+_int15_002:
+ mov $0, %bx
+ iret
+
+_int15_003:
+ clc
+ iret
+
+_int15_004:
+ mov $0, %al
+ iret
+
+_int15_005:
+ mov $0, %ah
+ clc
+ cmp $0, %ah
+ iret
+
+_int15_006:
+ mov $0xf000, %ax
+ iret
+
+_int15_007:
+ stc
+ iret
+
+_int15_008:
+ clc
+ mov $1024, %dx /* dx -> extended memory size (in 64K chuncks) */
+ mov $640, %cx /* cx -> conventional memory size (in 1 Kbytes chuncks) */
+ iret
+
+ .globl _int16_handler
+_int16_handler:
+ cmp $0x0, %ah
+ jnz _int16_01
+ mov $0x20, %al
+ mov $0x39, %ah
+ iret
+_int16_01:
+ cmp $0x1, %ah
+ jnz _int16_02
+ iret
+_int16_02:
+ cmp $0x2, %ah
+ jnz _int16_05
+ mov $0, %al
+ iret
+_int16_05:
+ cmp $0x5, %ah
+ jnz _int16_10
+ mov $0, %al
+ iret
+_int16_10:
+ cmp $0x10, %ah
+ jnz _int16_11
+ mov $0x20, %al
+ mov $0x39, %ah
+ iret
+_int16_11:
+ cmp $0x11, %ah
+ jnz _int16_12
+ iret
+_int16_12:
+ cmp $0x12, %ah
+ jnz _int16_XX
+ mov $0, %ax
+ iret
+_int16_XX:
+ iret
+
+ .globl _int17_handler
+_int17_handler:
+ mov $0xd0, %ah
+ iret
+
+ .globl _int19_handler
+_int19_handler:
+ hlt
+ iret
+
+ .globl _int1A_handler
+_int1A_handler:
+ stc
+ iret
+
+ .code32
+ .globl xstart
+xstart:
+ /* reprogram the PICs so that interrupt are masked */
+ movb $0x11,%al /* ICW1 [ICW4 NEEDED, EDGE TRIGGERED]*/
+ outb %al,$0x20
+ movb $PIC1_VBS, %al
+ outb %al,$0x21
+ movb $0x4,%al
+ outb %al,$0x21
+ movb $0x1,%al
+ outb %al,$0x21
+ movb $0xff,%al
+ outb %al,$0x21
+
+ movb $0x11,%al /* ICW1 [ICW4 NEEDED, EDGE TRIGGERED]*/
+ outb %al,$0xa0
+ movb $PIC2_VBS, %al
+ outb %al,$0xa1
+ movb $0x2,%al
+ outb %al,$0xa1
+ movb $0x1,%al
+ outb %al,$0xa1
+ movb $0xff,%al
+ outb %al,$0xa1
+
+ pushl %ebp
+ movl %esp,%ebp
+ pushl %ebx
+ pushl %esi
+ pushl %edi
+ movl 8(%ebp),%eax
+ movl %eax,_execaddr
+ movl 12(%ebp),%ebx
+ movl 16(%ebp),%ecx /* bootp record (32bit pointer) */
+ addl $28,%ecx /* ip, udp header */
+ shll $12,%ecx
+ shrw $12,%cx
+ call _prot_to_real
+ .code16
+/* MP: add int10 handler */
+ push %eax
+ push %ebx
+ push %es
+ mov $0,%ax
+ mov %ax,%es
+ mov %cs,%ax
+ shl $16,%eax
+
+ ADDR32 mov $(_int08_handler-_start),%ax
+ mov $0x20,%ebx
+ mov %eax,%es:(%bx)
+
+ ADDR32 mov $(_int10_handler-_start),%ax
+ mov $0x40,%ebx
+ mov %eax,%es:(%bx)
+
+ ADDR32 mov $(_int11_handler-_start),%ax
+ mov $0x44,%ebx
+ mov %eax,%es:(%bx)
+
+ ADDR32 mov $(_int12_handler-_start),%ax
+ mov $0x48,%ebx
+ mov %eax,%es:(%bx)
+
+ ADDR32 mov $(_int13_handler-_start),%ax
+ mov $0x4c,%ebx
+ mov %eax,%es:(%bx)
+
+ ADDR32 mov $(_int14_handler-_start),%ax
+ mov $0x50,%ebx
+ mov %eax,%es:(%bx)
+
+ ADDR32 mov $(_int15_handler-_start),%ax
+ mov $0x54,%ebx
+ mov %eax,%es:(%bx)
+
+ ADDR32 mov $(_int16_handler-_start),%ax
+ mov $0x58,%ebx
+ mov %eax,%es:(%bx)
+
+ ADDR32 mov $(_int17_handler-_start),%ax
+ mov $0x5c,%ebx
+ mov %eax,%es:(%bx)
+
+ ADDR32 mov $(_int19_handler-_start),%ax
+ mov $0x64,%ebx
+ mov %eax,%es:(%bx)
+
+ ADDR32 mov $(_int1A_handler-_start),%ax
+ mov $0x68,%ebx
+ mov %eax,%es:(%bx)
+
+ pop %es
+ pop %ebx
+ pop %eax
+/* */
+ pushl %ecx /* bootp record */
+ pushl %ebx /* file header */
+ movl $((RELOC<<12)+(1f-RELOC)),%eax
+ pushl %eax
+ ADDR32 LJMPI(_execaddr-_start)
+1:
+ addw $8,%sp /* XXX or is this 10 in case of a 16bit "ret" */
+ DATA32 call _real_to_prot
+ .code32
+ popl %edi
+ popl %esi
+ popl %ebx
+ popl %ebp
+ ret
+
+_execaddr:
+ .long 0
+
+#ifdef IMAGE_MULTIBOOT
+/**************************************************************************
+XEND - Restart Etherboot from the beginning (from protected mode)
+**************************************************************************/
+
+ .globl xend
+xend:
+ cs
+ lidt idtarg_realmode-_start+RELOC
+ cs
+ lgdt gdtarg-_start+RELOC
+#ifdef GAS291
+ ljmp $REAL_CODE_SEG,$1f-RELOC /* jump to a 16 bit segment */
+#else
+ ljmp $REAL_CODE_SEG,$1f-_start /* jump to a 16 bit segment */
+#endif /* GAS291 */
+1:
+ .code16
+ movw $REAL_DATA_SEG,%ax
+ movw %ax,%ds
+ movw %ax,%ss
+ movw %ax,%es
+
+ /* clear the PE bit of CR0 */
+ movl %cr0,%eax
+ andl $0!CR0_PE,%eax
+ movl %eax,%cr0
+
+ /* make intersegment jmp to flush the processor pipeline
+ * and reload %cs:%eip (to clear upper 16 bits of %eip).
+ */
+ DATA32 ljmp $(RELOC)>>4,$2f-_start
+2:
+ /* we are in real mode now
+ * set up the real mode segment registers : %ds, %ss, %es
+ */
+ movw %cs,%ax
+ movw %ax,%ds
+ movw %ax,%es
+ movw %ax,%ss
+ xorl %esp,%esp
+ ADDR32 movw initsp-RELOC,%sp
+
+ movw $0,%ax
+ movw %ax,%fs
+ movw %ax,%gs
+
+ sti
+ jmp _start
+
+ .code32
+#endif /* IMAGE_MULTIBOOT */
+
+.global get_cs
+get_cs:
+ xorl %eax,%eax
+ movw %cs,%ax
+ ret
+
+.global get_ds
+get_ds:
+ xorl %eax,%eax
+ movw %ds,%ax
+ ret
+
+.global getsp
+getsp:
+ movl %esp,%eax /* GET STACK POINTER */
+ subl $4, %eax /* ACCOUNT FOR RETURN ADDRESS ON */
+ ret
+
+.global get_gdtbase
+get_gdtbase:
+ sub $8,%esp /* ALLOCATE ROOM ON THE STACK */
+ sgdt (%esp,1) /*STORE IGDT REGISTER ON STACK */
+ mov 2(%esp),%eax /* READ GDT BASE ADDRESS */
+ mov $KERN_DATA_SEG,%dx /* ASSUME UNIVERSAL DS. */
+ add $8,%esp /* RESTORE STACK */
+ ret /* DONE */
+
+.global get_gdtsize
+get_gdtsize:
+ sub $8,%esp /* ALLOCATE ROOM ON THE STACK */
+ sgdt (%esp,1) /*STORE IGDT REGISTER ON STACK */
+ xor %eax,%eax
+ mov 2(%esp),%eax /* READ GDT BASE ADDRESS */
+ mov (%ESP),%ax
+ shr $3,%ax
+ add $8,%esp /* RESTORE STACK */
+ ret /* DONE */
+
+.global get_idtbase
+get_idtbase:
+ sub $8,%esp
+ sidt (%esp,1) /* STORE IIDT REGISTER ON STACK */
+ mov 2(%esp),%eax
+ mov $KERN_DATA_SEG,%dx
+ add $8,%esp
+ ret
+
+.global get_lw
+get_lw:
+ xor %edx,%edx
+ mov 8(%esp),%eax
+ mov 4(%esp),%dx
+ ret
+
+/**************************************************************************
+SETJMP - Save stack context for non-local goto
+**************************************************************************/
+ .globl setjmp
+setjmp:
+ mov 4(%esp),%ecx
+ mov 0(%esp),%edx
+ mov %edx,0(%ecx)
+ mov %ebx,4(%ecx)
+ mov %esp,8(%ecx)
+ mov %ebp,12(%ecx)
+ mov %esi,16(%ecx)
+ mov %edi,20(%ecx)
+ mov %eax,24(%ecx)
+ mov $0,%eax
+ ret
+
+/**************************************************************************
+LONGJMP - Non-local jump to a saved stack context
+**************************************************************************/
+ .globl longjmp
+longjmp:
+ mov 4(%esp),%edx
+ mov 8(%esp),%eax
+ mov 0(%edx),%ecx
+ mov 4(%edx),%ebx
+ mov 8(%edx),%esp
+ mov 12(%edx),%ebp
+ mov 16(%edx),%esi
+ mov 20(%edx),%edi
+ cmp $0,%eax
+ jne 1f
+ mov $1,%eax
+1: mov %ecx,0(%esp)
+ ret
+
+/**************************************************************************
+_REAL_TO_PROT - Go from REAL mode to Protected Mode
+**************************************************************************/
+ .globl _real_to_prot
+_real_to_prot:
+ .code16
+ cli
+ cs
+ ADDR32 lgdt gdtarg-_start
+ movl %cr0,%eax
+ orl $CR0_PE,%eax
+ movl %eax,%cr0 /* turn on protected mode */
+
+ /* flush prefetch queue, and reload %cs:%eip */
+ DATA32 ljmp $KERN_CODE_SEG,$1f
+1:
+ .code32
+ /* reload other segment registers */
+ movl $KERN_DATA_SEG,%eax
+ movl %eax,%ds
+ movl %eax,%es
+ movl %eax,%ss
+ addl $RELOC,%esp /* Fix up stack pointer */
+ xorl %eax,%eax
+ movl %eax,%fs
+ movl %eax,%gs
+ popl %eax /* Fix up return address */
+ addl $RELOC,%eax
+ pushl %eax
+ ret
+
+/**************************************************************************
+_PROT_TO_REAL - Go from Protected Mode to REAL Mode
+**************************************************************************/
+ .globl _prot_to_real
+_prot_to_real:
+ .code32
+ popl %eax
+ subl $RELOC,%eax /* Adjust return address */
+ pushl %eax
+ subl $RELOC,%esp /* Adjust stack pointer */
+#ifdef GAS291
+ ljmp $REAL_CODE_SEG,$1f-RELOC /* jump to a 16 bit segment */
+#else
+ ljmp $REAL_CODE_SEG,$1f-_start /* jump to a 16 bit segment */
+#endif /* GAS291 */
+1:
+ .code16
+ movw $REAL_DATA_SEG,%ax
+ movw %ax,%ds
+ movw %ax,%ss
+ movw %ax,%es
+ movw %ax,%fs
+ movw %ax,%gs
+ cli
+
+ /* clear the PE bit of CR0 */
+ movl %cr0,%eax
+ andl $0!CR0_PE,%eax
+ movl %eax,%cr0
+
+ /* make intersegment jmp to flush the processor pipeline
+ * and reload %cs:%eip (to clear upper 16 bits of %eip).
+ */
+ DATA32 ljmp $(RELOC)>>4,$2f-_start
+2:
+ /* we are in real mode now
+ * set up the real mode segment registers : %ds, $ss, %es
+ */
+ movw %cs,%ax
+ movw %ax,%ds
+ movw %ax,%es
+ movw %ax,%ss
+#if 0
+ sti
+#endif
+ DATA32 ret /* There is a 32 bit return address on the stack */
+ .code32
+
+/**************************************************************************
+GLOBAL DESCRIPTOR TABLE
+**************************************************************************/
+ .align 4
+Idt_Reg:
+ .word 0x3ff
+ .long 0
+
+ .align 4
+_gdt:
+gdtarg:
+Gdt_Table:
+ .word 0x27 /* limit */
+ .long _gdt /* addr */
+ .word 0
+_pmcs:
+ /* 32 bit protected mode code segment */
+ .word 0xffff,0
+ .byte 0,0x9f,0xcf,0
+
+_pmds:
+ /* 32 bit protected mode data segment */
+ .word 0xffff,0
+ .byte 0,0x93,0xcf,0
+
+_rmcs:
+ /* 16 bit real mode code segment */
+ .word 0xffff,(RELOC&0xffff)
+ .byte (RELOC>>16),0x9b,0x00,(RELOC>>24)
+
+_rmds:
+ /* 16 bit real mode data segment */
+ .word 0xffff,(RELOC&0xffff)
+ .byte (RELOC>>16),0x93,0x00,(RELOC>>24)
+
+ .align 4
+RUN_GDT: /* POINTER TO GDT IN RAM */
+ .byte 0x7f,0 /* [BSP_GDT_NUM*8]-1 */
+ .long Gdt_Table
+
+ .align 4
+
+ .section ".rodata"
+err_not386:
+ .ascii "Etherboot/32 requires 386+"
+ .byte 0x0d, 0x0a
+err_not386_end:
+
+days: .long 0
+irq_num: .long
+
+ .data
+ .align 4
+ .org 2048
+.global stktop
+stktop:
+ .long
+
+.section ".armando"
+/*                1:::::::::2:::::::::3:::::::3 */
+/*        12345678901234567890123456789012345678 */
+/*       v----+----v----+----v----+----v----+--- */
+
+.global EtherbootString
+EtherbootString:
+.ascii "EtherBoot MPCC " /* fw identifier */
+
+.byte 0, 0 /* mandatory hole */
+
+.long _start /* entry point */
+.word 0
+.byte 'E' /* type */
+.byte 0 /* selector */
+.word 0 /* CRC */