global gdt global idt global kboot global register_isr global register_trap extern con_init extern fs_init extern kmain extern paging_init extern printk extern syscall_init extern timer_init extern traps_init extern tty_init %define NRTASKS 64 ; Multiboot header section .mboothdr mboot_hdr: align 4 dd 0x1BADB002 dd 0x00 dd - (0x1BADB002 + 0x00) section .text kboot: cli ; put the stack pointer near the end of conventional memory ; WARNING: don't change this without changing the corresponding ; entries in the TSS constructor in sched.c mov esp, 0x80000 ; setup descriptor tables and enable paging call flush_gdt call paging_init call flush_idt ; initialize the console call con_init ; add this point, we can display *some* output push .msg call printk add esp, 4 ; initialize secondary subsystems call fs_init call tty_init ; last minute setup, then transfer to kmain call timer_init call kmain ; if kmain decides to return (which it shouldn't), ; disable interrupts and halt the system. cli hlt .msg: db "Kernel booting...", 10, 0 gdt: ; null descriptor dq 0 ; kernel code segment dw 0xFFFF ; limit (bits 0-15) dw 0x0000 ; base (bits 0-15) db 0x00 ; base (bits 16-23) db 0x9A ; access byte db 0xCF ; flags / limit (bits 16-19) db 0x00 ; base (bits 24-31) ; kernel data segment dw 0xFFFF dw 0x0000 db 0x00 db 0x92 db 0xCF db 0x00 ; userspace code segment dw 0xFFFF dw 0x0000 db 0x00 db 0xFA db 0xCF db 0x00 ; userspace data segment dw 0xFFFF dw 0x0000 db 0x00 db 0xF2 db 0xCF db 0x00 ; empty TSS slots for our C scheduler times NRTASKS dq 0 ; garbage TSS descriptor dq 0 .end: gdtp: dw (gdt.end-gdt-1) dd gdt garbage_tss: times 104 db 0 flush_gdt: push ebp mov ebp, esp push ebx ; now, load the GDT lgdt [gdtp] mov ax, 0x10 mov ds, ax mov es, ax mov fs, ax mov gs, ax mov ss, ax jmp 0x08:.end .end: ; finally, we load the task register with ; a pointer to our dummy TSS. this is ; necessary since the CPU *must* save the ; previous task state *somewhere* before ; switching tasks. to avoid overwriting ; any sensitive information, we reserve ; 104 bytes for a *garbage* TSS. mov eax, 5 add eax, NRTASKS shl eax, 3 mov ebx, eax add ebx, gdt mov edx, garbage_tss mov dword [ebx], 103 ; limit - 1 mov [ebx+2], dx shr edx, 16 mov [ebx+4], dl mov [ebx+7], dh mov byte [ebx+5], 0x89 mov byte [ebx+6], 0x00 ltr ax pop ebx pop ebp ret idt: times (256*8) db 0 .end: idtp: dw (idt.end-idt-1) dd idt int_handler: iret flush_idt: push ebp mov ebp, esp ; install the exception handlers (vectors 0-31) call traps_init ; install the default handlers (vectors 32-255) mov ecx, 0 lea edx, [idt+(32*8)] .loop: mov eax, int_handler mov [edx], ax shr eax, 16 mov [edx+6], ax mov word [edx+2], 0x08 mov byte [edx+4], 0x00 mov byte [edx+5], 0x8E inc ecx cmp ecx, (256-32) je .end add edx, 8 jmp .loop .end: ; install the system call handler call syscall_init ; load the IDT, initialize the PIC's, and enable interrupts lidt [idtp] call pic_init sti pop ebp ret ; void register_isr(uint8_t n, uint8_t dpl, void *handler); register_isr: push ebp mov ebp, esp mov edx, [ebp+8] shl edx, 3 add edx, idt mov eax, [ebp+16] mov [edx], ax shr eax, 16 mov [edx+6], ax mov eax, [ebp+12] and al, 3 shl al, 5 mov cl, 0x8E or cl, al mov [edx+5], cl pop ebp ret ; void register_trap(uint8_t n, uint8_t dpl, void *handler); register_trap: push ebp mov ebp, esp mov edx, [ebp+8] shl edx, 3 add edx, idt mov eax, [ebp+16] mov [edx], ax shr eax, 16 mov [edx+6], ax mov eax, [ebp+12] and al, 3 shl al, 5 mov cl, 0x8F or cl, al mov [edx+5], cl pop ebp ret pic_init: push ebp mov ebp, esp mov al, 0x11 out 0x20, al out 0xA0, al mov al, 0x20 out 0x21, al out 0xA1, al mov al, 0x04 out 0x21, al mov al, 0x02 out 0xA1, al mov al, 0x01 out 0x21, al out 0xA1, al mov al, 0xFF out 0x21, al out 0xA1, al pop ebp ret