bootloader/boot/gdt.S

343 lines
7.6 KiB
ArmAsm

.file "gdt.S"
#include "def.h"
#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
.globl BIOSreg
BIOSreg:
BIOS_AX: .long 0
BIOS_CX: .long 0
BIOS_DX: .long 0
BIOS_BX: .long 0
BIOS_BP: .long 0
BIOS_SI: .long 0
BIOS_DI: .long 0
BIOS_DS: .long 0
BIOS_ES: .long 0
.text
.code32
.globl pmode_init
// 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 BIOS_ES, %eax
movl $0x00, %eax
mov %eax, 7f
movl BIOS_DS, %eax
movl $0x00, %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
mov %eax, BIOS_BX
// movl $Leax, %eax
.byte 0xb8
3: .long 0x90909090
mov %eax, BIOS_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
.code32
movl %eax, BIOS_AX
movl %ecx, BIOS_CX
movl %edx, BIOS_DX
movl %ebp, BIOS_BP
movl %esi, BIOS_SI
movl %edi, BIOS_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