metalsvm/arch/x86/kernel/entry32.asm

829 lines
20 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]
; 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:
mov byte [msg], 'H'
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
msg db "?ello from MetalSVM kernel!!", 0
SECTION .text
ALIGN 4
stublet:
; initialize stack pointer.
mov esp, boot_stack
add esp, KERNEL_STACK_SIZE-16
; save pointer to the multiboot structure
push ebx
; initialize cpu features
call cpu_init
; interpret multiboot information
extern multiboot_init
; pointer to the multiboot structure is already pushed
call multiboot_init
add esp, 4
; jump to the boot processors's C code
extern main
call main
jmp $ ; infinitive loop
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. 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
; determines the current instruction pointer (after the jmp)
global read_ip
read_ip:
mov eax, [esp+4]
pop DWORD [eax] ; Get the return address
add esp, 4 ; Dirty Hack! read_ip cleanup the stack
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
; 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
; by entering the handler, the interrupt flag is not cleared
isrsyscall:
cli
push es
push ds
push ebp
push edi
push esi
push edx
push ecx
push ebx
push eax
; set kernel data segmenets
mov ax, 0x10
mov ds, ax
mov es, ax
mov eax, [esp]
sti
call syscall_handler
cli
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
pop ds
pop es
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
; 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 4
switch_context:
; create on the stack a pseudo interrupt
; afterwards, we switch to the task with iret
; we already in kernel space => no pushing of SS required
mov eax, [esp+4] ; on the stack is already the address to store the old esp
pushf ; EFLAGS
push DWORD 0x8 ; CS
push DWORD rollback ; EIP
push DWORD 0x0 ; Interrupt number
push DWORD 0x00edbabe ; Error code
pusha ; Registers...
push 0x10 ; kernel data segment
push 0x10 ; kernel data segment
jmp common_switch
ALIGN 4
rollback:
ret
ALIGN 4
common_stub:
pusha
push es
push ds
mov ax, 0x10
mov es, ax
mov ds, ax
; use the same handler for interrupts and exceptions
push esp
call irq_handler
add esp, 4
cmp eax, 0
je no_context_switch
common_switch:
mov [eax], esp ; store old esp
call get_current_stack ; get new esp
xchg eax, esp
; set task switched flag
mov eax, cr0
or eax, 8
mov cr0, eax
; call cleanup code
call finish_task_switch
no_context_switch:
pop ds
pop es
popa
add esp, 8
iret
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