metalsvm/arch/x86/kernel/entry64.asm

1163 lines
27 KiB
NASM
Raw Permalink Normal View History

;
; 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.
2014-01-09 13:41:22 +01:00
times 256 DD 0 ; Stack for booting
startup_stack:
SECTION .data
2014-01-09 13:41:22 +01:00
; Create default page tables for the 64bit kernel
global boot_pml4
ALIGN 4096 ; of course, the page tables have to be page aligned
PAGE_MAP_ENTRIES equ (1<<9)
PAGE_SIZE equ (1<<12)
boot_pml4 times PAGE_MAP_ENTRIES DQ 0
boot_pdpt times PAGE_MAP_ENTRIES DQ 0
boot_pgd times PAGE_MAP_ENTRIES DQ 0
boot_pgt times (KERNEL_SPACE/PAGE_SIZE) DQ 0
SECTION .text
2012-06-12 23:42:02 +02:00
ALIGN 8
%if MAX_CORES > 1
2012-06-12 23:42:02 +02:00
global smp_entry
smp_entry:
2014-01-09 13:41:22 +01:00
; Initialize cpu features
call cpu_init
2014-01-09 13:41:22 +01:00
; Initialize cr3 register
mov edi, boot_pml4
2012-06-12 23:42:02 +02:00
mov cr3, edi
2014-01-09 13:41:22 +01:00
; Enable PAE
2012-06-12 23:42:02 +02:00
mov eax, cr4
or eax, 1 << 5
mov cr4, eax
2014-01-09 13:41:22 +01:00
; Enable longmode (compatibility mode)
2012-06-12 23:42:02 +02:00
mov ecx, 0xC0000080
rdmsr
or eax, 1 << 8
wrmsr
2014-01-09 13:41:22 +01:00
; Enable paging
2012-06-12 23:42:02 +02:00
mov eax, cr0
2014-01-09 13:41:22 +01:00
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!
2012-06-12 23:42:02 +02:00
2014-01-09 13:41:22 +01:00
; Jump to 64-bit longmode
mov edi, [esp+4] ; Set argumet for smp_start
2012-06-12 23:42:02 +02:00
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
2012-06-12 23:42:02 +02:00
2014-01-09 13:41:22 +01:00
; 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:
2014-01-09 13:41:22 +01:00
; 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
2014-01-09 13:41:22 +01:00
; Check for extended cpu features (cpuid > 0x80000000)
mov eax, 0x80000000
cpuid
cmp eax, 0x80000001
jb .unsupported ; It is less, there is no long mode.
2014-01-09 13:41:22 +01:00
; 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:
2012-06-10 21:38:01 +02:00
push eax
push ebx
push ecx
push edx
mov eax, 1
cpuid
and edx, 0x200
cmp edx, 0
je .unsupported
2014-01-09 13:41:22 +01:00
; Map lapic at 0xFEE00000 below the kernel
mov edi, kernel_start - 0x1000
2012-06-10 21:38:01 +02:00
shr edi, 9 ; (edi >> 12) * 8
add edi, boot_pgt
mov ebx, 0xFEE00000 ; LAPIC base address
2012-06-10 21:38:01 +02:00
or ebx, 0x00000013
mov DWORD [edi], ebx
.unsupported:
2012-06-10 21:38:01 +02:00
pop edx
pop ecx
pop ebx
pop eax
ret
2012-06-10 21:38:01 +02:00
cpu_init:
mov eax, cr0
2014-01-09 13:41:22 +01:00
; Enable caching, disable paging and fpu emulation
and eax, 0x1ffffffb
; ...and turn on FPU exceptions
or eax, 0x22
mov cr0, eax
2014-01-09 13:41:22 +01:00
; Clear 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
2014-01-09 13:41:22 +01:00
; Identity map a single page at address eax
identity_page:
push edi
push ebx
mov edi, eax
2014-01-09 13:41:22 +01:00
and edi, 0xFFFFF000 ; page align in lower half
shr edi, 9 ; (edi >> 12) * 8 (index for boot_pgt)
add edi, boot_pgt
mov ebx, eax
2014-01-09 13:41:22 +01:00
and ebx, 0xFFFFF000 ; page align lower half
or ebx, 0x113 ; set present, global, writable and cache disable bits
mov DWORD [edi], ebx
2014-01-09 13:41:22 +01:00
mov DWORD [edi+4], 0x80000000 ; set execution disable bit in higher half
pop ebx
pop edi
ret
ALIGN 4
stublet:
2013-10-17 13:09:20 +02:00
mov esp, startup_stack-4
2014-01-09 13:41:22 +01:00
; Save pointer to the Multiboot structure
push ebx
2014-01-09 13:41:22 +01:00
; Initialize cpu features
call cpu_init
2014-01-09 13:41:22 +01:00
; Check if longmode is supported
call check_longmode
2014-01-09 13:41:22 +01:00
; Check if lapic is available
call check_lapic
2014-01-09 13:41:22 +01:00
; 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:
2014-01-09 13:41:22 +01:00
; Map MP Floating Pointer structure
mov DWORD [apic_mp], eax
call identity_page
2014-01-09 13:41:22 +01:00
; Map MP Configuration table
mov eax, [eax+4] ; Offset for physical address of MP table
call identity_page
%ifdef CONFIG_VGA
2014-01-09 13:41:22 +01:00
; Map VGA textmode plane
mov eax, 0xB8000
call identity_page
%endif
2014-01-09 13:41:22 +01:00
; Map Multiboot structure
mov eax, [esp] ; Pointer is still on the stack
call identity_page
map_kernel:
mov edi, kernel_start
shr edi, 9 ; (edi >> 12) * 8 (index for boot_pgt)
add edi, boot_pgt
mov ebx, kernel_start
or ebx, 0x103 ; set present, global and writable flags
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
add edi, 8
add ebx, 0x1000
loop .l1
init_paging:
mov edi, boot_pml4
mov cr3, edi
mov DWORD [edi], boot_pdpt
2014-01-09 13:41:22 +01:00
or DWORD [edi], 0x03 ; Set present and writable flags
mov edi, boot_pdpt
mov DWORD [edi], boot_pgd
2014-01-09 13:41:22 +01:00
or DWORD [edi], 0x03 ; Set present and writable flags
mov edi, boot_pgd
mov ebx, boot_pgt
2014-01-09 13:41:22 +01:00
mov ecx, PAGE_MAP_ENTRIES ; Map all boot_pgt to the kernel space
.l1:
mov DWORD [edi], ebx
2014-01-09 13:41:22 +01:00
or DWORD [edi], 0x03 ; Set present and writable flags
add edi, 8
add ebx, 0x1000
loop .l1
2014-01-09 13:41:22 +01:00
; Enable PAE
mov eax, cr4
or eax, 1 << 5
mov cr4, eax
2014-01-09 13:41:22 +01:00
; Enable longmode (compatibility mode)
mov ecx, 0xC0000080
rdmsr
or eax, (1 << 8) | (1 << 11) ; IA32_EFER.LME = 1, IA32_EFER.NXE = 1
wrmsr
2014-01-09 13:41:22 +01:00
; 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
2014-01-09 13:41:22 +01:00
; 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:
2014-01-09 13:41:22 +01:00
; Initialize segment registers
mov ax, GDT64.Data
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
mov ss, ax
2014-01-09 13:41:22 +01:00
; Set default stack pointer
mov rsp, boot_stack
add rsp, KERNEL_STACK_SIZE-16
2014-01-09 13:41:22 +01:00
; Interpret multiboot information
extern multiboot_init
mov rdi, rbx
call multiboot_init
2014-01-09 13:41:22 +01:00
; Jump to the boot processors's C code
extern main
call main
jmp $
%if MAX_CORES > 1
2012-06-12 23:42:02 +02:00
smp_start64:
2014-01-09 13:41:22 +01:00
; Initialize segment registers
2012-06-12 23:42:02 +02:00
mov ax, GDT64.Data
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
mov ss, ax
2014-01-09 13:41:22 +01:00
; Jump to the boot processors's C code
2012-06-12 23:42:02 +02:00
extern smp_start
call smp_start
jmp $
%endif
2012-06-12 23:42:02 +02:00
; 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
2011-04-08 10:45:26 -07:00
; 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
2011-07-30 17:28:09 +02:00
push byte 0 ; pseudo error code
push byte 0
2011-07-30 17:28:09 +02:00
jmp common_stub
; 1: Debug Exception
isr1:
; isr0 - isr31 are registered as "Interrupt Gate"
; Therefore, the interrupt flag (IF) is already cleared.
; cli
2011-07-30 17:28:09 +02:00
push byte 0 ; pseudo error code
push byte 1
2011-07-30 17:28:09 +02:00
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
2011-07-30 17:28:09 +02:00
push byte 0 ; pseudo error code
push byte 2
2011-07-30 17:28:09 +02:00
jmp common_stub
; 3: Int 3 Exception
isr3:
; isr0 - isr31 are registered as "Interrupt Gate"
; Therefore, the interrupt flag (IF) is already cleared.
; cli
2011-07-30 17:28:09 +02:00
push byte 0 ; pseudo error code
push byte 3
2011-07-30 17:28:09 +02:00
jmp common_stub
; 4: INTO Exception
isr4:
; isr0 - isr31 are registered as "Interrupt Gate"
; Therefore, the interrupt flag (IF) is already cleared.
; cli
2011-07-30 17:28:09 +02:00
push byte 0 ; pseudo error code
push byte 4
2011-07-30 17:28:09 +02:00
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
2011-07-30 17:28:09 +02:00
push byte 0 ; pseudo error code
push byte 5
2011-07-30 17:28:09 +02:00
jmp common_stub
; 6: Invalid Opcode Exception
isr6:
; isr0 - isr31 are registered as "Interrupt Gate"
; Therefore, the interrupt flag (IF) is already cleared.
; cli
2011-07-30 17:28:09 +02:00
push byte 0 ; pseudo error code
push byte 6
2011-07-30 17:28:09 +02:00
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
2011-07-30 17:28:09 +02:00
push byte 0 ; pseudo error code
push byte 7
2011-07-30 17:28:09 +02:00
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
2011-07-30 17:28:09 +02:00
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
2011-07-30 17:28:09 +02:00
push byte 0 ; pseudo error code
push byte 9
2011-07-30 17:28:09 +02:00
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
2011-07-30 17:28:09 +02:00
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
2011-07-30 17:28:09 +02:00
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
2011-07-30 17:28:09 +02:00
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
2011-07-30 17:28:09 +02:00
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
2011-07-30 17:28:09 +02:00
jmp common_stub
; 15: Reserved Exception
isr15:
; isr0 - isr31 are registered as "Interrupt Gate"
; Therefore, the interrupt flag (IF) is already cleared.
; cli
2011-07-30 17:28:09 +02:00
push byte 0 ; pseudo error code
push byte 15
2011-07-30 17:28:09 +02:00
jmp common_stub
; 16: Floating Point Exception
isr16:
; isr0 - isr31 are registered as "Interrupt Gate"
; Therefore, the interrupt flag (IF) is already cleared.
; cli
2011-07-30 17:28:09 +02:00
push byte 0 ; pseudo error code
push byte 16
2011-07-30 17:28:09 +02:00
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
2011-07-30 17:28:09 +02:00
jmp common_stub
; 18: Machine Check Exception
isr18:
; isr0 - isr31 are registered as "Interrupt Gate"
; Therefore, the interrupt flag (IF) is already cleared.
; cli
2011-07-30 17:28:09 +02:00
push byte 0 ; pseudo error code
push byte 18
2011-07-30 17:28:09 +02:00
jmp common_stub
; 19: Reserved
isr19:
; isr0 - isr31 are registered as "Interrupt Gate"
; Therefore, the interrupt flag (IF) is already cleared.
; cli
2011-07-30 17:28:09 +02:00
push byte 0 ; pseudo error code
push byte 19
2011-07-30 17:28:09 +02:00
jmp common_stub
; 20: Reserved
isr20:
; isr0 - isr31 are registered as "Interrupt Gate"
; Therefore, the interrupt flag (IF) is already cleared.
; cli
2011-07-30 17:28:09 +02:00
push byte 0 ; pseudo error code
push byte 20
2011-07-30 17:28:09 +02:00
jmp common_stub
; 21: Reserved
isr21:
; isr0 - isr31 are registered as "Interrupt Gate"
; Therefore, the interrupt flag (IF) is already cleared.
; cli
2011-07-30 17:28:09 +02:00
push byte 0 ; pseudo error code
push byte 21
2011-07-30 17:28:09 +02:00
jmp common_stub
; 22: Reserved
isr22:
; isr0 - isr31 are registered as "Interrupt Gate"
; Therefore, the interrupt flag (IF) is already cleared.
; cli
2011-07-30 17:28:09 +02:00
push byte 0 ; pseudo error code
push byte 22
2011-07-30 17:28:09 +02:00
jmp common_stub
; 23: Reserved
isr23:
; isr0 - isr31 are registered as "Interrupt Gate"
; Therefore, the interrupt flag (IF) is already cleared.
; cli
2011-07-30 17:28:09 +02:00
push byte 0 ; pseudo error code
push byte 23
2011-07-30 17:28:09 +02:00
jmp common_stub
; 24: Reserved
isr24:
; isr0 - isr31 are registered as "Interrupt Gate"
; Therefore, the interrupt flag (IF) is already cleared.
; cli
2011-07-30 17:28:09 +02:00
push byte 0 ; pseudo error code
push byte 24
2011-07-30 17:28:09 +02:00
jmp common_stub
; 25: Reserved
isr25:
; isr0 - isr31 are registered as "Interrupt Gate"
; Therefore, the interrupt flag (IF) is already cleared.
; cli
2011-07-30 17:28:09 +02:00
push byte 0 ; pseudo error code
push byte 25
2011-07-30 17:28:09 +02:00
jmp common_stub
; 26: Reserved
isr26:
; isr0 - isr31 are registered as "Interrupt Gate"
; Therefore, the interrupt flag (IF) is already cleared.
; cli
2011-07-30 17:28:09 +02:00
push byte 0 ; pseudo error code
push byte 26
2011-07-30 17:28:09 +02:00
jmp common_stub
; 27: Reserved
isr27:
; isr0 - isr31 are registered as "Interrupt Gate"
; Therefore, the interrupt flag (IF) is already cleared.
; cli
2011-07-30 17:28:09 +02:00
push byte 0 ; pseudo error code
push byte 27
2011-07-30 17:28:09 +02:00
jmp common_stub
; 28: Reserved
isr28:
; isr0 - isr31 are registered as "Interrupt Gate"
; Therefore, the interrupt flag (IF) is already cleared.
; cli
2011-07-30 17:28:09 +02:00
push byte 0 ; pseudo error code
push byte 28
2011-07-30 17:28:09 +02:00
jmp common_stub
; 29: Reserved
isr29:
; isr0 - isr31 are registered as "Interrupt Gate"
; Therefore, the interrupt flag (IF) is already cleared.
; cli
2011-07-30 17:28:09 +02:00
push byte 0 ; pseudo error code
push byte 29
2011-07-30 17:28:09 +02:00
jmp common_stub
; 30: Reserved
isr30:
; isr0 - isr31 are registered as "Interrupt Gate"
; Therefore, the interrupt flag (IF) is already cleared.
; cli
2011-07-30 17:28:09 +02:00
push byte 0 ; pseudo error code
push byte 30
2011-07-30 17:28:09 +02:00
jmp common_stub
; 31: Reserved
isr31:
; isr0 - isr31 are registered as "Interrupt Gate"
; Therefore, the interrupt flag (IF) is already cleared.
; cli
2011-07-30 17:28:09 +02:00
push byte 0 ; pseudo error code
push byte 31
2011-07-30 17:28:09 +02:00
jmp common_stub
extern syscall_handler
; used to realize system calls
isrsyscall:
cli ; disable interrupts during prologue
; save caller saved registers
push r11
push r10
push r9
push r8
push rdi
push rsi
push rdx
push rcx
; set kernel data segmenets
mov ax, 0x10
mov ds, ax
; x86-64 ABI calling convention
mov r8, rbx
mov r9, rax
mov rax, 0 ; we've not used vector registers for this va_arg call
sti ; enable interrupts during syscall
call syscall_handler
cli ; disable interrupts during prologue
; restore caller saved registers
pop rcx
pop rdx
pop rsi
pop rdi
pop r8
pop r9
pop r10
pop r11
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
2011-07-30 17:28:09 +02:00
push byte 0 ; pseudo error code
push byte 32
2011-07-30 17:28:09 +02:00
jmp common_stub
; 33: IRQ1
irq1:
; irq0 - irq15 are registered as "Interrupt Gate"
; Therefore, the interrupt flag (IF) is already cleared.
; cli
2011-07-30 17:28:09 +02:00
push byte 0 ; pseudo error code
push byte 33
2011-07-30 17:28:09 +02:00
jmp common_stub
; 34: IRQ2
irq2:
; irq0 - irq15 are registered as "Interrupt Gate"
; Therefore, the interrupt flag (IF) is already cleared.
; cli
2011-07-30 17:28:09 +02:00
push byte 0 ; pseudo error code
push byte 34
2011-07-30 17:28:09 +02:00
jmp common_stub
; 35: IRQ3
irq3:
; irq0 - irq15 are registered as "Interrupt Gate"
; Therefore, the interrupt flag (IF) is already cleared.
; cli
2011-07-30 17:28:09 +02:00
push byte 0 ; pseudo error code
push byte 35
2011-07-30 17:28:09 +02:00
jmp common_stub
; 36: IRQ4
irq4:
; irq0 - irq15 are registered as "Interrupt Gate"
; Therefore, the interrupt flag (IF) is already cleared.
; cli
2011-07-30 17:28:09 +02:00
push byte 0 ; pseudo error code
push byte 36
2011-07-30 17:28:09 +02:00
jmp common_stub
; 37: IRQ5
irq5:
; irq0 - irq15 are registered as "Interrupt Gate"
; Therefore, the interrupt flag (IF) is already cleared.
; cli
2011-07-30 17:28:09 +02:00
push byte 0 ; pseudo error code
push byte 37
2011-07-30 17:28:09 +02:00
jmp common_stub
; 38: IRQ6
irq6:
; irq0 - irq15 are registered as "Interrupt Gate"
; Therefore, the interrupt flag (IF) is already cleared.
; cli
2011-07-30 17:28:09 +02:00
push byte 0 ; pseudo error code
push byte 38
2011-07-30 17:28:09 +02:00
jmp common_stub
; 39: IRQ7
irq7:
; irq0 - irq15 are registered as "Interrupt Gate"
; Therefore, the interrupt flag (IF) is already cleared.
; cli
2011-07-30 17:28:09 +02:00
push byte 0 ; pseudo error code
push byte 39
2011-07-30 17:28:09 +02:00
jmp common_stub
; 40: IRQ8
irq8:
; irq0 - irq15 are registered as "Interrupt Gate"
; Therefore, the interrupt flag (IF) is already cleared.
; cli
2011-07-30 17:28:09 +02:00
push byte 0 ; pseudo error code
push byte 40
2011-07-30 17:28:09 +02:00
jmp common_stub
; 41: IRQ9
irq9:
; irq0 - irq15 are registered as "Interrupt Gate"
; Therefore, the interrupt flag (IF) is already cleared.
; cli
2011-07-30 17:28:09 +02:00
push byte 0 ; pseudo error code
push byte 41
2011-07-30 17:28:09 +02:00
jmp common_stub
; 42: IRQ10
irq10:
; irq0 - irq15 are registered as "Interrupt Gate"
; Therefore, the interrupt flag (IF) is already cleared.
; cli
2011-07-30 17:28:09 +02:00
push byte 0 ; pseudo error code
push byte 42
2011-07-30 17:28:09 +02:00
jmp common_stub
; 43: IRQ11
irq11:
; irq0 - irq15 are registered as "Interrupt Gate"
; Therefore, the interrupt flag (IF) is already cleared.
; cli
2011-07-30 17:28:09 +02:00
push byte 0 ; pseudo error code
push byte 43
2011-07-30 17:28:09 +02:00
jmp common_stub
; 44: IRQ12
irq12:
; irq0 - irq15 are registered as "Interrupt Gate"
; Therefore, the interrupt flag (IF) is already cleared.
; cli
2011-07-30 17:28:09 +02:00
push byte 0 ; pseudo error code
push byte 44
2011-07-30 17:28:09 +02:00
jmp common_stub
; 45: IRQ13
irq13:
; irq0 - irq15 are registered as "Interrupt Gate"
; Therefore, the interrupt flag (IF) is already cleared.
; cli
2011-07-30 17:28:09 +02:00
push byte 0 ; pseudo error code
push byte 45
2011-07-30 17:28:09 +02:00
jmp common_stub
; 46: IRQ14
irq14:
; irq0 - irq15 are registered as "Interrupt Gate"
; Therefore, the interrupt flag (IF) is already cleared.
; cli
2011-07-30 17:28:09 +02:00
push byte 0 ; pseudo error code
push byte 46
2011-07-30 17:28:09 +02:00
jmp common_stub
; 47: IRQ15
irq15:
; irq0 - irq15 are registered as "Interrupt Gate"
; Therefore, the interrupt flag (IF) is already cleared.
; cli
2011-07-30 17:28:09 +02:00
push byte 0 ; pseudo error code
push byte 47
2011-07-30 17:28:09 +02:00
jmp common_stub
; 48: IRQ16
irq16:
; irq16 - irq23 are registered as "Interrupt Gate"
; Therefore, the interrupt flag (IF) is already cleared.
; cli
2011-07-30 17:28:09 +02:00
push byte 0 ; pseudo error code
push byte 48
2011-07-30 17:28:09 +02:00
jmp common_stub
; 49: IRQ17
irq17:
; irq16- irq23 are registered as "Interrupt Gate"
; Therefore, the interrupt flag (IF) is already cleared.
; cli
2011-07-30 17:28:09 +02:00
push byte 0 ; pseudo error code
push byte 49
2011-07-30 17:28:09 +02:00
jmp common_stub
; 50: IRQ18
irq18:
; irq16 - irq23 are registered as "Interrupt Gate"
; Therefore, the interrupt flag (IF) is already cleared.
; cli
2011-07-30 17:28:09 +02:00
push byte 0 ; pseudo error code
push byte 50
2011-07-30 17:28:09 +02:00
jmp common_stub
; 51: IRQ19
irq19:
; irq16 - irq23 are registered as "Interrupt Gate"
; Therefore, the interrupt flag (IF) is already cleared.
; cli
2011-07-30 17:28:09 +02:00
push byte 0 ; pseudo error code
push byte 51
2011-07-30 17:28:09 +02:00
jmp common_stub
; 52: IRQ20
irq20:
; irq16- irq23 are registered as "Interrupt Gate"
; Therefore, the interrupt flag (IF) is already cleared.
; cli
2011-07-30 17:28:09 +02:00
push byte 0 ; pseudo error code
push byte 52
2011-07-30 17:28:09 +02:00
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
2011-07-30 17:28:09 +02:00
jmp common_stub
; 54: IRQ22
irq22:
; irq16- irq23 are registered as "Interrupt Gate"
; Therefore, the interrupt flag (IF) is already cleared.
; cli
2011-07-30 17:28:09 +02:00
push byte 0 ; pseudo error code
push byte 54
2011-07-30 17:28:09 +02:00
jmp common_stub
; 55: IRQ23
irq23:
; irq16 - irq23 are registered as "Interrupt Gate"
; Therefore, the interrupt flag (IF) is already cleared.
; cli
2011-07-30 17:28:09 +02:00
push byte 0 ; pseudo error code
push byte 55
2011-07-30 17:28:09 +02:00
jmp common_stub
apic_timer:
; apic timer is registered as "Interrupt Gate"
; Therefore, the interrupt flag (IF) is already cleared.
; cli
2011-07-30 17:28:09 +02:00
push byte 0 ; pseudo error code
push byte 123
2011-07-30 17:28:09 +02:00
jmp common_stub
apic_lint0:
; lint0 is registered as "Interrupt Gate"
; Therefore, the interrupt flag (IF) is already cleared.
; cli
2011-07-30 17:28:09 +02:00
push byte 0 ; pseudo error code
push byte 124
2011-07-30 17:28:09 +02:00
jmp common_stub
apic_lint1:
; lint1 is registered as "Interrupt Gate"
; Therefore, the interrupt flag (IF) is already cleared.
; cli
2011-07-30 17:28:09 +02:00
push byte 0 ; pseudo error code
push byte 125
2011-07-30 17:28:09 +02:00
jmp common_stub
apic_error:
; LVT error interrupt is registered as "Interrupt Gate"
; Therefore, the interrupt flag (IF) is already cleared.
; cli
2011-07-30 17:28:09 +02:00
push byte 0 ; pseudo error code
push byte 126
2011-07-30 17:28:09 +02:00
jmp common_stub
apic_svr:
; SVR is registered as "Interrupt Gate"
; Therefore, the interrupt flag (IF) is already cleared.
; cli
2011-07-30 17:28:09 +02:00
push byte 0 ; pseudo error code
push byte 127
2011-07-30 17:28:09 +02:00
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
2011-07-30 17:28:09 +02:00
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