.file "gdt.S" #include "def.h" #define AX 0 #define CX 4 #define DX 8 #define BX 12 #define BP 16 #define SI 20 #define DI 24 #define DS 28 #define ES 32 #define GEN_LABEL(n) X##n // idt entry #define idte(e) \ movl $GEN_LABEL(e), %eax ; \ call entry // idt bios entry #define idtbe(b) idte(emu##b) #define GEN_TRAP(name, err) \ GEN_LABEL(name): \ pushl $err; \ jmp 1f #define GEN_EMU(n) \ GEN_LABEL(emu##n): \ pushl $n; \ jmp 1f #define prot2real \ ljmp $S16TEXT, $1f - LINKADDR; \ 1: \ .code16; \ movw $S16DATA, %ax; \ movw %ax, %ds; \ movw %ax, %es; \ \ movl %cr0, %eax; \ andl $~CR0_PE, %eax; \ movl %eax, %cr0; \ \ data32 ljmp $(LINKADDR >> 4), $1f - LINKADDR; \ 1: \ movw %cs, %ax; \ movw %ax, %ds; \ movw %ax, %es; \ xorw %ax, %ax; \ movw %ax, %ss; \ data32 addr32 lidt (Idtr_real - LINKADDR); #define real2prot \ movw $LINKADDR >> 4, %ax; \ movw %ax, %ds; \ data32 addr32 lgdt (Gdtr - LINKADDR); \ \ movl %cr0, %eax; \ orl $CR0_PE, %eax; \ movl %eax, %cr0; \ \ data32 ljmp $S32TEXT, $1f; \ 1: \ .code32; \ mov $S32DATA, %eax; \ mov %ax, %ds; \ mov %ax, %ss; \ mov %ax, %es; \ \ lidt Idtr; .text .code32 .globl pmode_init .globl BIOSreg BIOSreg: .space 64 // Table // IDTR offset + 0 : entry 0 // IDTR offset + 8 : entry 1 // // Gate Descriptor // 63 ~ 48 : offset low // 47 ~ 32 : info // 31 ~ 16 : segment selector // 15 ~ 0 : offset high entry: movw %ax, (%ebx) movw $S32TEXT, 2(%ebx) movw $((0x80|SDT_SYS386TGT) << 8), 4(%ebx) shr $16, %eax movw %ax, 6(%ebx) addl $8, %ebx ret // init IDT for protected mode .align 8, 0x90 pmode_init: movl $idt, %ebx movl $Idtr, %eax movw $(640 - 1), (%eax) movl %ebx, 2(%eax) /* interal interrupts 0~31 */ idte(de); idte(db); idte(nmi); idte(bp); idte(of); idte(br) idte(ud); idte(nm); idte(df); idte(fo); idte(ts); idte(np) idte(ss); idte(gp); idte(pf); idte(xx); idte(mf); idte(ac) idte(mc) idte(xx); idte(xx); idte(xx); idte(xx); idte(xx); idte(xx) idte(xx); idte(xx); idte(xx); idte(xx); idte(xx); idte(xx) idte(xx) /* BIOS interrupt call (32-63) */ idtbe(0); idtbe(1); idtbe(2); idtbe(3); idtbe(4); idtbe(5) idtbe(6); idtbe(7); idtbe(8); idtbe(9); idtbe(10); idtbe(11) idtbe(12); idtbe(13); idtbe(14); idtbe(15); idtbe(16); idtbe(17) idtbe(18); idtbe(19); idtbe(20); idtbe(21); idtbe(22); idtbe(23) idtbe(24); idtbe(25); idtbe(26); idtbe(27); idtbe(28); idtbe(29) idtbe(30); idtbe(31); idtbe(32); idtbe(33); idtbe(34); idtbe(35) idtbe(36); idtbe(37); idtbe(38); idtbe(39); idtbe(40); idtbe(41) idtbe(42); idtbe(43); idtbe(44); idtbe(45); idtbe(46); idtbe(47) lidt Idtr ret .bss .align 8, 0x90 idt: .space 640 .globl Idtr Idtr: .word 0 .long 0 .word 0 .text .align 8 .globl Idtr_real Idtr_real: .word 1023 // 256 entry, 1k .long 0 .word 0 .align 8 gdt: /* 0x00 : null */ .space 8 /* 0x08 : flat code */ .word 0xFFFF // lolimit .word 0 // lobase .byte 0 // midbase .byte SDT_MEMERAC | 0 | 0x80 // RXAC, dpl = 0, present .byte 0xf | 0 | 0x40 | 0x80 // hilimit, xx, 32bit, 4k granularity .byte 0 // hibase /* 0x10 : flat data */ .word 0xFFFF // lolimit .word 0 // lobase .byte 0 // midbase .byte SDT_MEMRWA | 0 | 0x80 // RWA, dpl = 0, present .byte 0xf | 0 | 0x40 | 0x80 // hilimit, xx, 32bit, 4k granularity .byte 0 // hibase /* 0x18 : 16 bit code */ .word 0xFFFF // lolimit .word (LINKADDR & 0xffff) // lobase .byte (LINKADDR >> 16) & 0xff // midbase .byte SDT_MEMERAC | 0 | 0x80 // RXAC, dpl = 0, present .byte 0x0 | 0 | 0 | 0 // hilimit, xx, 16bit, byte granularity .byte (LINKADDR >> 20) & 0xff // hibase /* 0x20 : 16 bit data */ .word 0xFFFF // lolimit .word (LINKADDR & 0xffff) // lobase .byte (LINKADDR >> 16) & 0xff // midbase .byte SDT_MEMRWA | 0 | 0x80 // RWA, dpl = 0, present .byte 0x0 | 0 | 0 | 0 // hilimit, xx, 16bit, byte granularity .byte (LINKADDR >> 20) & 0xff // hibase // Register GDT .globl Gdtr Gdtr: .word . - gdt - 1 .long gdt .word 0 // ENTRY Reserved GEN_LABEL(xx): pushl $1 jmp 1f // trap entry points GEN_TRAP(de,T_DIVIDE) /* DE divide by zero */ GEN_TRAP(db,T_TRCTRAP) /* DB debug */ GEN_TRAP(nmi,T_NMI) /* NMI */ GEN_TRAP(bp,T_BPTFLT) /* BP breakpoint */ GEN_TRAP(of,T_OFLOW) /* OF overflow */ GEN_TRAP(br,T_BOUND) /* BR BOUND range exceeded */ GEN_TRAP(ud,T_PRIVINFLT) /* UD invalid opcode */ GEN_TRAP(nm,T_DNA) /* NM device not available */ GEN_TRAP(df,T_DOUBLEFLT) /* DF double fault */ GEN_TRAP(fo,T_FPOPFLT) /* FO coprocessor segment overrun */ GEN_TRAP(ts,T_TSSFLT) /* TS invalid TSS */ GEN_TRAP(np,T_SEGNPFLT) /* NP segment not present */ GEN_TRAP(ss,T_STKFLT) /* SS stack fault */ GEN_TRAP(gp,T_PROTFLT) /* GP general protection */ GEN_TRAP(pf,T_PAGEFLT) /* PF page fault */ GEN_TRAP(mf,T_ARITHTRAP) /* MF floating point error */ GEN_TRAP(ac,T_ALIGNFLT) /* AC alignment check */ GEN_TRAP(mc,T_MACHK) /* MC machine check */ 1: popl %ecx // what trap hlt jmp 1b GEN_EMU(0); GEN_EMU(1); GEN_EMU(2); GEN_EMU(3) GEN_EMU(4); GEN_EMU(5); GEN_EMU(6); GEN_EMU(7) GEN_EMU(8); GEN_EMU(9); GEN_EMU(10); GEN_EMU(11) GEN_EMU(12); GEN_EMU(13); GEN_EMU(14); GEN_EMU(15) GEN_EMU(16); GEN_EMU(17); GEN_EMU(18); GEN_EMU(19) GEN_EMU(20); GEN_EMU(21); GEN_EMU(22); GEN_EMU(23) GEN_EMU(24); GEN_EMU(25); GEN_EMU(26); GEN_EMU(27) GEN_EMU(28); GEN_EMU(29); GEN_EMU(30); GEN_EMU(31) GEN_EMU(32); GEN_EMU(33); GEN_EMU(34); GEN_EMU(35) GEN_EMU(36); GEN_EMU(37); GEN_EMU(38); GEN_EMU(39) GEN_EMU(40); GEN_EMU(41); GEN_EMU(42); GEN_EMU(43) GEN_EMU(44); GEN_EMU(45); GEN_EMU(46); GEN_EMU(47) 1: jmp EMUh // bios interrupt entry point // switch to real to protected mode and emulate 16bit mode .globl EMUh .align 8, 0x90 EMUh: // build stack for real mode mov %eax, 5f // save number to code segment not in the data segment pop %eax pusha push %ds push %es push %fs push %gs movb %al, intno // save BIOS int vector // BIOS_regs is area for saving the contents of registers returned by the BIOS during a BIOS CALL movl BIOSreg+ES, %eax mov %eax, 7f movl BIOSreg+DS, %eax mov %eax, 6f prot2real // save ds to stack and rewrite es, ds push %ds // data32 movl $Leax, %eax .byte 0x66, 0xb8 7: .long 0x90909090 mov %ax, %es // data32 movl $Leax, %eax .byte 0x66, 0xb8 6: .long 0x90909090 mov %ax, %ds // data32 movl $Leax, %eax => now ax is holding interrupt nummber .byte 0x66, 0xb8 5: .long 0x90909090 ;sti int $0 // do interrupt intno = . -1; cli; // restore register // preserve bx,es for protected mode pop %ds addr32 movl %eax, (2f - LINKADDR) movl %ebx, %eax addr32 movl %eax, (4f - LINKADDR) movl %es, %eax addr32 movl %eax, (3f- LINKADDR) addr32 movl (2f - LINKADDR), %eax // save eflags to bh movb %ah, %bh lahf xchgb %ah, %bh // preserve ax for protected mode addr32 movl %eax, (2f - LINKADDR) real2prot // movl $Leax, %eax .byte 0xb8 4: .long 0x90909090 movl %eax, BIOSreg+BX // movl $Leax, %eax .byte 0xb8 3: .long 0x90909090 movl %eax, BIOSreg+ES // movl $Leax, %eax .byte 0xb8 2: .long 0x90909090 // pass BIOS return values back to caller movl %eax, 0xb*4(%esp) movl %ecx, 0xa*4(%esp) movl %edx, 0x9*4(%esp) movb %bh, 0xe*4(%esp) // restore eflags // save register into BIOSREG movl %eax, BIOSreg+AX movl %ecx, BIOSreg+CX movl %edx, BIOSreg+DX movl %ebp, BIOSreg+BP movl %esi, BIOSreg+SI movl %edi, BIOSreg+DI // clear NT(Nested Task Flag: 14) flag in eflag // if 1 : interrupting pushf pop %eax and $0xffffbfff, %eax push %eax popf pop %ds pop %es pop %fs pop %gs popa iret