123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756 |
- /* #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 */
|