; ; 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! %include "config.inc" [BITS 32] extern kernel_start ; defined in linker script extern kernel_end extern apic_mp ; 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 ALIGN 4 ; we need already a valid GDT to switch in the 64bit modus GDT64: ; Global Descriptor Table (64-bit). .Null: equ $ - GDT64 ; The null descriptor. dw 0 ; Limit (low). dw 0 ; Base (low). db 0 ; Base (middle) db 0 ; Access. db 0 ; Granularity. db 0 ; Base (high). .Code: equ $ - GDT64 ; The code descriptor. dw 0 ; Limit (low). dw 0 ; Base (low). db 0 ; Base (middle) db 10011000b ; Access. db 00100000b ; Granularity. db 0 ; Base (high). .Data: equ $ - GDT64 ; The data descriptor. dw 0 ; Limit (low). dw 0 ; Base (low). db 0 ; Base (middle) db 10010010b ; Access. db 00000000b ; Granularity. db 0 ; Base (high). .Pointer: ; The GDT-pointer. dw $ - GDT64 - 1 ; Limit. dq GDT64 ; Base. times 256 DD 0 startup_stack: SECTION .data ; create default page tables for the 64bit kernel global boot_pgd ; aka PML4 ALIGN 4096 ; of course, the page tables have to be page aligned NOPTS equ 512 boot_pgd times 512 DQ 0 boot_pdpt times 512 DQ 0 boot_pd times 512 DQ 0 boot_pt times (NOPTS*512) DQ 0 SECTION .text ALIGN 8 %if MAX_CORES > 1 global smp_entry smp_entry: ; enable caching, disable paging and fpu emulation and eax, 0x1ffffffb ; ...and turn on FPU exceptions or eax, 0x22 mov cr0, eax ; clears the current pgd entry xor eax, eax mov cr3, eax ; at this stage, we disable the SSE support mov eax, cr4 and eax, 0xfffbf9ff mov cr4, eax ; initialize page table mov edi, boot_pgd mov cr3, edi ; we need to enable PAE modus mov eax, cr4 or eax, 1 << 5 mov cr4, eax ; switch to the compatibility mode (which is part of long mode) mov ecx, 0xC0000080 rdmsr or eax, 1 << 8 wrmsr ; enable paging mov eax, cr0 or eax, 1 << 31 | 1 << 0 ; Set the PG-bit, which is the 31nd bit, and the PM-bit, which is the 0th bit. mov cr0, eax mov edi, [esp+4] ; set argumet for smp_start lgdt [GDT64.Pointer] ; Load the 64-bit global descriptor table. jmp GDT64.Code:smp_start64 ; Set the code segment and enter 64-bit long mode. jmp $ ; endless loop %endif search_apic: push ebp mov ebp, esp push ecx xor eax, eax mov ecx, [ebp+8] L1: cmp [ecx], DWORD 0x5f504d5f ; MP_FLT_SIGNATURE jne L2 mov al, BYTE [ecx+9] cmp eax, 4 ja L2 mov al, BYTE [ecx+11] cmp eax, 0 jne L2 mov eax, ecx jmp L3 L2: add ecx, 4 cmp ecx, [ebp+12] jb L1 xor eax, eax L3: pop ecx pop ebp ret ALIGN 4 stublet: mov esp, startup_stack-4 push ebx ; save pointer to the multiboot structure mov eax, cr0 ; enable caching, disable paging and fpu emulation and eax, 0x1ffffffb ; ...and turn on FPU exceptions or eax, 0x22 mov cr0, eax ; clears the current pgd entry xor eax, eax mov cr3, eax ; at this stage, we disable the SSE support mov eax, cr4 and eax, 0xfffbf9ff mov cr4, eax ; do we have the instruction cpuid? pushfd pop eax mov ecx, eax xor eax, 1 << 21 push eax popfd pushfd pop eax push ecx popfd xor eax, ecx jz Linvalid ; cpuid > 0x80000000? mov eax, 0x80000000 cpuid cmp eax, 0x80000001 jb Linvalid ; It is less, there is no long mode. ; do we have a long mode? mov eax, 0x80000001 cpuid test edx, 1 << 29 ; Test if the LM-bit, which is bit 29, is set in the D-register. jz Linvalid ; They aren't, there is no long mode. ; initialize page table mov edi, boot_pgd mov cr3, edi ; So lets make PML4T[0] point to the PDPT and so on: mov DWORD [edi], boot_pdpt ; Set the double word at the destination index to pdpt. or DWORD [edi], 0x00000003 ; Set present and writeable bit mov edi, boot_pdpt mov DWORD [edi], boot_pd ; Set the double word at the destination index to pd. or DWORD [edi], 0x00000003 ; Set present and writeable bit mov edi, boot_pd mov ebx, boot_pt mov ecx, NOPTS L0: mov DWORD [edi], ebx ; Set the double word at the destination index to pt. or DWORD [edi], 0x00000003 ; Set present and writeable bit add edi, 8 add ebx, 0x1000 loop L0 %ifdef CONFIG_VGA ; map the VGA address into the virtual address space mov edi, 0xB8000 shr edi, 9 ; (edi >> 12) * 8 add edi, boot_pt mov ebx, 0xB8000 or ebx, 0x00000013 mov DWORD [edi], ebx %endif ; map multiboot structure into the virtual address space mov edi, [esp] and edi, 0xFFFFF000 shr edi, 9 ; (edi >> 12) * 8 add edi, boot_pt mov ebx, [esp] and ebx, 0xFFFFF000 or ebx, 0x00000003 mov DWORD [edi], ebx ; check if lapic is available push eax push ebx push ecx push edx mov eax, 1 cpuid and edx, 0x200 cmp edx, 0 je no_lapic ; map lapic at 0xFEE00000 below the kernel mov edi, kernel_start - 0x1000 shr edi, 9 ; (edi >> 12) * 8 add edi, boot_pt mov ebx, 0xFEE00000 or ebx, 0x00000013 mov DWORD [edi], ebx no_lapic: pop edx pop ecx pop ebx pop eax ; search APIC push DWORD 0x100000 push DWORD 0xF0000 call search_apic add esp, 8 cmp eax, 0 jne La push DWORD 0xA0000 push DWORD 0x9F000 call search_apic add esp, 8 cmp eax, 0 je Lb La: ; map MP Floating Pointer Structure mov DWORD [apic_mp], eax mov edi, eax and edi, 0xFFFFF000 shr edi, 9 ; (edi >> 12) * 8 add edi, boot_pt mov ebx, eax and ebx, 0xFFFFF000 or ebx, 0x00000013 mov DWORD [edi], ebx ; map mp_config mov edi, [eax+4] and edi, 0xFFFFF000 shr edi, 9 ; (edi >> 12) * 8 add edi, boot_pt mov ebx, [eax+4] and ebx, 0xFFFFF000 or ebx, 0x00000013 mov DWORD [edi], ebx Lb: mov edi, kernel_start shr edi, 9 ; (kernel_start >> 12) * 8 add edi, boot_pt mov ebx, kernel_start or ebx, 0x00000003 mov ecx, kernel_end ; determine kernel size in number of pages sub ecx, kernel_start shr ecx, 12 inc ecx Lc: mov DWORD [edi], ebx ; Set the double word at the destination index to the B-register. add edi, 8 add ebx, 0x1000 loop Lc ; we need to enable PAE modus mov eax, cr4 or eax, 1 << 5 mov cr4, eax ; switch to the compatibility mode (which is part of long mode) mov ecx, 0xC0000080 rdmsr or eax, 1 << 8 wrmsr ; enable paging mov eax, cr0 or eax, 1 << 31 | 1 << 0 ; Set the PG-bit, which is the 31nd bit, and the PM-bit, which is the 0th bit. mov cr0, eax pop ebx ; restore pointer to multiboot structure lgdt [GDT64.Pointer] ; Load the 64-bit global descriptor table. jmp GDT64.Code:start64 ; Set the code segment and enter 64-bit long mode. Linvalid: jmp $ [BITS 64] start64: ; initialize segment registers mov ax, GDT64.Data mov ds, ax mov es, ax mov fs, ax mov gs, ax mov ss, ax ; set default stack pointer mov rsp, boot_stack add rsp, KERNEL_STACK_SIZE-16 ; interpret multiboot information extern multiboot_init mov rdi, rbx call multiboot_init ; jump to the boot processors's C code extern main call main jmp $ %if MAX_CORES > 1 smp_start64: ; initialize segment registers mov ax, GDT64.Data mov ds, ax mov es, ax mov fs, ax mov gs, ax mov ss, ax ; jump to the boot processors's C code extern smp_start call smp_start jmp $ %endif global cpu_init cpu_init: ; mov eax, cr0 ; enable caching, disable paging and fpu emulation ; and eax, 0x1ffffffb ; ...and turn on FPU exceptions ; or eax, 0x22 ; mov cr0, eax ; clears the current pgd entry ; xor eax, eax ; mov cr3, eax ; at this stage, we disable the SSE support ; mov eax, cr4 ; and eax, 0xfffbf9ff ; mov cr4, eax ; ret ; This will set up our new segment registers and is declared in ; C as 'extern void gdt_flush();' global gdt_flush extern gp gdt_flush: lgdt [gp] ret ; determines the current instruction pointer (after the jmp) global read_eip read_eip: pop rax ; Get the return address jmp rax ; 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 ; 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 ; pseudo error code push byte 0 jmp 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 ; pseudo error code push byte 1 jmp 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 ; pseudo error code push byte 2 jmp 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 ; pseudo error code push byte 3 jmp 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 ; pseudo error code push byte 4 jmp 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 ; pseudo error code push byte 5 jmp 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 ; pseudo error code push byte 6 jmp 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 ; pseudo error code push byte 7 jmp 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 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 ; pseudo error code push byte 9 jmp 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 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 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 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 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 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 ; pseudo error code push byte 15 jmp 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 ; pseudo error code push byte 16 jmp 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 17 jmp 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 ; pseudo error code push byte 18 jmp common_stub ; 19: Reserved isr19: ; isr0 - isr31 are registered as "Interrupt Gate" ; Therefore, the interrupt flag (IF) is already cleared. ; cli push byte 0 ; pseudo error code push byte 19 jmp common_stub ; 20: Reserved isr20: ; isr0 - isr31 are registered as "Interrupt Gate" ; Therefore, the interrupt flag (IF) is already cleared. ; cli push byte 0 ; pseudo error code push byte 20 jmp common_stub ; 21: Reserved isr21: ; isr0 - isr31 are registered as "Interrupt Gate" ; Therefore, the interrupt flag (IF) is already cleared. ; cli push byte 0 ; pseudo error code push byte 21 jmp common_stub ; 22: Reserved isr22: ; isr0 - isr31 are registered as "Interrupt Gate" ; Therefore, the interrupt flag (IF) is already cleared. ; cli push byte 0 ; pseudo error code push byte 22 jmp common_stub ; 23: Reserved isr23: ; isr0 - isr31 are registered as "Interrupt Gate" ; Therefore, the interrupt flag (IF) is already cleared. ; cli push byte 0 ; pseudo error code push byte 23 jmp common_stub ; 24: Reserved isr24: ; isr0 - isr31 are registered as "Interrupt Gate" ; Therefore, the interrupt flag (IF) is already cleared. ; cli push byte 0 ; pseudo error code push byte 24 jmp common_stub ; 25: Reserved isr25: ; isr0 - isr31 are registered as "Interrupt Gate" ; Therefore, the interrupt flag (IF) is already cleared. ; cli push byte 0 ; pseudo error code push byte 25 jmp common_stub ; 26: Reserved isr26: ; isr0 - isr31 are registered as "Interrupt Gate" ; Therefore, the interrupt flag (IF) is already cleared. ; cli push byte 0 ; pseudo error code push byte 26 jmp common_stub ; 27: Reserved isr27: ; isr0 - isr31 are registered as "Interrupt Gate" ; Therefore, the interrupt flag (IF) is already cleared. ; cli push byte 0 ; pseudo error code push byte 27 jmp common_stub ; 28: Reserved isr28: ; isr0 - isr31 are registered as "Interrupt Gate" ; Therefore, the interrupt flag (IF) is already cleared. ; cli push byte 0 ; pseudo error code push byte 28 jmp common_stub ; 29: Reserved isr29: ; isr0 - isr31 are registered as "Interrupt Gate" ; Therefore, the interrupt flag (IF) is already cleared. ; cli push byte 0 ; pseudo error code push byte 29 jmp common_stub ; 30: Reserved isr30: ; isr0 - isr31 are registered as "Interrupt Gate" ; Therefore, the interrupt flag (IF) is already cleared. ; cli push byte 0 ; pseudo error code push byte 30 jmp common_stub ; 31: Reserved isr31: ; isr0 - isr31 are registered as "Interrupt Gate" ; Therefore, the interrupt flag (IF) is already cleared. ; cli push byte 0 ; pseudo error code push byte 31 jmp common_stub extern syscall_handler ; used to realize system calls isrsyscall: push r15 push r14 push r13 push r12 push r11 push r10 push r9 push r8 push rdi push rsi push rbp push rsp push rbx push rdx push rcx push rax mov rdi, rsp call syscall_handler pop rax pop rcx pop rdx pop rbx add rsp, 8 pop rbp pop rsi pop rdi pop r8 pop r9 pop r10 pop r11 pop r12 pop r13 pop r14 iretq 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 ; 32: IRQ0 irq0: ; irq0 - irq15 are registered as "Interrupt Gate" ; Therefore, the interrupt flag (IF) is already cleared. ; cli push byte 0 ; pseudo error code push byte 32 jmp common_stub ; 33: IRQ1 irq1: ; irq0 - irq15 are registered as "Interrupt Gate" ; Therefore, the interrupt flag (IF) is already cleared. ; cli push byte 0 ; pseudo error code push byte 33 jmp common_stub ; 34: IRQ2 irq2: ; irq0 - irq15 are registered as "Interrupt Gate" ; Therefore, the interrupt flag (IF) is already cleared. ; cli push byte 0 ; pseudo error code push byte 34 jmp common_stub ; 35: IRQ3 irq3: ; irq0 - irq15 are registered as "Interrupt Gate" ; Therefore, the interrupt flag (IF) is already cleared. ; cli push byte 0 ; pseudo error code push byte 35 jmp common_stub ; 36: IRQ4 irq4: ; irq0 - irq15 are registered as "Interrupt Gate" ; Therefore, the interrupt flag (IF) is already cleared. ; cli push byte 0 ; pseudo error code push byte 36 jmp common_stub ; 37: IRQ5 irq5: ; irq0 - irq15 are registered as "Interrupt Gate" ; Therefore, the interrupt flag (IF) is already cleared. ; cli push byte 0 ; pseudo error code push byte 37 jmp common_stub ; 38: IRQ6 irq6: ; irq0 - irq15 are registered as "Interrupt Gate" ; Therefore, the interrupt flag (IF) is already cleared. ; cli push byte 0 ; pseudo error code push byte 38 jmp common_stub ; 39: IRQ7 irq7: ; irq0 - irq15 are registered as "Interrupt Gate" ; Therefore, the interrupt flag (IF) is already cleared. ; cli push byte 0 ; pseudo error code push byte 39 jmp common_stub ; 40: IRQ8 irq8: ; irq0 - irq15 are registered as "Interrupt Gate" ; Therefore, the interrupt flag (IF) is already cleared. ; cli push byte 0 ; pseudo error code push byte 40 jmp common_stub ; 41: IRQ9 irq9: ; irq0 - irq15 are registered as "Interrupt Gate" ; Therefore, the interrupt flag (IF) is already cleared. ; cli push byte 0 ; pseudo error code push byte 41 jmp common_stub ; 42: IRQ10 irq10: ; irq0 - irq15 are registered as "Interrupt Gate" ; Therefore, the interrupt flag (IF) is already cleared. ; cli push byte 0 ; pseudo error code push byte 42 jmp common_stub ; 43: IRQ11 irq11: ; irq0 - irq15 are registered as "Interrupt Gate" ; Therefore, the interrupt flag (IF) is already cleared. ; cli push byte 0 ; pseudo error code push byte 43 jmp common_stub ; 44: IRQ12 irq12: ; irq0 - irq15 are registered as "Interrupt Gate" ; Therefore, the interrupt flag (IF) is already cleared. ; cli push byte 0 ; pseudo error code push byte 44 jmp common_stub ; 45: IRQ13 irq13: ; irq0 - irq15 are registered as "Interrupt Gate" ; Therefore, the interrupt flag (IF) is already cleared. ; cli push byte 0 ; pseudo error code push byte 45 jmp common_stub ; 46: IRQ14 irq14: ; irq0 - irq15 are registered as "Interrupt Gate" ; Therefore, the interrupt flag (IF) is already cleared. ; cli push byte 0 ; pseudo error code push byte 46 jmp common_stub ; 47: IRQ15 irq15: ; irq0 - irq15 are registered as "Interrupt Gate" ; Therefore, the interrupt flag (IF) is already cleared. ; cli push byte 0 ; pseudo error code push byte 47 jmp common_stub ; 48: IRQ16 irq16: ; irq16 - irq23 are registered as "Interrupt Gate" ; Therefore, the interrupt flag (IF) is already cleared. ; cli push byte 0 ; pseudo error code push byte 48 jmp common_stub ; 49: IRQ17 irq17: ; irq16- irq23 are registered as "Interrupt Gate" ; Therefore, the interrupt flag (IF) is already cleared. ; cli push byte 0 ; pseudo error code push byte 49 jmp common_stub ; 50: IRQ18 irq18: ; irq16 - irq23 are registered as "Interrupt Gate" ; Therefore, the interrupt flag (IF) is already cleared. ; cli push byte 0 ; pseudo error code push byte 50 jmp common_stub ; 51: IRQ19 irq19: ; irq16 - irq23 are registered as "Interrupt Gate" ; Therefore, the interrupt flag (IF) is already cleared. ; cli push byte 0 ; pseudo error code push byte 51 jmp common_stub ; 52: IRQ20 irq20: ; irq16- irq23 are registered as "Interrupt Gate" ; Therefore, the interrupt flag (IF) is already cleared. ; cli push byte 0 ; pseudo error code push byte 52 jmp common_stub ; 53: IRQ21 irq21: ; irq16 - irq23 are registered as "Interrupt Gate" ; Therefore, the interrupt flag (IF) is already cleared. ; cli push byte 0 ; error code push byte 53 jmp common_stub ; 54: IRQ22 irq22: ; irq16- irq23 are registered as "Interrupt Gate" ; Therefore, the interrupt flag (IF) is already cleared. ; cli push byte 0 ; pseudo error code push byte 54 jmp common_stub ; 55: IRQ23 irq23: ; irq16 - irq23 are registered as "Interrupt Gate" ; Therefore, the interrupt flag (IF) is already cleared. ; cli push byte 0 ; pseudo error code push byte 55 jmp common_stub apic_timer: ; apic timer is registered as "Interrupt Gate" ; Therefore, the interrupt flag (IF) is already cleared. ; cli push byte 0 ; pseudo error code push byte 123 jmp common_stub apic_lint0: ; lint0 is registered as "Interrupt Gate" ; Therefore, the interrupt flag (IF) is already cleared. ; cli push byte 0 ; pseudo error code push byte 124 jmp common_stub apic_lint1: ; lint1 is registered as "Interrupt Gate" ; Therefore, the interrupt flag (IF) is already cleared. ; cli push byte 0 ; pseudo error code push byte 125 jmp common_stub apic_error: ; LVT error interrupt is registered as "Interrupt Gate" ; Therefore, the interrupt flag (IF) is already cleared. ; cli push byte 0 ; pseudo error code push byte 126 jmp common_stub apic_svr: ; SVR is registered as "Interrupt Gate" ; Therefore, the interrupt flag (IF) is already cleared. ; cli push byte 0 ; pseudo error code push byte 127 jmp common_stub extern irq_handler extern get_current_stack extern finish_task_switch global switch_context ALIGN 8 switch_context: ; create on the stack a pseudo interrupt ; afterwards, we switch to the task with iret mov rax, rdi ; rdi contains the address to store the old rsp push QWORD 0x10 ; SS push rsp ; RSP add QWORD [rsp], 8*1 pushf ; RFLAGS push QWORD 0x08 ; CS push QWORD rollback ; RIP push QWORD 0x00 ; Interrupt number push QWORD 0x00edbabe ; Error code push rax push rcx push rdx push rbx push rsp push rbp push rsi push rdi push r8 push r9 push r10 push r11 push r12 push r13 push r14 push r15 jmp common_switch ALIGN 8 rollback: ret ALIGN 8 common_stub: push rax push rcx push rdx push rbx push rsp push rbp push rsi push rdi push r8 push r9 push r10 push r11 push r12 push r13 push r14 push r15 ; use the same handler for interrupts and exceptions mov rdi, rsp call irq_handler cmp rax, 0 je no_context_switch common_switch: mov [rax], rsp ; store old rsp call get_current_stack ; get new rsp xchg rax, rsp ; set task switched flag mov rax, cr0 or eax, 8 mov cr0, rax ; call cleanup code call finish_task_switch no_context_switch: pop r15 pop r14 pop r13 pop r12 pop r11 pop r10 pop r9 pop r8 pop rdi pop rsi pop rbp add rsp, 8 pop rbx pop rdx pop rcx pop rax add rsp, 16 iretq SECTION .data global boot_stack ALIGN 4096 boot_stack: TIMES (MAX_CORES*KERNEL_STACK_SIZE) DB 0xcd SECTION .note.GNU-stack noalloc noexec nowrite progbits