metalsvm/arch/x86/kernel/entry64.asm
2013-10-17 13:09:20 +02:00

1162 lines
27 KiB
NASM

;
; 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 beginning 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 mode
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 ; stack for booting
startup_stack:
SECTION .data
; create default page tables for the 64bit kernel
global boot_pml4
ALIGN 4096 ; of course, the page tables have to be page aligned
MAP_ENTRIES equ 512
boot_pml4 times 512 DQ 0
boot_pdpt times 512 DQ 0
boot_pd times 512 DQ 0
boot_pt times (MAP_ENTRIES*512) DQ 0
SECTION .text
ALIGN 8
%if MAX_CORES > 1
global smp_entry
smp_entry:
; initialize cpu features
call cpu_init
; initialize cr3 register
mov edi, boot_pml4
mov cr3, edi
; enable PAE
mov eax, cr4
or eax, 1 << 5
mov cr4, eax
; enable longmode (compatibility 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 PE-bit, which is the 0th bit.
mov cr0, eax ; According to the multiboot spec the PE-bit has to be set by bootloader already!
; jump to 64-bit longmode
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 MP Floating Pointer Structure
search_mps:
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
check_longmode:
; check for cpuid instruction
pushfd
pop eax
mov ecx, eax
xor eax, 1 << 21
push eax
popfd
pushfd
pop eax
push ecx
popfd
xor eax, ecx
jz .unsupported
; check for extended cpu features (cpuid > 0x80000000)
mov eax, 0x80000000
cpuid
cmp eax, 0x80000001
jb .unsupported ; It is less, there is no long mode.
; check if longmode is supported
mov eax, 0x80000001
cpuid
test edx, 1 << 29 ; Test if the LM-bit, which is bit 29, is set in the D-register.
jz .unsupported ; They aren't, there is no long mode.
ret
.unsupported:
jmp $
check_lapic:
push eax
push ebx
push ecx
push edx
mov eax, 1
cpuid
and edx, 0x200
cmp edx, 0
je .unsupported
; 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 ; LAPIC base address
or ebx, 0x00000013
mov DWORD [edi], ebx
.unsupported:
pop edx
pop ecx
pop ebx
pop eax
ret
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
ALIGN 4
stublet:
mov esp, startup_stack-4
; save pointer to the multiboot structure
push ebx
; initialize cpu features
call cpu_init
; check if longmode is supported
call check_longmode
; check if lapic is available
call check_lapic
; find MP Floating Pointer Structure
push DWORD 0x100000
push DWORD 0xF0000
call search_mps
add esp, 8
cmp eax, 0
jne map_mps
push DWORD 0xA0000
push DWORD 0x9F000
call search_mps
add esp, 8
cmp eax, 0
je map_kernel
map_mps:
; 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
%ifdef CONFIG_VGA
map_vga:
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:
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
map_kernel:
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
.l1:
mov DWORD [edi], ebx ; Set the double word at the destination index to the B-register.
add edi, 8
add ebx, 0x1000
loop .l1
init_paging:
mov edi, boot_pml4
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, MAP_ENTRIES
.l1:
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 .l1
; enable PAE
mov eax, cr4
or eax, 1 << 5
mov cr4, eax
; enable longmode (compatibility 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 PE-bit, which is the 0th bit.
mov cr0, eax
; jump to 64-bit longmode
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.
[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
; 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