; ; Copyright 2010 Stefan Lankes, Chair for Operating Systems, ; RWTH Aachen University ; ; Licensed under the Apache License, Version 2.0 (the "License"); ; you may not use this file except in compliance with the License. ; You may obtain a copy of the License at ; ; http://www.apache.org/licenses/LICENSE-2.0 ; ; Unless required by applicable law or agreed to in writing, software ; distributed under the License is distributed on an "AS IS" BASIS, ; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ; See the License for the specific language governing permissions and ; limitations under the License. ; ; This file is part of MetalSVM. ; This is the kernel's entry point. We could either call main here, ; or we can use this to setup the stack or other nice stuff, like ; perhaps setting up the GDT and segments. Please note that interrupts ; are disabled at this point: More on interrupts later! [BITS 32] ; We use a special name to map this section at the begin of our kernel ; => Multiboot needs its magic number at the begin of the kernel SECTION .mboot global start start: jmp stublet ; This part MUST be 4byte aligned, so we solve that issue using 'ALIGN 4' ALIGN 4 mboot: ; Multiboot macros to make a few lines more readable later MULTIBOOT_PAGE_ALIGN equ 1<<0 MULTIBOOT_MEMORY_INFO equ 1<<1 ; MULTIBOOT_AOUT_KLUDGE equ 1<<16 MULTIBOOT_HEADER_MAGIC equ 0x1BADB002 MULTIBOOT_HEADER_FLAGS equ MULTIBOOT_PAGE_ALIGN | MULTIBOOT_MEMORY_INFO ; | MULTIBOOT_AOUT_KLUDGE MULTIBOOT_CHECKSUM equ -(MULTIBOOT_HEADER_MAGIC + MULTIBOOT_HEADER_FLAGS) EXTERN code, bss, end ; This is the GRUB Multiboot header. A boot signature dd MULTIBOOT_HEADER_MAGIC dd MULTIBOOT_HEADER_FLAGS dd MULTIBOOT_CHECKSUM ; AOUT kludge - must be physical addresses. Make a note of these: ; The linker script fills in the data for these ones! ; dd mboot ; dd code ; dd bss ; dd end ; dd start extern default_stack_pointer SECTION .text ALIGN 4 stublet: ; initialize stack pointer. mov esp, default_stack_pointer ; enable cache and turn on FPU exceptions mov eax, cr0 ; enable cache and eax, 0x9fffffff ; ...and turn on FPU exceptions or eax, 0x20 mov cr0, eax ; clears the current pgd entry xor eax, eax mov cr3, eax ; interpret multiboot information extern multiboot_init push ebx call multiboot_init add esp, 4 ; jump to the boot processors's C code extern main call main jmp $ ; This will set up our new segment registers. We need to do ; something special in order to set CS. We do what is called a ; far jump. A jump that includes a segment as well as an offset. ; This is declared in C as 'extern void gdt_flush();' global gdt_flush extern gp gdt_flush: lgdt [gp] mov ax, 0x10 mov ds, ax mov es, ax mov fs, ax mov gs, ax mov ss, ax jmp 0x08:flush2 flush2: ret ; Loads the IDT defined in '_idtp' into the processor. ; This is declared in C as 'extern void idt_load();' global idt_load extern idtp idt_load: lidt [idtp] ret global read_eip read_eip: pop eax ; Get the return address jmp eax ; Return. Can't use RET because return ; address popped off the stack. ; In just a few pages in this tutorial, we will add our Interrupt ; Service Routines (ISRs) right here! global isr0 global isr1 global isr2 global isr3 global isr4 global isr5 global isr6 global isr7 global isr8 global isr9 global isr10 global isr11 global isr12 global isr13 global isr14 global isr15 global isr16 global isr17 global isr18 global isr19 global isr20 global isr21 global isr22 global isr23 global isr24 global isr25 global isr26 global isr27 global isr28 global isr29 global isr30 global isr31 global isrsyscall global jump_to_child ; 0: Divide By Zero Exception isr0: ; isr0 - isr31 are registered as "Interrupt Gate" ; Therefore, the interrupt flag (IF) is already cleared. ; cli push byte 0 push byte 0 jmp irq_common_stub ; 1: Debug Exception isr1: ; isr0 - isr31 are registered as "Interrupt Gate" ; Therefore, the interrupt flag (IF) is already cleared. ; cli push byte 0 push byte 1 jmp irq_common_stub ; 2: Non Maskable Interrupt Exception isr2: ; isr0 - isr31 are registered as "Interrupt Gate" ; Therefore, the interrupt flag (IF) is already cleared. ; cli push byte 0 push byte 2 jmp irq_common_stub ; 3: Int 3 Exception isr3: ; isr0 - isr31 are registered as "Interrupt Gate" ; Therefore, the interrupt flag (IF) is already cleared. ; cli push byte 0 push byte 3 jmp irq_common_stub ; 4: INTO Exception isr4: ; isr0 - isr31 are registered as "Interrupt Gate" ; Therefore, the interrupt flag (IF) is already cleared. ; cli push byte 0 push byte 4 jmp irq_common_stub ; 5: Out of Bounds Exception isr5: ; isr0 - isr31 are registered as "Interrupt Gate" ; Therefore, the interrupt flag (IF) is already cleared. ; cli push byte 0 push byte 5 jmp irq_common_stub ; 6: Invalid Opcode Exception isr6: ; isr0 - isr31 are registered as "Interrupt Gate" ; Therefore, the interrupt flag (IF) is already cleared. ; cli push byte 0 push byte 6 jmp irq_common_stub ; 7: Coprocessor Not Available Exception isr7: ; isr0 - isr31 are registered as "Interrupt Gate" ; Therefore, the interrupt flag (IF) is already cleared. ; cli push byte 0 push byte 7 jmp irq_common_stub ; 8: Double Fault Exception (With Error Code!) isr8: ; isr0 - isr31 are registered as "Interrupt Gate" ; Therefore, the interrupt flag (IF) is already cleared. ; cli push byte 8 jmp irq_common_stub ; 9: Coprocessor Segment Overrun Exception isr9: ; isr0 - isr31 are registered as "Interrupt Gate" ; Therefore, the interrupt flag (IF) is already cleared. ; cli push byte 0 push byte 9 jmp irq_common_stub ; 10: Bad TSS Exception (With Error Code!) isr10: ; isr0 - isr31 are registered as "Interrupt Gate" ; Therefore, the interrupt flag (IF) is already cleared. ; cli push byte 10 jmp irq_common_stub ; 11: Segment Not Present Exception (With Error Code!) isr11: ; isr0 - isr31 are registered as "Interrupt Gate" ; Therefore, the interrupt flag (IF) is already cleared. ; cli push byte 11 jmp irq_common_stub ; 12: Stack Fault Exception (With Error Code!) isr12: ; isr0 - isr31 are registered as "Interrupt Gate" ; Therefore, the interrupt flag (IF) is already cleared. ; cli push byte 12 jmp irq_common_stub ; 13: General Protection Fault Exception (With Error Code!) isr13: ; isr0 - isr31 are registered as "Interrupt Gate" ; Therefore, the interrupt flag (IF) is already cleared. ; cli push byte 13 jmp irq_common_stub ; 14: Page Fault Exception (With Error Code!) isr14: ; isr0 - isr31 are registered as "Interrupt Gate" ; Therefore, the interrupt flag (IF) is already cleared. ; cli push byte 14 jmp irq_common_stub ; 15: Reserved Exception isr15: ; isr0 - isr31 are registered as "Interrupt Gate" ; Therefore, the interrupt flag (IF) is already cleared. ; cli push byte 0 push byte 15 jmp irq_common_stub ; 16: Floating Point Exception isr16: ; isr0 - isr31 are registered as "Interrupt Gate" ; Therefore, the interrupt flag (IF) is already cleared. ; cli push byte 0 push byte 16 jmp irq_common_stub ; 17: Alignment Check Exception isr17: ; isr0 - isr31 are registered as "Interrupt Gate" ; Therefore, the interrupt flag (IF) is already cleared. ; cli push byte 0 push byte 17 jmp irq_common_stub ; 18: Machine Check Exception isr18: ; isr0 - isr31 are registered as "Interrupt Gate" ; Therefore, the interrupt flag (IF) is already cleared. ; cli push byte 0 push byte 18 jmp irq_common_stub ; 19: Reserved isr19: ; isr0 - isr31 are registered as "Interrupt Gate" ; Therefore, the interrupt flag (IF) is already cleared. ; cli push byte 0 push byte 19 jmp irq_common_stub ; 20: Reserved isr20: ; isr0 - isr31 are registered as "Interrupt Gate" ; Therefore, the interrupt flag (IF) is already cleared. ; cli push byte 0 push byte 20 jmp irq_common_stub ; 21: Reserved isr21: ; isr0 - isr31 are registered as "Interrupt Gate" ; Therefore, the interrupt flag (IF) is already cleared. ; cli push byte 0 push byte 21 jmp irq_common_stub ; 22: Reserved isr22: ; isr0 - isr31 are registered as "Interrupt Gate" ; Therefore, the interrupt flag (IF) is already cleared. ; cli push byte 0 push byte 22 jmp irq_common_stub ; 23: Reserved isr23: ; isr0 - isr31 are registered as "Interrupt Gate" ; Therefore, the interrupt flag (IF) is already cleared. ; cli push byte 0 push byte 23 jmp irq_common_stub ; 24: Reserved isr24: ; isr0 - isr31 are registered as "Interrupt Gate" ; Therefore, the interrupt flag (IF) is already cleared. ; cli push byte 0 push byte 24 jmp irq_common_stub ; 25: Reserved isr25: ; isr0 - isr31 are registered as "Interrupt Gate" ; Therefore, the interrupt flag (IF) is already cleared. ; cli push byte 0 push byte 25 jmp irq_common_stub ; 26: Reserved isr26: ; isr0 - isr31 are registered as "Interrupt Gate" ; Therefore, the interrupt flag (IF) is already cleared. ; cli push byte 0 push byte 26 jmp irq_common_stub ; 27: Reserved isr27: ; isr0 - isr31 are registered as "Interrupt Gate" ; Therefore, the interrupt flag (IF) is already cleared. ; cli push byte 0 push byte 27 jmp irq_common_stub ; 28: Reserved isr28: ; isr0 - isr31 are registered as "Interrupt Gate" ; Therefore, the interrupt flag (IF) is already cleared. ; cli push byte 0 push byte 28 jmp irq_common_stub ; 29: Reserved isr29: ; isr0 - isr31 are registered as "Interrupt Gate" ; Therefore, the interrupt flag (IF) is already cleared. ; cli push byte 0 push byte 29 jmp irq_common_stub ; 30: Reserved isr30: ; isr0 - isr31 are registered as "Interrupt Gate" ; Therefore, the interrupt flag (IF) is already cleared. ; cli push byte 0 push byte 30 jmp irq_common_stub ; 31: Reserved isr31: ; isr0 - isr31 are registered as "Interrupt Gate" ; Therefore, the interrupt flag (IF) is already cleared. ; cli push byte 0 push byte 31 jmp irq_common_stub extern syscall_handler ; used to realize system calls isrsyscall: push ebp push edi push esi push edx push ecx push ebx push eax call syscall_handler add esp, 4 ; eax contains the return value ; => we did not restore eax pop ebx pop ecx pop edx pop esi pop edi pop ebp iret jump_to_child: add esp, 4 mov eax, 0 ; child got always zero as return value pop ebx pop ecx pop edx pop esi pop edi pop ebp iret global irq0 global irq1 global irq2 global irq3 global irq4 global irq5 global irq6 global irq7 global irq8 global irq9 global irq10 global irq11 global irq12 global irq13 global irq14 global irq15 global irq16 global irq17 global irq18 global irq19 global irq20 global irq21 global irq22 global irq23 global apic_timer global apic_lint0 global apic_lint1 global apic_error global apic_svr extern irq_handler extern get_current_task extern scheduler global reschedule reschedule: cli ; eax could change across a function call ; => so we don't have to save the original eax value push ebx call get_current_task push eax call scheduler call get_current_task pop ebx cmp eax, ebx je no_task_switch1 mov eax, [eax] add ax, WORD 5 mov bx, WORD 8 mul bx mov [hack1+5], ax hack1: jmp 0x00 : 0xDEADBEAF no_task_switch1: pop ebx sti ret ; 32: IRQ0 irq0: ; irq0 - irq15 are registered as "Interrupt Gate" ; Therefore, the interrupt flag (IF) is already cleared. ; cli push byte 0 push byte 32 Lirq0: pusha push esp call irq_handler add esp, 4 call get_current_task push eax call scheduler call get_current_task pop ebx cmp eax, ebx je no_task_switch2 mov eax, [eax] add ax, WORD 5 mov bx, WORD 8 mul bx mov [hack2+5], ax hack2: jmp 0x00 : 0xDEADBEAF no_task_switch2: popa add esp, 8 iret ; 33: IRQ1 irq1: ; irq0 - irq15 are registered as "Interrupt Gate" ; Therefore, the interrupt flag (IF) is already cleared. ; cli push byte 0 push byte 33 jmp irq_common_stub ; 34: IRQ2 irq2: ; irq0 - irq15 are registered as "Interrupt Gate" ; Therefore, the interrupt flag (IF) is already cleared. ; cli push byte 0 push byte 34 jmp irq_common_stub ; 35: IRQ3 irq3: ; irq0 - irq15 are registered as "Interrupt Gate" ; Therefore, the interrupt flag (IF) is already cleared. ; cli push byte 0 push byte 35 jmp irq_common_stub ; 36: IRQ4 irq4: ; irq0 - irq15 are registered as "Interrupt Gate" ; Therefore, the interrupt flag (IF) is already cleared. ; cli push byte 0 push byte 36 jmp irq_common_stub ; 37: IRQ5 irq5: ; irq0 - irq15 are registered as "Interrupt Gate" ; Therefore, the interrupt flag (IF) is already cleared. ; cli push byte 0 push byte 37 jmp irq_common_stub ; 38: IRQ6 irq6: ; irq0 - irq15 are registered as "Interrupt Gate" ; Therefore, the interrupt flag (IF) is already cleared. ; cli push byte 0 push byte 38 jmp irq_common_stub ; 39: IRQ7 irq7: ; irq0 - irq15 are registered as "Interrupt Gate" ; Therefore, the interrupt flag (IF) is already cleared. ; cli push byte 0 push byte 39 jmp irq_common_stub ; 40: IRQ8 irq8: ; irq0 - irq15 are registered as "Interrupt Gate" ; Therefore, the interrupt flag (IF) is already cleared. ; cli push byte 0 push byte 40 jmp irq_common_stub ; 41: IRQ9 irq9: ; irq0 - irq15 are registered as "Interrupt Gate" ; Therefore, the interrupt flag (IF) is already cleared. ; cli push byte 0 push byte 41 jmp irq_common_stub ; 42: IRQ10 irq10: ; irq0 - irq15 are registered as "Interrupt Gate" ; Therefore, the interrupt flag (IF) is already cleared. ; cli push byte 0 push byte 42 jmp irq_common_stub ; 43: IRQ11 irq11: ; irq0 - irq15 are registered as "Interrupt Gate" ; Therefore, the interrupt flag (IF) is already cleared. ; cli push byte 0 push byte 43 jmp irq_common_stub ; 44: IRQ12 irq12: ; irq0 - irq15 are registered as "Interrupt Gate" ; Therefore, the interrupt flag (IF) is already cleared. ; cli push byte 0 push byte 44 jmp irq_common_stub ; 45: IRQ13 irq13: ; irq0 - irq15 are registered as "Interrupt Gate" ; Therefore, the interrupt flag (IF) is already cleared. ; cli push byte 0 push byte 45 jmp irq_common_stub ; 46: IRQ14 irq14: ; irq0 - irq15 are registered as "Interrupt Gate" ; Therefore, the interrupt flag (IF) is already cleared. ; cli push byte 0 push byte 46 jmp irq_common_stub ; 47: IRQ15 irq15: ; irq0 - irq15 are registered as "Interrupt Gate" ; Therefore, the interrupt flag (IF) is already cleared. ; cli push byte 0 push byte 47 jmp irq_common_stub ; 48: IRQ16 irq16: ; irq16 - irq23 are registered as "Interrupt Gate" ; Therefore, the interrupt flag (IF) is already cleared. ; cli push byte 0 push byte 48 jmp irq_common_stub ; 49: IRQ17 irq17: ; irq16- irq23 are registered as "Interrupt Gate" ; Therefore, the interrupt flag (IF) is already cleared. ; cli push byte 0 push byte 49 jmp irq_common_stub ; 50: IRQ18 irq18: ; irq16 - irq23 are registered as "Interrupt Gate" ; Therefore, the interrupt flag (IF) is already cleared. ; cli push byte 0 push byte 50 jmp irq_common_stub ; 51: IRQ19 irq19: ; irq16 - irq23 are registered as "Interrupt Gate" ; Therefore, the interrupt flag (IF) is already cleared. ; cli push byte 0 push byte 51 jmp irq_common_stub ; 52: IRQ20 irq20: ; irq16- irq23 are registered as "Interrupt Gate" ; Therefore, the interrupt flag (IF) is already cleared. ; cli push byte 0 push byte 52 jmp irq_common_stub ; 53: IRQ21 irq21: ; irq16 - irq23 are registered as "Interrupt Gate" ; Therefore, the interrupt flag (IF) is already cleared. ; cli push byte 0 push byte 53 jmp irq_common_stub ; 54: IRQ22 irq22: ; irq16- irq23 are registered as "Interrupt Gate" ; Therefore, the interrupt flag (IF) is already cleared. ; cli push byte 0 push byte 54 jmp irq_common_stub ; 55: IRQ23 irq23: ; irq16 - irq23 are registered as "Interrupt Gate" ; Therefore, the interrupt flag (IF) is already cleared. ; cli push byte 0 push byte 55 jmp irq_common_stub apic_timer: ; apic timer is registered as "Interrupt Gate" ; Therefore, the interrupt flag (IF) is already cleared. ; cli push byte 0 push byte 123 ; we reuse code of the "traditional" timer interrupt (PIC) jmp Lirq0 apic_lint0: ; lint0 is registered as "Interrupt Gate" ; Therefore, the interrupt flag (IF) is already cleared. ; cli push byte 0 push byte 124 jmp irq_common_stub apic_lint1: ; lint1 is registered as "Interrupt Gate" ; Therefore, the interrupt flag (IF) is already cleared. ; cli push byte 0 push byte 125 jmp irq_common_stub apic_error: ; LVT error interrupt is registered as "Interrupt Gate" ; Therefore, the interrupt flag (IF) is already cleared. ; cli push byte 0 push byte 126 jmp irq_common_stub apic_svr: ; SVR is registered as "Interrupt Gate" ; Therefore, the interrupt flag (IF) is already cleared. ; cli push byte 0 push byte 127 jmp irq_common_stub irq_common_stub: pusha push esp call irq_handler add esp, 4 popa add esp, 8 iret SECTION .note.GNU-stack noalloc noexec nowrite progbits