<commit_before>
; Copyright (c) 2010, <NAME>, 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:
    ; 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

; 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
    global cpu_freq
    global boot_processor
    global cpu_online
    base dd kernel_start
    limit dd 0
    cpu_freq dd 0
    boot_processor dd -1
    cpu_online dd 0

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:
    ; Relocate stack pointer
    mov eax, boot_stack
    sub eax, kernel_start
    add eax, ebp
    mov esp, eax
    add esp, KERNEL_STACK_SIZE - 16
    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:

    ; Interpret multiboot information
    mov eax, mb_info
    sub eax, kernel_start
    add eax, ebp
    mov DWORD [eax], ebx

; 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:
   push edi

; 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:
; 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

; 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
    sub edi, kernel_start
    add edi, ebp
    or eax, 0x113             ; set present, global, writable and cache disable bits
    mov DWORD [edi], eax
%endif

    ; map multiboot info 1:1
    mov eax, mb_info  ; map multiboot info
    sub eax, kernel_start
    add eax, ebp
    mov eax, DWORD [eax]
    cmp eax, 0
    je short Lno_mbinfo
    and eax, 0xFFFFF000       ; page align lower half
    mov edi, eax
    shr edi, 9                ; (edi >> 12) * 8 (index for boot_pgt)
    add edi, boot_pgt
    sub edi, kernel_start
    add edi, ebp
    or eax, 0x101             ; set present and global bits
    mov DWORD [edi], eax
Lno_mbinfo:

    ; 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

Lmap_kernel:
    cmp ebp, kernel_start
    je Lno_remap

    ; map kernel 1:1, use a page size of 2MB
    mov eax, ebp
    and eax, 0xFFE00000
    mov edi, eax
    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
Lno_remap:

    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
    jz short Linvalid

    ; cpuid > 0x80000000?
    mov eax, 0x80000000
    cpuid
    cmp eax, 0x80000001
    jb short 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 short Linvalid ; They aren't, there is no long mode.


    ; 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
    sub eax, kernel_start
    add eax, ebp    
    mov cr3, eax

    ; Set CR4
    mov eax, cr4
    and eax, 0xfffbf9ff     ; disable SSE
    or eax, (1 << 4)        ; enable PSE
    mov cr4, eax

    ; Set CR0
    mov eax, cr0
    and eax, ~(1 << 30)     ; enable caching
    and eax, ~(1 << 16)	    ; allow kernel write access to read-only pages
    or eax, (1 << 31)       ; enable paging
    or eax, (1 << 0)        ; long mode also needs PM-bit set
    mov cr0, eax

    lgdt [GDT64.Pointer] ; Load the 64-bit global descriptor table.
    jmp GDT64.Code:start64 ; Set the code segment and enter 64-bit long mode.

; there is no long mode
Linvalid:
    jmp $

[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

    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:
    mov eax, DWORD [cpu_online]
    cmp eax, 0
    jne Lsmp_main

    ; set default stack pointer
    mov rsp, boot_stack
    add rsp, KERNEL_STACK_SIZE-16
    xor rax, rax
    mov eax, [boot_processor]
    cmp eax, -1
    je L1
    imul eax, KERNEL_STACK_SIZE
    add rsp, rax
L1:
    mov rbp, rsp

    ; jump to the boot processors's C code
    extern main
    call main
    jmp $

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
    
    extern smp_start
    call smp_start
    jmp $

    DQ 0, 0, 0, 0
    DQ 0, 0, 0, 0
tmp_stack:

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
    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
<commit_msg>fix bug in the creation of a pseudo interrupt<commit_after>
; Copyright (c) 2010, <NAME>, 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:
    ; 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

; 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
    global cpu_freq
    global boot_processor
    global cpu_online
    base dd kernel_start
    limit dd 0
    cpu_freq dd 0
    boot_processor dd -1
    cpu_online dd 0

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:
    ; Relocate stack pointer
    mov eax, boot_stack
    sub eax, kernel_start
    add eax, ebp
    mov esp, eax
    add esp, KERNEL_STACK_SIZE - 16
    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:

    ; Interpret multiboot information
    mov eax, mb_info
    sub eax, kernel_start
    add eax, ebp
    mov DWORD [eax], ebx

; 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:
   push edi

; 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:
; 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

; 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
    sub edi, kernel_start
    add edi, ebp
    or eax, 0x113             ; set present, global, writable and cache disable bits
    mov DWORD [edi], eax
%endif

    ; map multiboot info 1:1
    mov eax, mb_info  ; map multiboot info
    sub eax, kernel_start
    add eax, ebp
    mov eax, DWORD [eax]
    cmp eax, 0
    je short Lno_mbinfo
    and eax, 0xFFFFF000       ; page align lower half
    mov edi, eax
    shr edi, 9                ; (edi >> 12) * 8 (index for boot_pgt)
    add edi, boot_pgt
    sub edi, kernel_start
    add edi, ebp
    or eax, 0x101             ; set present and global bits
    mov DWORD [edi], eax
Lno_mbinfo:

    ; 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

Lmap_kernel:
    cmp ebp, kernel_start
    je Lno_remap

    ; map kernel 1:1, use a page size of 2MB
    mov eax, ebp
    and eax, 0xFFE00000
    mov edi, eax
    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
Lno_remap:

    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
    jz short Linvalid

    ; cpuid > 0x80000000?
    mov eax, 0x80000000
    cpuid
    cmp eax, 0x80000001
    jb short 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 short Linvalid ; They aren't, there is no long mode.


    ; 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
    sub eax, kernel_start
    add eax, ebp    
    mov cr3, eax

    ; Set CR4
    mov eax, cr4
    and eax, 0xfffbf9ff     ; disable SSE
    or eax, (1 << 4)        ; enable PSE
    mov cr4, eax

    ; Set CR0
    mov eax, cr0
    and eax, ~(1 << 30)     ; enable caching
    and eax, ~(1 << 16)	    ; allow kernel write access to read-only pages
    or eax, (1 << 31)       ; enable paging
    or eax, (1 << 0)        ; long mode also needs PM-bit set
    mov cr0, eax

    lgdt [GDT64.Pointer] ; Load the 64-bit global descriptor table.
    jmp GDT64.Code:start64 ; Set the code segment and enter 64-bit long mode.

; there is no long mode
Linvalid:
    jmp $

[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

    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:
    mov eax, DWORD [cpu_online]
    cmp eax, 0
    jne Lsmp_main

    ; set default stack pointer
    mov rsp, boot_stack
    add rsp, KERNEL_STACK_SIZE-16
    xor rax, rax
    mov eax, [boot_processor]
    cmp eax, -1
    je L1
    imul eax, KERNEL_STACK_SIZE
    add rsp, rax
L1:
    mov rbp, rsp

    ; jump to the boot processors's C code
    extern main
    call main
    jmp $

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
    
    extern smp_start
    call smp_start
    jmp $

    DQ 0, 0, 0, 0
    DQ 0, 0, 0, 0
tmp_stack:

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
    push QWORD 0x10             ; SS
    push rsp                    ; RSP
    add QWORD [rsp], 0x08       ; => value of rsp before the creation of a pseudo interrupt
    pushfq                      ; 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

{'fraction_non_alphanumeric': 0.054702781553558996, 'fraction_numerical': 0.03162815369823956, 'mean_word_length': 2.2212729602733874, 'pattern_counts': {'":': 0, '<': 49, '<?xml version=': 0, '>': 36, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 6, 'word_list_counts': {'cursed_substrings.json': 28, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5086657', 'n_tokens_mistral': 10914, 'n_tokens_neox': 9839, 'n_words': 4129}