2015-05-23 14:35:45 +02:00
|
|
|
|
|
|
|
; Copyright (c) 2010, Stefan Lankes, RWTH Aachen University
|
|
|
|
; All rights reserved.
|
|
|
|
;
|
|
|
|
; Redistribution and use in source and binary forms, with or without
|
|
|
|
; modification, are permitted provided that the following conditions are met:
|
|
|
|
; * Redistributions of source code must retain the above copyright
|
|
|
|
; notice, this list of conditions and the following disclaimer.
|
|
|
|
; * Redistributions in binary form must reproduce the above copyright
|
|
|
|
; notice, this list of conditions and the following disclaimer in the
|
|
|
|
; documentation and/or other materials provided with the distribution.
|
|
|
|
; * Neither the name of the University nor the names of its contributors
|
|
|
|
; may be used to endorse or promote products derived from this software
|
|
|
|
; without specific prior written permission.
|
|
|
|
;
|
|
|
|
; THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
|
|
|
; ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
|
|
; WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
|
|
; DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
|
|
|
; DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
|
|
; (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
|
|
; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
|
|
|
; ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
|
|
; (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
|
|
; SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
|
|
|
|
|
|
; 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
|
|
|
|
|
|
|
|
; We use a special name to map this section at the begin of our kernel
|
|
|
|
; => Multiboot expects its magic number at the beginning of the kernel.
|
|
|
|
SECTION .mboot
|
|
|
|
global start
|
|
|
|
start:
|
2015-05-24 09:46:44 +02:00
|
|
|
; do we have a multiboot info? => no relocation required
|
|
|
|
cmp ebx, 0
|
|
|
|
je short Lnoreset
|
|
|
|
mov ebp, kernel_start
|
|
|
|
Lnoreset:
|
|
|
|
; relocate jmp
|
|
|
|
mov eax, stublet
|
|
|
|
sub eax, kernel_start
|
|
|
|
add eax, ebp ; ebp contains the physical address of the kernel
|
|
|
|
jmp eax
|
2015-05-23 14:35:45 +02:00
|
|
|
|
|
|
|
; This part MUST be 4 byte 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_HEADER_MAGIC equ 0x1BADB002
|
|
|
|
MULTIBOOT_HEADER_FLAGS equ MULTIBOOT_PAGE_ALIGN | MULTIBOOT_MEMORY_INFO
|
|
|
|
MULTIBOOT_CHECKSUM equ -(MULTIBOOT_HEADER_MAGIC + MULTIBOOT_HEADER_FLAGS)
|
|
|
|
|
|
|
|
; This is the GRUB Multiboot header. A boot signature
|
|
|
|
dd MULTIBOOT_HEADER_MAGIC
|
|
|
|
dd MULTIBOOT_HEADER_FLAGS
|
|
|
|
dd MULTIBOOT_CHECKSUM
|
|
|
|
dd 0, 0, 0, 0, 0 ; address fields
|
|
|
|
dd 0, 0, 0, 0,
|
|
|
|
global base
|
|
|
|
global limit
|
2015-05-24 09:46:44 +02:00
|
|
|
global cpu_freq
|
2015-05-25 09:19:57 +02:00
|
|
|
global boot_processor
|
2015-05-31 00:30:13 +02:00
|
|
|
global cpu_online
|
2015-05-24 09:46:44 +02:00
|
|
|
base dd kernel_start
|
|
|
|
limit dd 0
|
|
|
|
cpu_freq dd 0
|
2015-05-25 09:19:57 +02:00
|
|
|
boot_processor dd -1
|
2015-05-31 00:30:13 +02:00
|
|
|
cpu_online dd 0
|
2015-05-23 14:35:45 +02:00
|
|
|
|
|
|
|
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.
|
|
|
|
|
|
|
|
SECTION .text
|
|
|
|
ALIGN 4
|
|
|
|
stublet:
|
2015-05-24 09:46:44 +02:00
|
|
|
; Relocate stack pointer
|
|
|
|
mov eax, boot_stack
|
|
|
|
sub eax, kernel_start
|
|
|
|
add eax, ebp
|
|
|
|
mov esp, eax
|
2015-05-23 14:35:45 +02:00
|
|
|
add esp, KERNEL_STACK_SIZE - 16
|
2015-05-31 00:30:13 +02:00
|
|
|
mov eax, boot_processor
|
|
|
|
sub eax, kernel_start
|
|
|
|
add eax, ebp
|
|
|
|
mov eax, DWORD [eax]
|
|
|
|
cmp eax, -1
|
|
|
|
je L0
|
|
|
|
imul eax, KERNEL_STACK_SIZE
|
|
|
|
add esp, eax
|
|
|
|
L0:
|
2015-05-23 14:35:45 +02:00
|
|
|
|
|
|
|
; Interpret multiboot information
|
2015-05-24 09:46:44 +02:00
|
|
|
mov eax, mb_info
|
|
|
|
sub eax, kernel_start
|
|
|
|
add eax, ebp
|
|
|
|
mov DWORD [eax], ebx
|
2015-05-23 14:35:45 +02:00
|
|
|
|
|
|
|
; This will set up the x86 control registers:
|
|
|
|
; Caching and the floating point unit are enabled
|
|
|
|
; Bootstrap page tables are loaded and page size
|
|
|
|
; extensions (huge pages) enabled.
|
|
|
|
cpu_init:
|
2015-05-24 09:46:44 +02:00
|
|
|
push edi
|
|
|
|
|
2015-05-31 00:30:13 +02:00
|
|
|
; do we have to relocate / to intialize the page tables?
|
|
|
|
; only the boot_processor have to do it
|
|
|
|
mov eax, cpu_online
|
|
|
|
sub eax, kernel_start
|
|
|
|
add eax, ebp
|
|
|
|
mov eax, DWORD [eax]
|
|
|
|
cmp eax, 0
|
|
|
|
je short Lrelocate
|
|
|
|
mov eax, Lmap_kernel
|
|
|
|
sub eax, kernel_start
|
|
|
|
add eax, ebp ; ebp contains the physical address of the kernel
|
|
|
|
jmp eax
|
|
|
|
|
|
|
|
Lrelocate:
|
2015-05-24 09:46:44 +02:00
|
|
|
; relocate page tables
|
|
|
|
mov edi, boot_pml4
|
|
|
|
sub edi, kernel_start
|
|
|
|
add edi, ebp
|
|
|
|
mov eax, DWORD [edi]
|
|
|
|
sub eax, kernel_start
|
|
|
|
add eax, ebp
|
|
|
|
mov DWORD [edi], eax
|
|
|
|
|
|
|
|
mov eax, DWORD [edi+511*8]
|
|
|
|
sub eax, kernel_start
|
|
|
|
add eax, ebp
|
|
|
|
mov DWORD [edi+511*8], eax
|
|
|
|
|
|
|
|
mov edi, boot_pdpt
|
|
|
|
sub edi, kernel_start
|
|
|
|
add edi, ebp
|
|
|
|
mov eax, DWORD [edi]
|
|
|
|
sub eax, kernel_start
|
|
|
|
add eax, ebp
|
|
|
|
mov DWORD [edi], eax
|
|
|
|
|
|
|
|
mov eax, DWORD [edi+511*8]
|
|
|
|
sub eax, kernel_start
|
|
|
|
add eax, ebp
|
|
|
|
mov DWORD [edi+511*8], eax
|
|
|
|
|
|
|
|
mov edi, boot_pgd
|
|
|
|
sub edi, kernel_start
|
|
|
|
add edi, ebp
|
|
|
|
mov eax, DWORD [edi]
|
|
|
|
sub eax, kernel_start
|
|
|
|
add eax, ebp
|
|
|
|
mov DWORD [edi], eax
|
|
|
|
|
|
|
|
mov eax, DWORD [edi+511*8]
|
|
|
|
sub eax, kernel_start
|
|
|
|
add eax, ebp
|
|
|
|
mov DWORD [edi+511*8], eax
|
2015-05-23 14:35:45 +02:00
|
|
|
|
|
|
|
; initialize page tables
|
|
|
|
|
|
|
|
; map vga 1:1
|
|
|
|
%ifdef CONFIG_VGA
|
|
|
|
mov eax, VIDEO_MEM_ADDR ; map vga
|
|
|
|
and eax, 0xFFFFF000 ; page align lower half
|
|
|
|
mov edi, eax
|
|
|
|
shr edi, 9 ; (edi >> 12) * 8 (index for boot_pgt)
|
|
|
|
add edi, boot_pgt
|
2015-05-24 09:46:44 +02:00
|
|
|
sub edi, kernel_start
|
|
|
|
add edi, ebp
|
2015-05-23 14:35:45 +02:00
|
|
|
or eax, 0x113 ; set present, global, writable and cache disable bits
|
|
|
|
mov DWORD [edi], eax
|
|
|
|
%endif
|
|
|
|
|
|
|
|
; map multiboot info 1:1
|
2015-05-24 09:46:44 +02:00
|
|
|
mov eax, mb_info ; map multiboot info
|
|
|
|
sub eax, kernel_start
|
|
|
|
add eax, ebp
|
|
|
|
mov eax, DWORD [eax]
|
2015-05-23 14:35:45 +02:00
|
|
|
cmp eax, 0
|
2015-05-24 09:46:44 +02:00
|
|
|
je short Lno_mbinfo
|
2015-05-23 14:35:45 +02:00
|
|
|
and eax, 0xFFFFF000 ; page align lower half
|
|
|
|
mov edi, eax
|
|
|
|
shr edi, 9 ; (edi >> 12) * 8 (index for boot_pgt)
|
|
|
|
add edi, boot_pgt
|
2015-05-24 09:46:44 +02:00
|
|
|
sub edi, kernel_start
|
|
|
|
add edi, ebp
|
2015-05-23 14:35:45 +02:00
|
|
|
or eax, 0x101 ; set present and global bits
|
|
|
|
mov DWORD [edi], eax
|
|
|
|
Lno_mbinfo:
|
2015-05-24 09:46:44 +02:00
|
|
|
|
|
|
|
; map kernel at link address, use a page size of 2MB
|
|
|
|
mov eax, ebp
|
|
|
|
and eax, 0xFFE00000
|
|
|
|
mov edi, kernel_start
|
|
|
|
and edi, 0xFFE00000
|
|
|
|
shr edi, 18 ; (edi >> 21) * 8 (index for boot_pgd)
|
|
|
|
add edi, boot_pgd
|
|
|
|
sub edi, kernel_start
|
|
|
|
add edi, ebp
|
|
|
|
or eax, 0x183
|
|
|
|
mov DWORD [edi], eax
|
2015-05-23 14:35:45 +02:00
|
|
|
|
2015-05-31 00:30:13 +02:00
|
|
|
Lmap_kernel:
|
2015-05-24 11:23:10 +02:00
|
|
|
cmp ebp, kernel_start
|
|
|
|
je Lno_remap
|
|
|
|
|
2015-05-23 14:35:45 +02:00
|
|
|
; map kernel 1:1, use a page size of 2MB
|
2015-05-24 09:46:44 +02:00
|
|
|
mov eax, ebp
|
2015-05-23 14:35:45 +02:00
|
|
|
and eax, 0xFFE00000
|
|
|
|
mov edi, eax
|
|
|
|
shr edi, 18 ; (edi >> 21) * 8 (index for boot_pgd)
|
|
|
|
add edi, boot_pgd
|
2015-05-24 09:46:44 +02:00
|
|
|
sub edi, kernel_start
|
|
|
|
add edi, ebp
|
2015-05-23 14:35:45 +02:00
|
|
|
or eax, 0x183
|
|
|
|
mov DWORD [edi], eax
|
2015-05-24 11:23:10 +02:00
|
|
|
Lno_remap:
|
2015-05-24 09:46:44 +02:00
|
|
|
|
2015-05-23 14:35:45 +02:00
|
|
|
pop edi
|
|
|
|
|
|
|
|
; check for long mode
|
|
|
|
|
|
|
|
; 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
|
2015-07-08 08:12:13 +02:00
|
|
|
jz $ ; there is no long mode
|
2015-05-23 14:35:45 +02:00
|
|
|
|
|
|
|
; cpuid > 0x80000000?
|
|
|
|
mov eax, 0x80000000
|
|
|
|
cpuid
|
|
|
|
cmp eax, 0x80000001
|
2015-07-08 08:12:13 +02:00
|
|
|
jb $ ; It is less, there is no long mode.
|
2015-05-23 14:35:45 +02:00
|
|
|
|
|
|
|
; 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.
|
2015-07-08 08:12:13 +02:00
|
|
|
jz $ ; They aren't, there is no long mode.
|
2015-05-23 14:35:45 +02:00
|
|
|
|
|
|
|
|
|
|
|
; 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
|
|
|
|
|
|
|
|
; Set CR3
|
|
|
|
mov eax, boot_pml4
|
2015-05-24 09:46:44 +02:00
|
|
|
sub eax, kernel_start
|
2015-07-08 08:12:13 +02:00
|
|
|
add eax, ebp
|
|
|
|
or eax, (1 << 0) ; set present bit
|
2015-05-23 14:35:45 +02:00
|
|
|
mov cr3, eax
|
|
|
|
|
2015-07-08 20:08:53 +02:00
|
|
|
; Set CR4 (PAE is already set)
|
2015-05-23 14:35:45 +02:00
|
|
|
mov eax, cr4
|
|
|
|
and eax, 0xfffbf9ff ; disable SSE
|
2015-07-08 08:12:13 +02:00
|
|
|
or eax, (1 << 7) ; enable PGE
|
2015-05-23 14:35:45 +02:00
|
|
|
mov cr4, eax
|
|
|
|
|
2015-07-08 20:08:53 +02:00
|
|
|
; Set CR0 (PM-bit is already set)
|
2015-05-23 14:35:45 +02:00
|
|
|
mov eax, cr0
|
|
|
|
and eax, ~(1 << 30) ; enable caching
|
2015-07-08 20:08:53 +02:00
|
|
|
and eax, ~(1 << 29) ; disable write through caching
|
2015-07-08 16:33:08 +02:00
|
|
|
and eax, ~(1 << 16) ; allow kernel write access to read-only pages
|
2015-05-23 14:35:45 +02:00
|
|
|
or eax, (1 << 31) ; enable paging
|
|
|
|
mov cr0, eax
|
|
|
|
|
2015-05-24 09:46:44 +02:00
|
|
|
lgdt [GDT64.Pointer] ; Load the 64-bit global descriptor table.
|
|
|
|
jmp GDT64.Code:start64 ; Set the code segment and enter 64-bit long mode.
|
2015-05-23 14:35:45 +02:00
|
|
|
|
|
|
|
[BITS 64]
|
|
|
|
start64:
|
|
|
|
; initialize segment registers
|
|
|
|
mov ax, GDT64.Data
|
|
|
|
mov ds, ax
|
|
|
|
mov es, ax
|
|
|
|
mov ss, ax
|
|
|
|
mov ax, 0x00
|
|
|
|
mov fs, ax
|
|
|
|
mov gs, ax
|
|
|
|
|
2015-05-24 11:23:10 +02:00
|
|
|
cmp ebp, kernel_start
|
|
|
|
je Lno_unmap
|
|
|
|
; unmap temporary 1:1 mapping of the kernel
|
|
|
|
mov edi, ebp
|
|
|
|
shr edi, 18 ; (edi >> 21) * 8 (index for boot_pgd)
|
|
|
|
add edi, boot_pgd
|
|
|
|
mov DWORD [edi], 0
|
|
|
|
xor rdi, rdi
|
|
|
|
|
|
|
|
Lno_unmap:
|
2015-05-31 00:30:13 +02:00
|
|
|
mov eax, DWORD [cpu_online]
|
|
|
|
cmp eax, 0
|
|
|
|
jne Lsmp_main
|
|
|
|
|
2015-05-23 14:35:45 +02:00
|
|
|
; set default stack pointer
|
|
|
|
mov rsp, boot_stack
|
|
|
|
add rsp, KERNEL_STACK_SIZE-16
|
2015-05-31 00:30:13 +02:00
|
|
|
xor rax, rax
|
|
|
|
mov eax, [boot_processor]
|
|
|
|
cmp eax, -1
|
|
|
|
je L1
|
|
|
|
imul eax, KERNEL_STACK_SIZE
|
|
|
|
add rsp, rax
|
|
|
|
L1:
|
2015-05-24 09:46:44 +02:00
|
|
|
mov rbp, rsp
|
2015-05-23 14:35:45 +02:00
|
|
|
|
|
|
|
; jump to the boot processors's C code
|
|
|
|
extern main
|
|
|
|
call main
|
|
|
|
jmp $
|
|
|
|
|
2015-05-31 00:30:13 +02:00
|
|
|
Lsmp_main:
|
|
|
|
; dirty to hack to determine the cpu id
|
|
|
|
; with a temporary stack
|
|
|
|
mov rsp, tmp_stack-16
|
|
|
|
extern apic_cpu_id
|
|
|
|
call apic_cpu_id
|
|
|
|
|
|
|
|
; set default stack pointer
|
|
|
|
imul rax, KERNEL_STACK_SIZE
|
|
|
|
add rax, boot_stack
|
|
|
|
add rax, KERNEL_STACK_SIZE-16
|
|
|
|
mov rsp, rax
|
|
|
|
mov rbp, rsp
|
2015-07-08 08:12:13 +02:00
|
|
|
|
2015-05-31 00:30:13 +02:00
|
|
|
extern smp_start
|
|
|
|
call smp_start
|
|
|
|
jmp $
|
|
|
|
|
|
|
|
DQ 0, 0, 0, 0
|
|
|
|
DQ 0, 0, 0, 0
|
|
|
|
tmp_stack:
|
|
|
|
|
2015-05-23 14:35:45 +02:00
|
|
|
global gdt_flush
|
|
|
|
extern gp
|
|
|
|
|
|
|
|
; This will set up our new segment registers and is declared in
|
|
|
|
; C as 'extern void gdt_flush();'
|
|
|
|
gdt_flush:
|
|
|
|
lgdt [gp]
|
|
|
|
ret
|
|
|
|
|
|
|
|
; The first 32 interrupt service routines (ISR) entries correspond to exceptions.
|
|
|
|
; Some exceptions will push an error code onto the stack which is specific to
|
|
|
|
; the exception caused. To decrease the complexity, we handle this by pushing a
|
|
|
|
; Dummy error code of 0 onto the stack for any ISR that doesn't push an error
|
|
|
|
; code already.
|
|
|
|
;
|
|
|
|
; ISRs are registered as "Interrupt Gate".
|
|
|
|
; Therefore, the interrupt flag (IF) is already cleared.
|
|
|
|
|
|
|
|
; NASM macro which pushs also an pseudo error code
|
|
|
|
%macro isrstub_pseudo_error 1
|
|
|
|
global isr%1
|
|
|
|
isr%1:
|
|
|
|
push byte 0 ; pseudo error code
|
|
|
|
push byte %1
|
|
|
|
jmp common_stub
|
|
|
|
%endmacro
|
|
|
|
|
|
|
|
; Similar to isrstub_pseudo_error, but without pushing
|
|
|
|
; a pseudo error code => The error code is already
|
|
|
|
; on the stack.
|
|
|
|
%macro isrstub 1
|
|
|
|
global isr%1
|
|
|
|
isr%1:
|
|
|
|
push byte %1
|
|
|
|
jmp common_stub
|
|
|
|
%endmacro
|
|
|
|
|
|
|
|
; Create isr entries, where the number after the
|
|
|
|
; pseudo error code represents following interrupts:
|
|
|
|
; 0: Divide By Zero Exception
|
|
|
|
; 1: Debug Exception
|
|
|
|
; 2: Non Maskable Interrupt Exception
|
|
|
|
; 3: Int 3 Exception
|
|
|
|
; 4: INTO Exception
|
|
|
|
; 5: Out of Bounds Exception
|
|
|
|
; 6: Invalid Opcode Exception
|
|
|
|
; 7: Coprocessor Not Available Exception
|
|
|
|
%assign i 0
|
|
|
|
%rep 8
|
|
|
|
isrstub_pseudo_error i
|
|
|
|
%assign i i+1
|
|
|
|
%endrep
|
|
|
|
|
|
|
|
; 8: Double Fault Exception (With Error Code!)
|
|
|
|
isrstub 8
|
|
|
|
|
|
|
|
; 9: Coprocessor Segment Overrun Exception
|
|
|
|
isrstub_pseudo_error 9
|
|
|
|
|
|
|
|
; 10: Bad TSS Exception (With Error Code!)
|
|
|
|
; 11: Segment Not Present Exception (With Error Code!)
|
|
|
|
; 12: Stack Fault Exception (With Error Code!)
|
|
|
|
; 13: General Protection Fault Exception (With Error Code!)
|
|
|
|
; 14: Page Fault Exception (With Error Code!)
|
|
|
|
%assign i 10
|
|
|
|
%rep 5
|
|
|
|
isrstub i
|
|
|
|
%assign i i+1
|
|
|
|
%endrep
|
|
|
|
|
|
|
|
; 15: Reserved Exception
|
|
|
|
; 16: Floating Point Exception
|
|
|
|
; 17: Alignment Check Exception
|
|
|
|
; 18: Machine Check Exceptio
|
|
|
|
; 19-31: Reserved
|
|
|
|
%assign i 15
|
|
|
|
%rep 17
|
|
|
|
isrstub_pseudo_error i
|
|
|
|
%assign i i+1
|
|
|
|
%endrep
|
|
|
|
|
|
|
|
; NASM macro for asynchronous interrupts (no exceptions)
|
|
|
|
%macro irqstub 1
|
|
|
|
global irq%1
|
|
|
|
irq%1:
|
|
|
|
push byte 0 ; pseudo error code
|
|
|
|
push byte 32+%1
|
|
|
|
jmp common_stub
|
|
|
|
%endmacro
|
|
|
|
|
|
|
|
; Create entries for the interrupts 0 to 23
|
|
|
|
%assign i 0
|
|
|
|
%rep 24
|
|
|
|
irqstub i
|
|
|
|
%assign i i+1
|
|
|
|
%endrep
|
|
|
|
|
|
|
|
global apic_timer
|
|
|
|
apic_timer:
|
|
|
|
push byte 0 ; pseudo error code
|
|
|
|
push byte 123
|
|
|
|
jmp common_stub
|
|
|
|
|
|
|
|
global apic_lint0
|
|
|
|
apic_lint0:
|
|
|
|
push byte 0 ; pseudo error code
|
|
|
|
push byte 124
|
|
|
|
jmp common_stub
|
|
|
|
|
|
|
|
global apic_lint1
|
|
|
|
apic_lint1:
|
|
|
|
push byte 0 ; pseudo error code
|
|
|
|
push byte 125
|
|
|
|
jmp common_stub
|
|
|
|
|
|
|
|
global apic_error
|
|
|
|
apic_error:
|
|
|
|
push byte 0 ; pseudo error code
|
|
|
|
push byte 126
|
|
|
|
jmp common_stub
|
|
|
|
|
|
|
|
global apic_svr
|
|
|
|
apic_svr:
|
|
|
|
push byte 0 ; pseudo error code
|
|
|
|
push byte 127
|
|
|
|
jmp common_stub
|
|
|
|
|
|
|
|
extern irq_handler
|
|
|
|
extern get_current_stack
|
|
|
|
extern finish_task_switch
|
|
|
|
|
|
|
|
global isrsyscall
|
|
|
|
; used to realize system calls
|
|
|
|
isrsyscall:
|
|
|
|
cli
|
|
|
|
; set kernel stack
|
|
|
|
extern get_kernel_stack
|
|
|
|
call get_kernel_stack
|
|
|
|
xchg rsp, rax ; => rax contains original rsp
|
|
|
|
|
|
|
|
push rax ; contains original rsp
|
|
|
|
push r15
|
|
|
|
push r14
|
|
|
|
push r13
|
|
|
|
push r12
|
|
|
|
push r11
|
|
|
|
push rbp
|
|
|
|
push rdx
|
|
|
|
push rcx
|
|
|
|
push rbx
|
|
|
|
push rdi
|
|
|
|
push rsi
|
|
|
|
sti
|
|
|
|
|
|
|
|
extern syscall_handler
|
|
|
|
call syscall_handler
|
|
|
|
|
|
|
|
cli
|
|
|
|
pop rsi
|
|
|
|
pop rdi
|
|
|
|
pop rbx
|
|
|
|
pop rcx
|
|
|
|
pop rdx
|
|
|
|
pop rbp
|
|
|
|
pop r11
|
|
|
|
pop r12
|
|
|
|
pop r13
|
|
|
|
pop r14
|
|
|
|
pop r15
|
|
|
|
pop r10
|
|
|
|
mov rsp, r10
|
|
|
|
sti
|
|
|
|
o64 sysret
|
|
|
|
|
|
|
|
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
|
2015-06-27 20:14:18 +02:00
|
|
|
push QWORD 0x10 ; SS
|
|
|
|
push rsp ; RSP
|
|
|
|
add QWORD [rsp], 0x08 ; => value of rsp before the creation of a pseudo interrupt
|
|
|
|
pushfq ; RFLAGS
|
2015-05-23 14:35:45 +02:00
|
|
|
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 mb_info:
|
|
|
|
ALIGN 8
|
|
|
|
mb_info:
|
|
|
|
DQ 0
|
|
|
|
|
|
|
|
ALIGN 4096
|
|
|
|
global boot_stack
|
|
|
|
boot_stack:
|
2015-05-31 00:30:13 +02:00
|
|
|
TIMES (MAX_CORES*KERNEL_STACK_SIZE) DB 0xcd
|
2015-05-23 14:35:45 +02:00
|
|
|
|
|
|
|
; Bootstrap page tables are used during the initialization.
|
|
|
|
ALIGN 4096
|
|
|
|
boot_pml4:
|
2015-07-08 16:33:08 +02:00
|
|
|
DQ boot_pdpt + 0x7 ; PG_PRESENT | PG_RW | PG_USER
|
2015-05-23 14:35:45 +02:00
|
|
|
times 510 DQ 0 ; PAGE_MAP_ENTRIES - 2
|
2015-07-08 16:33:08 +02:00
|
|
|
DQ boot_pml4 + 0x203 ; PG_PRESENT | PG_RW | PG_SELF (self-reference)
|
2015-05-23 14:35:45 +02:00
|
|
|
boot_pdpt:
|
2015-07-08 16:33:08 +02:00
|
|
|
DQ boot_pgd + 0x7 ; PG_PRESENT | PG_RW | PG_USER
|
2015-05-23 14:35:45 +02:00
|
|
|
times 510 DQ 0 ; PAGE_MAP_ENTRIES - 2
|
2015-07-08 16:33:08 +02:00
|
|
|
DQ boot_pml4 + 0x203 ; PG_PRESENT | PG_RW | PG_SELF (self-reference)
|
2015-05-23 14:35:45 +02:00
|
|
|
boot_pgd:
|
2015-07-08 16:33:08 +02:00
|
|
|
DQ boot_pgt + 0x7 ; PG_PRESENT | PG_RW | PG_USER
|
2015-05-23 14:35:45 +02:00
|
|
|
times 510 DQ 0 ; PAGE_MAP_ENTRIES - 2
|
2015-07-08 16:33:08 +02:00
|
|
|
DQ boot_pml4 + 0x203 ; PG_PRESENT | PG_RW | PG_SELF (self-reference)
|
2015-05-23 14:35:45 +02:00
|
|
|
boot_pgt:
|
|
|
|
times 512 DQ 0
|
|
|
|
|
|
|
|
; add some hints to the ELF file
|
|
|
|
SECTION .note.GNU-stack noalloc noexec nowrite progbits
|