david/ipxe
david
/
ipxe
Archived
1
0
Fork 0
This repository has been archived on 2020-12-06. You can view files and clone it, but cannot push or open issues or pull requests.
ipxe/contrib/baremetal/startmpcc.S

757 lines
14 KiB
ArmAsm
Raw Blame History

/* #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"
/* <20> <20> <20> <20> <20> <20> <20> <20>1:::::::::2:::::::::3:::::::3 */
/* <20> <20> <20> <20>12345678901234567890123456789012345678 */
/* <20> <20> <20> 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 */