1 /* #defines because ljmp wants a number, probably gas bug */
2 /* .equ KERN_CODE_SEG,_pmcs-_gdt */
3 #define KERN_CODE_SEG 0x08
4 .equ KERN_DATA_SEG,_pmds-_gdt
5 /* .equ REAL_CODE_SEG,_rmcs-_gdt */
6 #define REAL_CODE_SEG 0x18
7 .equ REAL_DATA_SEG,_rmds-_gdt
11 #define DATA32 data32;
12 #define ADDR32 addr32;
13 #define LJMPI(x) ljmp x
17 /* newer GAS295 require #define LJMPI(x) ljmp *x */
18 #define LJMPI(x) ljmp x
21 #define PIC1_VBS 0x08 /* PIC1 interrupts start at vector 64 */
22 #define PIC2_VBS 0x70 /* PIC1 interrupts start at vector 112 */
25 * NOTE: if you write a subroutine that is called from C code (gcc/egcs),
26 * then you only have to take care of %ebx, %esi, %edi and %ebp. These
27 * registers must not be altered under any circumstance. All other registers
28 * may be clobbered without any negative side effects. If you don't follow
29 * this rule then you'll run into strange effects that only occur on some
30 * gcc versions (because the register allocator may use different registers).
32 * All the data32 prefixes for the ljmp instructions are necessary, because
33 * the assembler emits code with a relocation address of 0. This means that
34 * all destinations are initially negative, which the assembler doesn't grok,
35 * because for some reason negative numbers don't fit into 16 bits. The addr32
36 * prefixes are there for the same reasons, because otherwise the memory
37 * references are only 16 bit wide. Theoretically they are all superfluous.
38 * One last note about prefixes: the data32 prefixes on all call _real_to_prot
39 * instructions could be removed if the _real_to_prot function is changed to
40 * deal correctly with 16 bit return addresses. I tried it, but failed.
43 /**************************************************************************
44 START - Where all the fun begins....
45 **************************************************************************/
46 /* this must be the first thing in the file because we enter from the top */
52 /* load new IDT and GDT */
55 /* flush prefetch queue, and reload %cs:%eip */
56 ljmp $KERN_CODE_SEG,$1f
59 /* reload other segment registers */
60 movl $KERN_DATA_SEG,%eax
66 /* program the PITs in order to stop them */
83 ljmp $KERN_CODE_SEG,$2b
85 /**************************************************************************
86 MEMSIZE - Determine size of extended memory
87 **************************************************************************/
111 DATA32 call _real_to_prot
122 /**************************************************************************
123 XSTART - Transfer control to the kernel just loaded
124 **************************************************************************/
127 .globl _int08_handler
133 .globl _int10_handler
170 .globl _int11_handler
175 .globl _int12_handler
180 .globl _int13_handler
186 .globl _int14_handler
190 .globl _int15_handler
288 mov $1024, %dx /* dx -> extended memory size (in 64K chuncks) */
289 mov $640, %cx /* cx -> conventional memory size (in 1 Kbytes chuncks) */
292 .globl _int16_handler
331 .globl _int17_handler
336 .globl _int19_handler
341 .globl _int1A_handler
349 /* reprogram the PICs so that interrupt are masked */
350 movb $0x11,%al /* ICW1 [ICW4 NEEDED, EDGE TRIGGERED]*/
361 movb $0x11,%al /* ICW1 [ICW4 NEEDED, EDGE TRIGGERED]*/
380 movl 16(%ebp),%ecx /* bootp record (32bit pointer) */
381 addl $28,%ecx /* ip, udp header */
386 /* MP: add int10 handler */
395 ADDR32 mov $(_int08_handler-_start),%ax
399 ADDR32 mov $(_int10_handler-_start),%ax
403 ADDR32 mov $(_int11_handler-_start),%ax
407 ADDR32 mov $(_int12_handler-_start),%ax
411 ADDR32 mov $(_int13_handler-_start),%ax
415 ADDR32 mov $(_int14_handler-_start),%ax
419 ADDR32 mov $(_int15_handler-_start),%ax
423 ADDR32 mov $(_int16_handler-_start),%ax
427 ADDR32 mov $(_int17_handler-_start),%ax
431 ADDR32 mov $(_int19_handler-_start),%ax
435 ADDR32 mov $(_int1A_handler-_start),%ax
443 pushl %ecx /* bootp record */
444 pushl %ebx /* file header */
445 movl $((RELOC<<12)+(1f-RELOC)),%eax
447 ADDR32 LJMPI(_execaddr-_start)
449 addw $8,%sp /* XXX or is this 10 in case of a 16bit "ret" */
450 DATA32 call _real_to_prot
461 #ifdef IMAGE_MULTIBOOT
462 /**************************************************************************
463 XEND - Restart Etherboot from the beginning (from protected mode)
464 **************************************************************************/
469 lidt idtarg_realmode-_start+RELOC
471 lgdt gdtarg-_start+RELOC
473 ljmp $REAL_CODE_SEG,$1f-RELOC /* jump to a 16 bit segment */
475 ljmp $REAL_CODE_SEG,$1f-_start /* jump to a 16 bit segment */
479 movw $REAL_DATA_SEG,%ax
484 /* clear the PE bit of CR0 */
489 /* make intersegment jmp to flush the processor pipeline
490 * and reload %cs:%eip (to clear upper 16 bits of %eip).
492 DATA32 ljmp $(RELOC)>>4,$2f-_start
494 /* we are in real mode now
495 * set up the real mode segment registers : %ds, %ss, %es
502 ADDR32 movw initsp-RELOC,%sp
512 #endif /* IMAGE_MULTIBOOT */
528 movl %esp,%eax /* GET STACK POINTER */
529 subl $4, %eax /* ACCOUNT FOR RETURN ADDRESS ON */
534 sub $8,%esp /* ALLOCATE ROOM ON THE STACK */
535 sgdt (%esp,1) /*STORE IGDT REGISTER ON STACK */
536 mov 2(%esp),%eax /* READ GDT BASE ADDRESS */
537 mov $KERN_DATA_SEG,%dx /* ASSUME UNIVERSAL DS. */
538 add $8,%esp /* RESTORE STACK */
543 sub $8,%esp /* ALLOCATE ROOM ON THE STACK */
544 sgdt (%esp,1) /*STORE IGDT REGISTER ON STACK */
546 mov 2(%esp),%eax /* READ GDT BASE ADDRESS */
549 add $8,%esp /* RESTORE STACK */
555 sidt (%esp,1) /* STORE IIDT REGISTER ON STACK */
557 mov $KERN_DATA_SEG,%dx
568 /**************************************************************************
569 SETJMP - Save stack context for non-local goto
570 **************************************************************************/
585 /**************************************************************************
586 LONGJMP - Non-local jump to a saved stack context
587 **************************************************************************/
604 /**************************************************************************
605 _REAL_TO_PROT - Go from REAL mode to Protected Mode
606 **************************************************************************/
612 ADDR32 lgdt gdtarg-_start
615 movl %eax,%cr0 /* turn on protected mode */
617 /* flush prefetch queue, and reload %cs:%eip */
618 DATA32 ljmp $KERN_CODE_SEG,$1f
621 /* reload other segment registers */
622 movl $KERN_DATA_SEG,%eax
626 addl $RELOC,%esp /* Fix up stack pointer */
630 popl %eax /* Fix up return address */
635 /**************************************************************************
636 _PROT_TO_REAL - Go from Protected Mode to REAL Mode
637 **************************************************************************/
642 subl $RELOC,%eax /* Adjust return address */
644 subl $RELOC,%esp /* Adjust stack pointer */
646 ljmp $REAL_CODE_SEG,$1f-RELOC /* jump to a 16 bit segment */
648 ljmp $REAL_CODE_SEG,$1f-_start /* jump to a 16 bit segment */
652 movw $REAL_DATA_SEG,%ax
660 /* clear the PE bit of CR0 */
665 /* make intersegment jmp to flush the processor pipeline
666 * and reload %cs:%eip (to clear upper 16 bits of %eip).
668 DATA32 ljmp $(RELOC)>>4,$2f-_start
670 /* we are in real mode now
671 * set up the real mode segment registers : %ds, $ss, %es
680 DATA32 ret /* There is a 32 bit return address on the stack */
683 /**************************************************************************
684 GLOBAL DESCRIPTOR TABLE
685 **************************************************************************/
695 .word 0x27 /* limit */
696 .long _gdt /* addr */
699 /* 32 bit protected mode code segment */
704 /* 32 bit protected mode data segment */
709 /* 16 bit real mode code segment */
710 .word 0xffff,(RELOC&0xffff)
711 .byte (RELOC>>16),0x9b,0x00,(RELOC>>24)
714 /* 16 bit real mode data segment */
715 .word 0xffff,(RELOC&0xffff)
716 .byte (RELOC>>16),0x93,0x00,(RELOC>>24)
719 RUN_GDT: /* POINTER TO GDT IN RAM */
720 .byte 0x7f,0 /* [BSP_GDT_NUM*8]-1 */
727 .ascii "Etherboot/32 requires 386+"
742 /* 1:::::::::2:::::::::3:::::::3 */
743 /* 12345678901234567890123456789012345678 */
744 /* v----+----v----+----v----+----v----+--- */
746 .global EtherbootString
748 .ascii "EtherBoot MPCC " /* fw identifier */
750 .byte 0, 0 /* mandatory hole */
752 .long _start /* entry point */
755 .byte 0 /* selector */