From ef3b761d4f061817a17ea0e78a575aa93b8677cd Mon Sep 17 00:00:00 2001 From: Alex Date: Fri, 11 Aug 2023 04:57:32 +0300 Subject: [PATCH] Removal of NASM support and migration of .asm files to .s --- .vscode/extensions.json | 2 +- .../amd64/Bootstrap/Multiboot/1/Start.asm | 22 - .../Bootstrap/Multiboot/1/Start.s} | 7 +- .../amd64/Bootstrap/Multiboot/2/Detect.s | 16 +- .../amd64/Bootstrap/Multiboot/2/GDT32.s | 22 +- .../amd64/Bootstrap/Multiboot/2/GDT64.s | 35 +- .../amd64/Bootstrap/Multiboot/2/Header.s | 3 +- .../Multiboot/2/Multiboot_PageTable.asm | 61 -- .../Multiboot/2/Multiboot_PageTable.s | 62 ++ .../Multiboot/2/Multiboot_PageTable.s_fixme | 67 -- .../amd64/Bootstrap/Multiboot/2/Start.asm | 112 ---- .../Multiboot/2/{Start.s_fixme => Start.s} | 76 +-- ...dvancedProgrammableInterruptController.cpp | 621 +++++++++--------- Architecture/amd64/cpu/SMPTrampoline.asm | 136 ---- Architecture/amd64/cpu/SMPTrampoline.s | 179 +++++ .../amd64/cpu/SymmetricMultiprocessing.cpp | 160 +++-- .../i386/Bootstrap/Multiboot/1/Start.asm | 22 - .../Multiboot_PageTable.s_fixme => 1/Start.s} | 7 +- .../Multiboot/2/Multiboot_PageTable.asm | 46 -- .../Multiboot/2/Multiboot_PageTable.s | 51 ++ .../i386/Bootstrap/Multiboot/2/Start.asm | 86 --- .../i386/Bootstrap/Multiboot/2/Start.s | 79 +++ Makefile | 29 +- include/cpu.hpp | 20 +- 24 files changed, 868 insertions(+), 1053 deletions(-) delete mode 100644 Architecture/amd64/Bootstrap/Multiboot/1/Start.asm rename Architecture/{i386/Bootstrap/Multiboot/2/Start.s_fixme => amd64/Bootstrap/Multiboot/1/Start.s} (90%) delete mode 100644 Architecture/amd64/Bootstrap/Multiboot/2/Multiboot_PageTable.asm create mode 100644 Architecture/amd64/Bootstrap/Multiboot/2/Multiboot_PageTable.s delete mode 100644 Architecture/amd64/Bootstrap/Multiboot/2/Multiboot_PageTable.s_fixme delete mode 100644 Architecture/amd64/Bootstrap/Multiboot/2/Start.asm rename Architecture/amd64/Bootstrap/Multiboot/2/{Start.s_fixme => Start.s} (64%) delete mode 100644 Architecture/amd64/cpu/SMPTrampoline.asm create mode 100644 Architecture/amd64/cpu/SMPTrampoline.s delete mode 100644 Architecture/i386/Bootstrap/Multiboot/1/Start.asm rename Architecture/i386/Bootstrap/Multiboot/{2/Multiboot_PageTable.s_fixme => 1/Start.s} (90%) delete mode 100644 Architecture/i386/Bootstrap/Multiboot/2/Multiboot_PageTable.asm create mode 100644 Architecture/i386/Bootstrap/Multiboot/2/Multiboot_PageTable.s delete mode 100644 Architecture/i386/Bootstrap/Multiboot/2/Start.asm create mode 100644 Architecture/i386/Bootstrap/Multiboot/2/Start.s diff --git a/.vscode/extensions.json b/.vscode/extensions.json index 091659fd..3ccb126d 100644 --- a/.vscode/extensions.json +++ b/.vscode/extensions.json @@ -9,6 +9,6 @@ "ibm.output-colorizer", "wayou.vscode-todo-highlight", "gruntfuggly.todo-tree", - "13xforever.language-x86-64-assembly" + "maziac.asm-code-lens" ] } \ No newline at end of file diff --git a/Architecture/amd64/Bootstrap/Multiboot/1/Start.asm b/Architecture/amd64/Bootstrap/Multiboot/1/Start.asm deleted file mode 100644 index 49bc2c27..00000000 --- a/Architecture/amd64/Bootstrap/Multiboot/1/Start.asm +++ /dev/null @@ -1,22 +0,0 @@ -; This file is part of Fennix Kernel. -; -; Fennix Kernel is free software: you can redistribute it and/or -; modify it under the terms of the GNU General Public License as -; published by the Free Software Foundation, either version 3 of -; the License, or (at your option) any later version. -; -; Fennix Kernel is distributed in the hope that it will be useful, -; but WITHOUT ANY WARRANTY; without even the implied warranty of -; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -; GNU General Public License for more details. -; -; You should have received a copy of the GNU General Public License -; along with Fennix Kernel. If not, see . - -[bits 32] - -section .bootstrap.text - -global Multiboot1_start -Multiboot1_start: - int3 diff --git a/Architecture/i386/Bootstrap/Multiboot/2/Start.s_fixme b/Architecture/amd64/Bootstrap/Multiboot/1/Start.s similarity index 90% rename from Architecture/i386/Bootstrap/Multiboot/2/Start.s_fixme rename to Architecture/amd64/Bootstrap/Multiboot/1/Start.s index 8d58c66d..8efbeb24 100644 --- a/Architecture/i386/Bootstrap/Multiboot/2/Start.s_fixme +++ b/Architecture/amd64/Bootstrap/Multiboot/1/Start.s @@ -15,6 +15,9 @@ along with Fennix Kernel. If not, see . */ -.intel_syntax noprefix - .code32 +.section .bootstrap.text + +.global Multiboot1_start +Multiboot1_start: + jmp . diff --git a/Architecture/amd64/Bootstrap/Multiboot/2/Detect.s b/Architecture/amd64/Bootstrap/Multiboot/2/Detect.s index 319d180e..cda5c35b 100644 --- a/Architecture/amd64/Bootstrap/Multiboot/2/Detect.s +++ b/Architecture/amd64/Bootstrap/Multiboot/2/Detect.s @@ -25,7 +25,7 @@ DetectCPUID: pushfd pop eax mov ecx, eax - xor eax, 1 << 21 + xor eax, 0x200000 push eax popfd pushfd @@ -34,7 +34,7 @@ DetectCPUID: popfd xor eax, ecx jz .NoCPUID - mov eax, 1 + mov eax, 0x1 ret .NoCPUID: xor eax, eax @@ -48,9 +48,9 @@ Detect64Bit: jb .NoLongMode mov eax, 0x80000001 cpuid - test edx, 1 << 29 + test edx, 0x20000000 jz .NoLongMode - mov eax, 1 + mov eax, 0x1 ret .NoLongMode: xor eax, eax @@ -58,11 +58,11 @@ Detect64Bit: .global DetectPSE DetectPSE: - mov eax, 0x00000001 + mov eax, 0x00000001 cpuid test edx, 0x00000008 jz .NoPSE - mov eax, 1 + mov eax, 0x1 ret .NoPSE: xor eax, eax @@ -70,11 +70,11 @@ DetectPSE: .global DetectPAE DetectPAE: - mov eax, 0x00000001 + mov eax, 0x00000001 cpuid test edx, 0x00000040 jz .NoPAE - mov eax, 1 + mov eax, 0x1 ret .NoPAE: xor eax, eax diff --git a/Architecture/amd64/Bootstrap/Multiboot/2/GDT32.s b/Architecture/amd64/Bootstrap/Multiboot/2/GDT32.s index 30974ac9..85fe29e2 100644 --- a/Architecture/amd64/Bootstrap/Multiboot/2/GDT32.s +++ b/Architecture/amd64/Bootstrap/Multiboot/2/GDT32.s @@ -15,8 +15,6 @@ along with Fennix Kernel. If not, see . */ -.intel_syntax noprefix - .code32 .section .bootstrap.text @@ -48,19 +46,19 @@ GDT32: .word 0x4092 .byte 0x00 GDT32_END: + nop .global LoadGDT32 LoadGDT32: lgdt [gdtr] + ljmp $0x8, $ActivateGDT - jmp 0x8:ActivateGDT - ActivateGDT: - mov cx, 0x10 - mov ss, cx - mov ds, cx - mov es, cx - mov fs, cx - mov cx, 0x18 - mov gs, cx - +ActivateGDT: + mov $0x10, %cx + mov %cx, %ss + mov %cx, %ds + mov %cx, %es + mov %cx, %fs + mov $0x18, %cx + mov %cx, %gs ret diff --git a/Architecture/amd64/Bootstrap/Multiboot/2/GDT64.s b/Architecture/amd64/Bootstrap/Multiboot/2/GDT64.s index d655c4e8..f62ec98e 100644 --- a/Architecture/amd64/Bootstrap/Multiboot/2/GDT64.s +++ b/Architecture/amd64/Bootstrap/Multiboot/2/GDT64.s @@ -15,49 +15,48 @@ along with Fennix Kernel. If not, see . */ -.intel_syntax noprefix - .code64 .section .bootstrap.data /* Access bits */ -.equ A, 1 << 0 -.equ RW, 1 << 1 -.equ DC, 1 << 2 -.equ E, 1 << 3 -.equ S, 1 << 4 -.equ DPL0, 0 << 5 -.equ DPL1, 1 << 5 -.equ P, 1 << 7 +A = 0x1 +RW = 0x2 +DC = 0x4 +E = 0x8 +S = 0x10 +DPL0 = 0x0 /* 0 << 5 ???? */ +DPL1 = 0x20 +P = 0x80 /* Flags bits */ -.equ LONG_MODE, 1 << 5 -.equ SZ_32, 1 << 6 -.equ GRAN_4K, 1 << 7 +LONG_MODE = 0x20 +SZ_32 = 0x40 +GRAN_4K = 0x80 .global GDT64.Null .global GDT64.Code .global GDT64.Data .global GDT64.Tss .global GDT64.Ptr + GDT64: -.equ GDT64.Null, $ - GDT64 +GDT64.Null = . - GDT64 .quad 0 -.equ GDT64.Code, $ - GDT64 +GDT64.Code = . - GDT64 .long 0xFFFF .byte 0 .byte P | S | E | RW .byte GRAN_4K | LONG_MODE | 0xF .byte 0 -.equ GDT64.Data, $ - GDT64 +GDT64.Data = . - GDT64 .long 0xFFFF .byte 0 .byte P | S | RW .byte GRAN_4K | SZ_32 | 0xF .byte 0 -.equ GDT64.Tss, $ - GDT64 +GDT64.Tss = . - GDT64 .long 0x00000068 .long 0x00CF8900 GDT64.Ptr: - .word $ - GDT64 - 1 + .word . - GDT64 - 1 .quad GDT64 diff --git a/Architecture/amd64/Bootstrap/Multiboot/2/Header.s b/Architecture/amd64/Bootstrap/Multiboot/2/Header.s index 2f8d0f74..2ec235b5 100644 --- a/Architecture/amd64/Bootstrap/Multiboot/2/Header.s +++ b/Architecture/amd64/Bootstrap/Multiboot/2/Header.s @@ -15,8 +15,6 @@ along with Fennix Kernel. If not, see . */ -.intel_syntax noprefix - .code32 .extern Multiboot2_start @@ -91,3 +89,4 @@ EndTag_Start: .long EndTag_End - EndTag_Start EndTag_End: MULTIBOOT2_HEADER_END: + nop diff --git a/Architecture/amd64/Bootstrap/Multiboot/2/Multiboot_PageTable.asm b/Architecture/amd64/Bootstrap/Multiboot/2/Multiboot_PageTable.asm deleted file mode 100644 index 179233d1..00000000 --- a/Architecture/amd64/Bootstrap/Multiboot/2/Multiboot_PageTable.asm +++ /dev/null @@ -1,61 +0,0 @@ -; This file is part of Fennix Kernel. -; -; Fennix Kernel is free software: you can redistribute it and/or -; modify it under the terms of the GNU General Public License as -; published by the Free Software Foundation, either version 3 of -; the License, or (at your option) any later version. -; -; Fennix Kernel is distributed in the hope that it will be useful, -; but WITHOUT ANY WARRANTY; without even the implied warranty of -; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -; GNU General Public License for more details. -; -; You should have received a copy of the GNU General Public License -; along with Fennix Kernel. If not, see . - -[bits 32] - -PAGE_TABLE_SIZE equ 0x4 - -section .bootstrap.data -align 0x1000 -global BootPageTable -BootPageTable: - times (0x10000) dq 0 ; 0x4000 bytes will be used in UpdatePageTable - -section .bootstrap.text -global UpdatePageTable -UpdatePageTable: - mov edi, (BootPageTable + 0x0000) ; First PML4E - mov eax, (BootPageTable + 0x1000) ; First PDPTE - or eax, 11b ; Bitwise OR on rax (PDPTE) with 11b (Present, Write) - mov dword [edi], eax ; Write 11b to PML4E - - mov edi, (BootPageTable + 0x1000) ; First PDPTE - mov eax, (BootPageTable + 0x2000) ; First PDE - or eax, 11b ; Bitwise OR on rax (PDE) with 11b (Present, Write) - - mov ecx, PAGE_TABLE_SIZE ; For loop instruction - mov ebx, 0x0 ; Value to store in the next 4 bytes - .FillPageTableLevel3: - mov dword [edi], eax ; Store modified PDE in PDPTE - mov dword [edi + 4], ebx ; Store the rbx value in the next 4 bytes - add eax, 0x1000 ; Increment (page size) - adc ebx, 0 ; Add 0 to carry flag - add edi, 8 ; Add 8 to rdi (next PDE) - loop .FillPageTableLevel3 ; Loop until rcx is 0 - - mov edi, (BootPageTable + 0x2000) ; First PDE - mov eax, 10000011b ; Present, Write, Large Page - - mov ecx, (512 * PAGE_TABLE_SIZE) ; For loop instruction - mov ebx, 0x0 ; Value to store in the next 4 bytes - .FillPageTableLevel2: - mov dword [edi], eax ; Store modified PDE in PDPTE - mov dword [edi + 4], ebx ; Store the rbx value in the next 4 bytes - add eax, 1 << 21 ; Increment (page size) - adc ebx, 0 ; Add 0 (carry flag) to rbx to increment if there was a carry - add edi, 8 ; Add 8 to rdi (next PDE) - loop .FillPageTableLevel2 ; Loop until rcx is 0 - - ret diff --git a/Architecture/amd64/Bootstrap/Multiboot/2/Multiboot_PageTable.s b/Architecture/amd64/Bootstrap/Multiboot/2/Multiboot_PageTable.s new file mode 100644 index 00000000..596f6355 --- /dev/null +++ b/Architecture/amd64/Bootstrap/Multiboot/2/Multiboot_PageTable.s @@ -0,0 +1,62 @@ +/* + This file is part of Fennix Kernel. + + Fennix Kernel is free software: you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation, either version 3 of + the License, or (at your option) any later version. + + Fennix Kernel is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Fennix Kernel. If not, see . +*/ + +PAGE_TABLE_SIZE = 0x4 + +.code32 +.section .bootstrap.data +.align 0x1000 +.global BootPageTable +BootPageTable: + .space 0x10000 /* 0x4000 bytes will be used in UpdatePageTable */ + +.section .bootstrap.text +.global UpdatePageTable +UpdatePageTable: + mov $(BootPageTable + 0x0000), %edi /* First PML4E */ + mov $(BootPageTable + 0x1000), %eax /* First PDPTE */ + or $0x3, %eax /* Bitwise OR on eax (PDPTE) with 11b (Present, Write) */ + mov %eax, (%edi) /* Write 11b to PML4E */ + + mov $(BootPageTable + 0x1000), %edi /* First PDPTE */ + mov $(BootPageTable + 0x2000), %eax /* First PDE */ + or $0x3, %eax /* Bitwise OR on eax (PDE) with 11b (Present, Write) */ + + mov $PAGE_TABLE_SIZE, %ecx /* For loop instruction */ + mov $0x0, %ebx /* Value to store in the next 4 bytes */ + .FillPageTableLevel3: + mov %eax, (%edi) /* Store modified PDE in PDPTE */ + mov %ebx, 0x4(%edi) /* Store the ebx value in the next 4 bytes */ + add $0x1000, %eax /* Increment (page size) */ + adc $0x0, %ebx /* Add 0 to carry flag */ + add $0x8, %edi /* Add 8 to edi (next PDE) */ + loop .FillPageTableLevel3 /* Loop until ecx is 0 */ + + mov $(BootPageTable + 0x2000), %edi /* First PDE */ + mov $0x83, %eax /* Present, Write, Large Page */ + + mov $(512 * PAGE_TABLE_SIZE), %ecx /* For loop instruction */ + mov $0x0, %ebx /* Value to store in the next 4 bytes */ + .FillPageTableLevel2: + mov %eax, (%edi) /* Store modified PDE in PDPTE */ + mov %ebx, 0x4(%edi) /* Store the ebx value in the next 4 bytes */ + add $0x200000, %eax /* Increment (page size) */ + adc $0x0, %ebx /* Add 0 (carry flag) to ebx to increment if there was a carry */ + add $0x8, %edi /* Add 8 to edi (next PDE) */ + loop .FillPageTableLevel2 /* Loop until ecx is 0 */ + + ret diff --git a/Architecture/amd64/Bootstrap/Multiboot/2/Multiboot_PageTable.s_fixme b/Architecture/amd64/Bootstrap/Multiboot/2/Multiboot_PageTable.s_fixme deleted file mode 100644 index 6922f1bb..00000000 --- a/Architecture/amd64/Bootstrap/Multiboot/2/Multiboot_PageTable.s_fixme +++ /dev/null @@ -1,67 +0,0 @@ -/* - This file is part of Fennix Kernel. - - Fennix Kernel is free software: you can redistribute it and/or - modify it under the terms of the GNU General Public License as - published by the Free Software Foundation, either version 3 of - the License, or (at your option) any later version. - - Fennix Kernel is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Fennix Kernel. If not, see . -*/ - -.intel_syntax noprefix - -.code32 - -.equ PAGE_TABLE_SIZE, 0x4 - -.section .bootstrap.data -.align 0x1000 -.global BootPageTable -BootPageTable: - .rept 0x10000 /* 0x4000 bytes will be used in UpdatePageTable */ - .long 0 - .endr - -.section .bootstrap.text -.global UpdatePageTable -UpdatePageTable: - mov edi, (BootPageTable + 0x0000) /* First PML4E */ - mov eax, (BootPageTable + 0x1000) /* First PDPTE */ - or eax, 0b11 /* Bitwise OR on rax (PDPTE) with 11b (Present, Write) */ - mov dword [edi], eax /* Write 11b to PML4E */ - - mov edi, (BootPageTable + 0x1000) /* First PDPTE */ - mov eax, (BootPageTable + 0x2000) /* First PDE */ - or eax, 0b11 /* Bitwise OR on rax (PDE) with 11b (Present, Write) */ - - mov ecx, PAGE_TABLE_SIZE /* For loop instruction */ - mov ebx, 0x0 /* Value to store in the next 4 bytes */ - .FillPageTableLevel3: - mov dword [edi], eax /* Store modified PDE in PDPTE */ - mov dword [edi + 4], ebx /* Store the rbx value in the next 4 bytes */ - add eax, 0x1000 /* Increment (page size) */ - adc ebx, 0 /* Add 0 to carry flag */ - add edi, 8 /* Add 8 to rdi (next PDE) */ - loop .FillPageTableLevel3 /* Loop until rcx is 0 */ - - mov edi, (BootPageTable + 0x2000) /* First PDE */ - mov eax, 0b10000011 /* Present, Write, Large Page */ - - mov ecx, (512 * PAGE_TABLE_SIZE) /* For loop instruction */ - mov ebx, 0x0 /* Value to store in the next 4 bytes */ - .FillPageTableLevel2: - mov dword [edi], eax /* Store modified PDE in PDPTE */ - mov dword [edi + 4], ebx /* Store the rbx value in the next 4 bytes */ - add eax, 1 << 21 /* Increment (page size) */ - adc ebx, 0 /* Add 0 (carry flag) to rbx to increment if there was a carry */ - add edi, 8 /* Add 8 to rdi (next PDE) */ - loop .FillPageTableLevel2 /* Loop until rcx is 0 */ - - ret diff --git a/Architecture/amd64/Bootstrap/Multiboot/2/Start.asm b/Architecture/amd64/Bootstrap/Multiboot/2/Start.asm deleted file mode 100644 index 9f28534e..00000000 --- a/Architecture/amd64/Bootstrap/Multiboot/2/Start.asm +++ /dev/null @@ -1,112 +0,0 @@ -; This file is part of Fennix Kernel. -; -; Fennix Kernel is free software: you can redistribute it and/or -; modify it under the terms of the GNU General Public License as -; published by the Free Software Foundation, either version 3 of -; the License, or (at your option) any later version. -; -; Fennix Kernel is distributed in the hope that it will be useful, -; but WITHOUT ANY WARRANTY; without even the implied warranty of -; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -; GNU General Public License for more details. -; -; You should have received a copy of the GNU General Public License -; along with Fennix Kernel. If not, see . - -[bits 32] -KERNEL_STACK_SIZE equ 0x4000 ; 16KB - -extern DetectCPUID -extern Detect64Bit -extern DetectPSE -extern DetectPAE -extern multiboot_main -extern LoadGDT32 -extern BootPageTable -extern UpdatePageTable -extern GDT64.Ptr -extern GDT64.Code -extern GDT64.Data - -section .bootstrap.data -MB_HeaderMagic: - dq 0 - -MB_HeaderInfo: - dq 0 - -section .bootstrap.text - -global Multiboot2_start -Multiboot2_start: - cli - - mov [MB_HeaderMagic], eax - mov [MB_HeaderInfo], ebx - - call DetectCPUID - cmp eax, 0 - je $ - - call Detect64Bit - cmp eax, 0 - je $ - - call DetectPSE - cmp eax, 0 - je $ - - call DetectPAE - cmp eax, 0 - je $ - - mov ecx, cr4 - or ecx, 0x00000010 ; Set PSE in CR4 - or ecx, 0x00000020 ; Set PAE in CR4 - mov cr4, ecx - - call LoadGDT32 - call UpdatePageTable - - mov ecx, BootPageTable - mov cr3, ecx - - mov ecx, 0xC0000080 ; EFER - rdmsr - or eax, 0x800 | 0x100 | 0x1 ; Set LME, LMA, SCE - wrmsr - - mov ecx, cr0 - or ecx, 0x80000001 ; Set PG and PE in CR0 - mov cr0, ecx - - lgdt [GDT64.Ptr] - jmp GDT64.Code:HigherHalfStart - -extern UpdatePageTable64 - -[bits 64] -HigherHalfStart: - mov ax, GDT64.Data - mov ds, ax - mov es, ax - mov fs, ax - mov gs, ax - mov ss, ax - - call UpdatePageTable64 - - mov rsp, KernelStack + KERNEL_STACK_SIZE - mov rdi, [MB_HeaderMagic] - mov rsi, [MB_HeaderInfo] - push rsi - push rdi - call multiboot_main -.Hang: - hlt - jmp .Hang - -section .bootstrap.bss -align 16 -KernelStack: - resb KERNEL_STACK_SIZE diff --git a/Architecture/amd64/Bootstrap/Multiboot/2/Start.s_fixme b/Architecture/amd64/Bootstrap/Multiboot/2/Start.s similarity index 64% rename from Architecture/amd64/Bootstrap/Multiboot/2/Start.s_fixme rename to Architecture/amd64/Bootstrap/Multiboot/2/Start.s index 8076319c..c9965c6d 100644 --- a/Architecture/amd64/Bootstrap/Multiboot/2/Start.s_fixme +++ b/Architecture/amd64/Bootstrap/Multiboot/2/Start.s @@ -15,10 +15,8 @@ along with Fennix Kernel. If not, see . */ -.intel_syntax noprefix - .code32 -.equ KERNEL_STACK_SIZE, 0x4000 /* 16KB */ +KERNEL_STACK_SIZE = 0x4000 /* 16KB */ .extern DetectCPUID .extern Detect64Bit @@ -45,67 +43,71 @@ MB_HeaderInfo: Multiboot2_start: cli - mov [MB_HeaderMagic], eax - mov [MB_HeaderInfo], ebx + mov %eax, [MB_HeaderMagic] + mov %ebx, [MB_HeaderInfo] call DetectCPUID - cmp eax, 0 - je $ + cmp $0, %eax + je . call Detect64Bit - cmp eax, 0 - je $ + cmp $0, %eax + je . call DetectPSE - cmp eax, 0 - je $ + cmp $0, %eax + je . call DetectPAE - cmp eax, 0 - je $ + cmp $0, %eax + je . - mov ecx, cr4 - or ecx, 0x00000010 /* Set PSE in CR4 */ - or ecx, 0x00000020 /* Set PAE in CR4 */ - mov cr4, ecx + mov %cr4, %ecx + or $0x00000010, %ecx /* PSE */ + or $0x00000020, %ecx /* PAE */ + mov %ecx, %cr4 call LoadGDT32 call UpdatePageTable - mov ecx, BootPageTable - mov cr3, ecx + mov $BootPageTable, %ecx + mov %ecx, %cr3 - mov ecx, 0xC0000080 /* EFER */ + mov $0xC0000080, %ecx /* EFER */ rdmsr - or eax, 0x800 | 0x100 | 0x1 /* Set LME, LMA, SCE */ + or $0x800, %eax /* LME */ + or $0x100, %eax /* LMA */ + or $0x1, %eax /* SCE */ wrmsr - mov ecx, cr0 - or ecx, 0x80000001 /* Set PG and PE in CR0 */ - mov cr0, ecx + mov %cr0, %ecx + or $0x80000000, %ecx /* PG */ + or $0x1, %ecx /* PE */ + mov %ecx, %cr0 lgdt [GDT64.Ptr] - jmp GDT64.Code:HigherHalfStart + ljmp $GDT64.Code, $HigherHalfStart .extern UpdatePageTable64 .code64 HigherHalfStart: - mov ax, GDT64.Data - mov ds, ax - mov es, ax - mov fs, ax - mov gs, ax - mov ss, ax + mov GDT64.Data, %ax + mov %ax, %ds + mov %ax, %es + mov %ax, %fs + mov %ax, %gs + mov %ax, %ss call UpdatePageTable64 - mov rsp, KernelStack + KERNEL_STACK_SIZE - mov rbp, 0 - mov rdi, [MB_HeaderMagic] - mov rsi, [MB_HeaderInfo] - push rsi - push rdi + mov $(KernelStack + KERNEL_STACK_SIZE), %rsp + mov $0x0, %rbp + + mov [MB_HeaderMagic], %rdi + mov [MB_HeaderInfo], %rsi + push %rsi + push %rdi call multiboot_main .Hang: hlt diff --git a/Architecture/amd64/cpu/AdvancedProgrammableInterruptController.cpp b/Architecture/amd64/cpu/AdvancedProgrammableInterruptController.cpp index c19b7358..4faa54b8 100644 --- a/Architecture/amd64/cpu/AdvancedProgrammableInterruptController.cpp +++ b/Architecture/amd64/cpu/AdvancedProgrammableInterruptController.cpp @@ -42,362 +42,363 @@ warning: left shift count >= width of type namespace APIC { - // headache - // https://www.amd.com/system/files/TechDocs/24593.pdf - // https://www.naic.edu/~phil/software/intel/318148.pdf + // headache + // https://www.amd.com/system/files/TechDocs/24593.pdf + // https://www.naic.edu/~phil/software/intel/318148.pdf - uint32_t APIC::Read(uint32_t Register) - { + uint32_t APIC::Read(uint32_t Register) + { #ifdef DEBUG - if (Register != APIC_ICRLO && - Register != APIC_ICRHI && - Register != APIC_ID) - debug("APIC::Read(%#lx) [x2=%d]", Register, x2APICSupported ? 1 : 0); + if (Register != APIC_ICRLO && + Register != APIC_ICRHI && + Register != APIC_ID) + debug("APIC::Read(%#lx) [x2=%d]", Register, x2APICSupported ? 1 : 0); #endif - if (x2APICSupported) - { - if (Register != APIC_ICRHI) - return s_cst(uint32_t, rdmsr((Register >> 4) + 0x800)); - else - return s_cst(uint32_t, rdmsr(0x30 + 0x800)); - } - else - { - CPU::MemBar::Barrier(); - uint32_t ret = *((volatile uint32_t *)((uintptr_t)APICBaseAddress + Register)); - CPU::MemBar::Barrier(); - return ret; - } - } + if (x2APICSupported) + { + if (Register != APIC_ICRHI) + return s_cst(uint32_t, rdmsr((Register >> 4) + 0x800)); + else + return s_cst(uint32_t, rdmsr(0x30 + 0x800)); + } + else + { + CPU::MemBar::Barrier(); + uint32_t ret = *((volatile uint32_t *)((uintptr_t)APICBaseAddress + Register)); + CPU::MemBar::Barrier(); + return ret; + } + } - void APIC::Write(uint32_t Register, uint32_t Value) - { + void APIC::Write(uint32_t Register, uint32_t Value) + { #ifdef DEBUG - if (Register != APIC_EOI && - Register != APIC_TDCR && - Register != APIC_TIMER && - Register != APIC_TICR && - Register != APIC_ICRLO && - Register != APIC_ICRHI) - debug("APIC::Write(%#lx, %#lx) [x2=%d]", Register, Value, x2APICSupported ? 1 : 0); + if (Register != APIC_EOI && + Register != APIC_TDCR && + Register != APIC_TIMER && + Register != APIC_TICR && + Register != APIC_ICRLO && + Register != APIC_ICRHI) + debug("APIC::Write(%#lx, %#lx) [x2=%d]", Register, Value, x2APICSupported ? 1 : 0); #endif - if (x2APICSupported) - { - if (Register != APIC_ICRHI) - wrmsr((Register >> 4) + 0x800, Value); - else - wrmsr(MSR_X2APIC_ICR, Value); - } - else - { - CPU::MemBar::Barrier(); - *((volatile uint32_t *)(((uintptr_t)APICBaseAddress) + Register)) = Value; - CPU::MemBar::Barrier(); - } - } + if (x2APICSupported) + { + if (Register != APIC_ICRHI) + wrmsr((Register >> 4) + 0x800, Value); + else + wrmsr(MSR_X2APIC_ICR, Value); + } + else + { + CPU::MemBar::Barrier(); + *((volatile uint32_t *)(((uintptr_t)APICBaseAddress) + Register)) = Value; + CPU::MemBar::Barrier(); + } + } - void APIC::IOWrite(uint64_t Base, uint32_t Register, uint32_t Value) - { - debug("APIC::IOWrite(%#lx, %#lx, %#lx)", Base, Register, Value); - CPU::MemBar::Barrier(); - *((volatile uint32_t *)(((uintptr_t)Base))) = Register; - CPU::MemBar::Barrier(); - *((volatile uint32_t *)(((uintptr_t)Base + 16))) = Value; - CPU::MemBar::Barrier(); - } + void APIC::IOWrite(uint64_t Base, uint32_t Register, uint32_t Value) + { + debug("APIC::IOWrite(%#lx, %#lx, %#lx)", Base, Register, Value); + CPU::MemBar::Barrier(); + *((volatile uint32_t *)(((uintptr_t)Base))) = Register; + CPU::MemBar::Barrier(); + *((volatile uint32_t *)(((uintptr_t)Base + 16))) = Value; + CPU::MemBar::Barrier(); + } - uint32_t APIC::IORead(uint64_t Base, uint32_t Register) - { - debug("APIC::IORead(%#lx, %#lx)", Base, Register); - CPU::MemBar::Barrier(); - *((volatile uint32_t *)(((uintptr_t)Base))) = Register; - CPU::MemBar::Barrier(); - uint32_t ret = *((volatile uint32_t *)(((uintptr_t)Base + 16))); - CPU::MemBar::Barrier(); - return ret; - } + uint32_t APIC::IORead(uint64_t Base, uint32_t Register) + { + debug("APIC::IORead(%#lx, %#lx)", Base, Register); + CPU::MemBar::Barrier(); + *((volatile uint32_t *)(((uintptr_t)Base))) = Register; + CPU::MemBar::Barrier(); + uint32_t ret = *((volatile uint32_t *)(((uintptr_t)Base + 16))); + CPU::MemBar::Barrier(); + return ret; + } - void APIC::EOI() { this->Write(APIC_EOI, 0); } + void APIC::EOI() { this->Write(APIC_EOI, 0); } - void APIC::WaitForIPI() - { - InterruptCommandRegisterLow icr = {.raw = 0}; - do - { - icr.raw = this->Read(APIC_ICRLO); - } while (icr.DeliveryStatus != Idle); - } + void APIC::WaitForIPI() + { + InterruptCommandRegisterLow icr = {.raw = 0}; + do + { + icr.raw = this->Read(APIC_ICRLO); + CPU::Pause(); + } while (icr.DeliveryStatus != Idle); + } - void APIC::IPI(int CPU, InterruptCommandRegisterLow icr) - { - SmartCriticalSection(APICLock); - if (x2APICSupported) - { - wrmsr(MSR_X2APIC_ICR, s_cst(uint32_t, icr.raw)); - this->WaitForIPI(); - } - else - { - this->Write(APIC_ICRHI, (CPU << 24)); - this->Write(APIC_ICRLO, s_cst(uint32_t, icr.raw)); - this->WaitForIPI(); - } - } + void APIC::IPI(int CPU, InterruptCommandRegisterLow icr) + { + SmartCriticalSection(APICLock); + if (x2APICSupported) + { + wrmsr(MSR_X2APIC_ICR, s_cst(uint32_t, icr.raw)); + this->WaitForIPI(); + } + else + { + this->Write(APIC_ICRHI, (CPU << 24)); + this->Write(APIC_ICRLO, s_cst(uint32_t, icr.raw)); + this->WaitForIPI(); + } + } - void APIC::SendInitIPI(int CPU) - { - SmartCriticalSection(APICLock); - if (x2APICSupported) - { - InterruptCommandRegisterLow icr = {.raw = 0}; - icr.DeliveryMode = INIT; - icr.Level = Assert; - wrmsr(MSR_X2APIC_ICR, s_cst(uint32_t, icr.raw)); - this->WaitForIPI(); - } - else - { - InterruptCommandRegisterLow icr = {.raw = 0}; - icr.DeliveryMode = INIT; - icr.Level = Assert; - this->Write(APIC_ICRHI, (CPU << 24)); - this->Write(APIC_ICRLO, s_cst(uint32_t, icr.raw)); - this->WaitForIPI(); - } - } + void APIC::SendInitIPI(int CPU) + { + SmartCriticalSection(APICLock); + if (x2APICSupported) + { + InterruptCommandRegisterLow icr = {.raw = 0}; + icr.DeliveryMode = INIT; + icr.Level = Assert; + wrmsr(MSR_X2APIC_ICR, s_cst(uint32_t, icr.raw)); + this->WaitForIPI(); + } + else + { + InterruptCommandRegisterLow icr = {.raw = 0}; + icr.DeliveryMode = INIT; + icr.Level = Assert; + this->Write(APIC_ICRHI, (CPU << 24)); + this->Write(APIC_ICRLO, s_cst(uint32_t, icr.raw)); + this->WaitForIPI(); + } + } - void APIC::SendStartupIPI(int CPU, uint64_t StartupAddress) - { - SmartCriticalSection(APICLock); - if (x2APICSupported) - { - InterruptCommandRegisterLow icr = {.raw = 0}; - icr.Vector = s_cst(uint8_t, StartupAddress >> 12); - icr.DeliveryMode = Startup; - icr.Level = Assert; - wrmsr(MSR_X2APIC_ICR, s_cst(uint32_t, icr.raw)); - this->WaitForIPI(); - } - else - { - InterruptCommandRegisterLow icr = {.raw = 0}; - icr.Vector = s_cst(uint8_t, StartupAddress >> 12); - icr.DeliveryMode = Startup; - icr.Level = Assert; - this->Write(APIC_ICRHI, (CPU << 24)); - this->Write(APIC_ICRLO, s_cst(uint32_t, icr.raw)); - this->WaitForIPI(); - } - } + void APIC::SendStartupIPI(int CPU, uint64_t StartupAddress) + { + SmartCriticalSection(APICLock); + if (x2APICSupported) + { + InterruptCommandRegisterLow icr = {.raw = 0}; + icr.Vector = s_cst(uint8_t, StartupAddress >> 12); + icr.DeliveryMode = Startup; + icr.Level = Assert; + wrmsr(MSR_X2APIC_ICR, s_cst(uint32_t, icr.raw)); + this->WaitForIPI(); + } + else + { + InterruptCommandRegisterLow icr = {.raw = 0}; + icr.Vector = s_cst(uint8_t, StartupAddress >> 12); + icr.DeliveryMode = Startup; + icr.Level = Assert; + this->Write(APIC_ICRHI, (CPU << 24)); + this->Write(APIC_ICRLO, s_cst(uint32_t, icr.raw)); + this->WaitForIPI(); + } + } - uint32_t APIC::IOGetMaxRedirect(uint32_t APICID) - { - uint32_t TableAddress = (this->IORead((((ACPI::MADT *)PowerManager->GetMADT())->ioapic[APICID]->Address), GetIOAPICVersion)); - return ((IOAPICVersion *)&TableAddress)->MaximumRedirectionEntry; - } + uint32_t APIC::IOGetMaxRedirect(uint32_t APICID) + { + uint32_t TableAddress = (this->IORead((((ACPI::MADT *)PowerManager->GetMADT())->ioapic[APICID]->Address), GetIOAPICVersion)); + return ((IOAPICVersion *)&TableAddress)->MaximumRedirectionEntry; + } - void APIC::RawRedirectIRQ(uint16_t Vector, uint32_t GSI, uint16_t Flags, int CPU, int Status) - { - uint64_t Value = Vector; + void APIC::RawRedirectIRQ(uint16_t Vector, uint32_t GSI, uint16_t Flags, int CPU, int Status) + { + uint64_t Value = Vector; - int64_t IOAPICTarget = -1; - for (uint64_t i = 0; ((ACPI::MADT *)PowerManager->GetMADT())->ioapic[i] != 0; i++) - if (((ACPI::MADT *)PowerManager->GetMADT())->ioapic[i]->GSIBase <= GSI) - if (((ACPI::MADT *)PowerManager->GetMADT())->ioapic[i]->GSIBase + IOGetMaxRedirect(s_cst(uint32_t, i)) > GSI) - { - IOAPICTarget = i; - break; - } + int64_t IOAPICTarget = -1; + for (uint64_t i = 0; ((ACPI::MADT *)PowerManager->GetMADT())->ioapic[i] != 0; i++) + if (((ACPI::MADT *)PowerManager->GetMADT())->ioapic[i]->GSIBase <= GSI) + if (((ACPI::MADT *)PowerManager->GetMADT())->ioapic[i]->GSIBase + IOGetMaxRedirect(s_cst(uint32_t, i)) > GSI) + { + IOAPICTarget = i; + break; + } - if (IOAPICTarget == -1) - { - error("No ISO table found for I/O APIC"); - return; - } + if (IOAPICTarget == -1) + { + error("No ISO table found for I/O APIC"); + return; + } - // TODO: IOAPICRedirectEntry Entry = {.raw = 0}; + // TODO: IOAPICRedirectEntry Entry = {.raw = 0}; - if (Flags & ActiveHighLow) - Value |= (1 << 13); + if (Flags & ActiveHighLow) + Value |= (1 << 13); - if (Flags & EdgeLevel) - Value |= (1 << 15); + if (Flags & EdgeLevel) + Value |= (1 << 15); - if (!Status) - Value |= (1 << 16); + if (!Status) + Value |= (1 << 16); - Value |= (((uintptr_t)CPU) << 56); - uint32_t IORegister = (GSI - ((ACPI::MADT *)PowerManager->GetMADT())->ioapic[IOAPICTarget]->GSIBase) * 2 + 16; + Value |= (((uintptr_t)CPU) << 56); + uint32_t IORegister = (GSI - ((ACPI::MADT *)PowerManager->GetMADT())->ioapic[IOAPICTarget]->GSIBase) * 2 + 16; - this->IOWrite(((ACPI::MADT *)PowerManager->GetMADT())->ioapic[IOAPICTarget]->Address, IORegister, (uint32_t)Value); - this->IOWrite(((ACPI::MADT *)PowerManager->GetMADT())->ioapic[IOAPICTarget]->Address, IORegister + 1, (uint32_t)(Value >> 32)); - } + this->IOWrite(((ACPI::MADT *)PowerManager->GetMADT())->ioapic[IOAPICTarget]->Address, IORegister, (uint32_t)Value); + this->IOWrite(((ACPI::MADT *)PowerManager->GetMADT())->ioapic[IOAPICTarget]->Address, IORegister + 1, (uint32_t)(Value >> 32)); + } - void APIC::RedirectIRQ(int CPU, uint16_t IRQ, int Status) - { - for (uint64_t i = 0; i < ((ACPI::MADT *)PowerManager->GetMADT())->iso.size(); i++) - if (((ACPI::MADT *)PowerManager->GetMADT())->iso[i]->IRQSource == IRQ) - { - debug("[ISO %d] Mapping to source IRQ%#d GSI:%#lx on CPU %d", - i, ((ACPI::MADT *)PowerManager->GetMADT())->iso[i]->IRQSource, ((ACPI::MADT *)PowerManager->GetMADT())->iso[i]->GSI, CPU); + void APIC::RedirectIRQ(int CPU, uint16_t IRQ, int Status) + { + for (uint64_t i = 0; i < ((ACPI::MADT *)PowerManager->GetMADT())->iso.size(); i++) + if (((ACPI::MADT *)PowerManager->GetMADT())->iso[i]->IRQSource == IRQ) + { + debug("[ISO %d] Mapping to source IRQ%#d GSI:%#lx on CPU %d", + i, ((ACPI::MADT *)PowerManager->GetMADT())->iso[i]->IRQSource, ((ACPI::MADT *)PowerManager->GetMADT())->iso[i]->GSI, CPU); - this->RawRedirectIRQ(((ACPI::MADT *)PowerManager->GetMADT())->iso[i]->IRQSource + 0x20, ((ACPI::MADT *)PowerManager->GetMADT())->iso[i]->GSI, ((ACPI::MADT *)PowerManager->GetMADT())->iso[i]->Flags, CPU, Status); - return; - } - debug("Mapping IRQ%d on CPU %d", IRQ, CPU); - this->RawRedirectIRQ(IRQ + 0x20, IRQ, 0, CPU, Status); - } + this->RawRedirectIRQ(((ACPI::MADT *)PowerManager->GetMADT())->iso[i]->IRQSource + 0x20, ((ACPI::MADT *)PowerManager->GetMADT())->iso[i]->GSI, ((ACPI::MADT *)PowerManager->GetMADT())->iso[i]->Flags, CPU, Status); + return; + } + debug("Mapping IRQ%d on CPU %d", IRQ, CPU); + this->RawRedirectIRQ(IRQ + 0x20, IRQ, 0, CPU, Status); + } - void APIC::RedirectIRQs(int CPU) - { - SmartCriticalSection(APICLock); - debug("Redirecting IRQs..."); - for (uint8_t i = 0; i < 16; i++) - this->RedirectIRQ(CPU, i, 1); - debug("Redirecting IRQs completed."); - } + void APIC::RedirectIRQs(int CPU) + { + SmartCriticalSection(APICLock); + debug("Redirecting IRQs..."); + for (uint8_t i = 0; i < 16; i++) + this->RedirectIRQ(CPU, i, 1); + debug("Redirecting IRQs completed."); + } - APIC::APIC(int Core) - { - SmartCriticalSection(APICLock); - APIC_BASE BaseStruct = {.raw = rdmsr(MSR_APIC_BASE)}; - uint64_t BaseLow = BaseStruct.ApicBaseLo; - uint64_t BaseHigh = BaseStruct.ApicBaseHi; - this->APICBaseAddress = BaseLow << 12u | BaseHigh << 32u; - trace("APIC Address: %#lx", this->APICBaseAddress); - Memory::Virtual().Map((void *)this->APICBaseAddress, (void *)this->APICBaseAddress, Memory::PTFlag::RW | Memory::PTFlag::PCD); + APIC::APIC(int Core) + { + SmartCriticalSection(APICLock); + APIC_BASE BaseStruct = {.raw = rdmsr(MSR_APIC_BASE)}; + uint64_t BaseLow = BaseStruct.ApicBaseLo; + uint64_t BaseHigh = BaseStruct.ApicBaseHi; + this->APICBaseAddress = BaseLow << 12u | BaseHigh << 32u; + trace("APIC Address: %#lx", this->APICBaseAddress); + Memory::Virtual().Map((void *)this->APICBaseAddress, (void *)this->APICBaseAddress, Memory::PTFlag::RW | Memory::PTFlag::PCD); - bool x2APICSupported = false; - if (strcmp(CPU::Vendor(), x86_CPUID_VENDOR_AMD) == 0) - { - CPU::x86::AMD::CPUID0x00000001 cpuid; - cpuid.Get(); - if (cpuid.ECX.x2APIC) - { - // x2APICSupported = cpuid.ECX.x2APIC; - fixme("x2APIC is supported"); - } - } - else if (strcmp(CPU::Vendor(), x86_CPUID_VENDOR_INTEL) == 0) - { - CPU::x86::Intel::CPUID0x00000001 cpuid; - cpuid.Get(); - if (cpuid.ECX.x2APIC) - { - // x2APICSupported = cpuid.ECX.x2APIC; - fixme("x2APIC is supported"); - } - } + bool x2APICSupported = false; + if (strcmp(CPU::Vendor(), x86_CPUID_VENDOR_AMD) == 0) + { + CPU::x86::AMD::CPUID0x00000001 cpuid; + cpuid.Get(); + if (cpuid.ECX.x2APIC) + { + // x2APICSupported = cpuid.ECX.x2APIC; + fixme("x2APIC is supported"); + } + } + else if (strcmp(CPU::Vendor(), x86_CPUID_VENDOR_INTEL) == 0) + { + CPU::x86::Intel::CPUID0x00000001 cpuid; + cpuid.Get(); + if (cpuid.ECX.x2APIC) + { + // x2APICSupported = cpuid.ECX.x2APIC; + fixme("x2APIC is supported"); + } + } - if (x2APICSupported) - { - this->x2APICSupported = true; - wrmsr(MSR_APIC_BASE, (rdmsr(MSR_APIC_BASE) | (1 << 11)) & ~(1 << 10)); - BaseStruct.EN = 1; - wrmsr(MSR_APIC_BASE, BaseStruct.raw); - } - else - { - BaseStruct.EN = 1; - wrmsr(MSR_APIC_BASE, BaseStruct.raw); - } + if (x2APICSupported) + { + this->x2APICSupported = true; + wrmsr(MSR_APIC_BASE, (rdmsr(MSR_APIC_BASE) | (1 << 11)) & ~(1 << 10)); + BaseStruct.EN = 1; + wrmsr(MSR_APIC_BASE, BaseStruct.raw); + } + else + { + BaseStruct.EN = 1; + wrmsr(MSR_APIC_BASE, BaseStruct.raw); + } - this->Write(APIC_TPR, 0x0); - // this->Write(APIC_SVR, this->Read(APIC_SVR) | 0x100); // 0x1FF or 0x100 ? on https://wiki.osdev.org/APIC is 0x100 + this->Write(APIC_TPR, 0x0); + // this->Write(APIC_SVR, this->Read(APIC_SVR) | 0x100); // 0x1FF or 0x100 ? on https://wiki.osdev.org/APIC is 0x100 - if (!this->x2APICSupported) - { - this->Write(APIC_DFR, 0xF0000000); - this->Write(APIC_LDR, this->Read(APIC_ID)); - } + if (!this->x2APICSupported) + { + this->Write(APIC_DFR, 0xF0000000); + this->Write(APIC_LDR, this->Read(APIC_ID)); + } - ACPI::MADT *madt = (ACPI::MADT *)PowerManager->GetMADT(); + ACPI::MADT *madt = (ACPI::MADT *)PowerManager->GetMADT(); - for (size_t i = 0; i < madt->nmi.size(); i++) - { - if (madt->nmi[i]->processor != 0xFF && Core != madt->nmi[i]->processor) - return; + for (size_t i = 0; i < madt->nmi.size(); i++) + { + if (madt->nmi[i]->processor != 0xFF && Core != madt->nmi[i]->processor) + return; - uint32_t nmi = 0x402; - if (madt->nmi[i]->flags & 2) - nmi |= 1 << 13; - if (madt->nmi[i]->flags & 8) - nmi |= 1 << 15; - if (madt->nmi[i]->lint == 0) - this->Write(APIC_LINT0, nmi); - else if (madt->nmi[i]->lint == 1) - this->Write(APIC_LINT1, nmi); - } + uint32_t nmi = 0x402; + if (madt->nmi[i]->flags & 2) + nmi |= 1 << 13; + if (madt->nmi[i]->flags & 8) + nmi |= 1 << 15; + if (madt->nmi[i]->lint == 0) + this->Write(APIC_LINT0, nmi); + else if (madt->nmi[i]->lint == 1) + this->Write(APIC_LINT1, nmi); + } - // Setup the spurrious interrupt vector - Spurious Spurious = {.raw = this->Read(APIC_SVR)}; - Spurious.Vector = IRQ223; // TODO: Should I map the IRQ to something? - Spurious.Software = 1; - this->Write(APIC_SVR, s_cst(uint32_t, Spurious.raw)); + // Setup the spurrious interrupt vector + Spurious Spurious = {.raw = this->Read(APIC_SVR)}; + Spurious.Vector = IRQ223; // TODO: Should I map the IRQ to something? + Spurious.Software = 1; + this->Write(APIC_SVR, s_cst(uint32_t, Spurious.raw)); - static int once = 0; - if (!once++) - { - // Disable PIT - outb(0x43, 0x28); - outb(0x40, 0x0); + static int once = 0; + if (!once++) + { + // Disable PIT + outb(0x43, 0x28); + outb(0x40, 0x0); - // Disable PIC - outb(0x21, 0xFF); - outb(0xA1, 0xFF); - } - } + // Disable PIC + outb(0x21, 0xFF); + outb(0xA1, 0xFF); + } + } - APIC::~APIC() {} + APIC::~APIC() {} - void Timer::OnInterruptReceived(TrapFrame *Frame) { UNUSED(Frame); } + void Timer::OnInterruptReceived(TrapFrame *Frame) { UNUSED(Frame); } - void Timer::OneShot(uint32_t Vector, uint64_t Miliseconds) - { - SmartCriticalSection(APICLock); - LVTTimer timer = {.raw = 0}; - timer.Vector = s_cst(uint8_t, Vector); - timer.TimerMode = 0; - if (strcmp(CPU::Hypervisor(), x86_CPUID_VENDOR_TCG) != 0) - this->lapic->Write(APIC_TDCR, DivideBy128); - else - this->lapic->Write(APIC_TDCR, DivideBy16); - this->lapic->Write(APIC_TICR, s_cst(uint32_t, Ticks * Miliseconds)); - this->lapic->Write(APIC_TIMER, s_cst(uint32_t, timer.raw)); - } + void Timer::OneShot(uint32_t Vector, uint64_t Miliseconds) + { + SmartCriticalSection(APICLock); + LVTTimer timer = {.raw = 0}; + timer.Vector = s_cst(uint8_t, Vector); + timer.TimerMode = 0; + if (strcmp(CPU::Hypervisor(), x86_CPUID_VENDOR_TCG) != 0) + this->lapic->Write(APIC_TDCR, DivideBy128); + else + this->lapic->Write(APIC_TDCR, DivideBy16); + this->lapic->Write(APIC_TICR, s_cst(uint32_t, Ticks * Miliseconds)); + this->lapic->Write(APIC_TIMER, s_cst(uint32_t, timer.raw)); + } - Timer::Timer(APIC *apic) : Interrupts::Handler(0) /* IRQ0 */ - { - SmartCriticalSection(APICLock); - this->lapic = apic; - LVTTimerDivide Divider = DivideBy16; + Timer::Timer(APIC *apic) : Interrupts::Handler(0) /* IRQ0 */ + { + SmartCriticalSection(APICLock); + this->lapic = apic; + LVTTimerDivide Divider = DivideBy16; - trace("Initializing APIC timer on CPU %d", GetCurrentCPU()->ID); + trace("Initializing APIC timer on CPU %d", GetCurrentCPU()->ID); - this->lapic->Write(APIC_TDCR, Divider); - this->lapic->Write(APIC_TICR, 0xFFFFFFFF); + this->lapic->Write(APIC_TDCR, Divider); + this->lapic->Write(APIC_TICR, 0xFFFFFFFF); - TimeManager->Sleep(1, Time::Units::Milliseconds); + TimeManager->Sleep(1, Time::Units::Milliseconds); - // Mask the timer - this->lapic->Write(APIC_TIMER, 0x10000 /* LVTTimer.Mask flag */); - Ticks = 0xFFFFFFFF - this->lapic->Read(APIC_TCCR); + // Mask the timer + this->lapic->Write(APIC_TIMER, 0x10000 /* LVTTimer.Mask flag */); + Ticks = 0xFFFFFFFF - this->lapic->Read(APIC_TCCR); - // Config for IRQ0 timer - LVTTimer timer = {.raw = 0}; - timer.Vector = IRQ0; - timer.Mask = Unmasked; - timer.TimerMode = LVTTimerMode::OneShot; + // Config for IRQ0 timer + LVTTimer timer = {.raw = 0}; + timer.Vector = IRQ0; + timer.Mask = Unmasked; + timer.TimerMode = LVTTimerMode::OneShot; - // Initialize APIC timer - this->lapic->Write(APIC_TDCR, Divider); - this->lapic->Write(APIC_TICR, s_cst(uint32_t, Ticks)); - this->lapic->Write(APIC_TIMER, s_cst(uint32_t, timer.raw)); - trace("%d APIC Timer %d ticks in.", GetCurrentCPU()->ID, Ticks); - KPrint("APIC Timer: \e8888FF%ld\eCCCCCC ticks.", Ticks); - } + // Initialize APIC timer + this->lapic->Write(APIC_TDCR, Divider); + this->lapic->Write(APIC_TICR, s_cst(uint32_t, Ticks)); + this->lapic->Write(APIC_TIMER, s_cst(uint32_t, timer.raw)); + trace("%d APIC Timer %d ticks in.", GetCurrentCPU()->ID, Ticks); + KPrint("APIC Timer: \e8888FF%ld\eCCCCCC ticks.", Ticks); + } - Timer::~Timer() - { - } + Timer::~Timer() + { + } } diff --git a/Architecture/amd64/cpu/SMPTrampoline.asm b/Architecture/amd64/cpu/SMPTrampoline.asm deleted file mode 100644 index ca690e67..00000000 --- a/Architecture/amd64/cpu/SMPTrampoline.asm +++ /dev/null @@ -1,136 +0,0 @@ -; This file is part of Fennix Kernel. -; -; Fennix Kernel is free software: you can redistribute it and/or -; modify it under the terms of the GNU General Public License as -; published by the Free Software Foundation, either version 3 of -; the License, or (at your option) any later version. -; -; Fennix Kernel is distributed in the hope that it will be useful, -; but WITHOUT ANY WARRANTY; without even the implied warranty of -; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -; GNU General Public License for more details. -; -; You should have received a copy of the GNU General Public License -; along with Fennix Kernel. If not, see . - -; This has to be the same as enum SMPTrampolineAddress. -TRAMPOLINE_PAGE_TABLE equ 0x500 -TRAMPOLINE_START_ADDR equ 0x520 -TRAMPOLINE_STACK equ 0x570 -TRAMPOLINE_GDT equ 0x580 -TRAMPOLINE_IDT equ 0x590 -TRAMPOLINE_CORE equ 0x600 -TRAMPOLINE_START equ 0x2000 - -[bits 16] - -extern StartCPU -global _trampoline_start -_trampoline_start: - cli - mov ax, 0x0 - mov ds, ax - mov es, ax - mov fs, ax - mov gs, ax - mov ss, ax - o32 lgdt [ProtectedMode_gdtr - _trampoline_start + TRAMPOLINE_START] - mov eax, cr0 - or al, 0x1 - mov cr0, eax - jmp 0x8:(Trampoline32 - _trampoline_start + TRAMPOLINE_START) - -[bits 32] -section .text -Trampoline32: - mov bx, 0x10 - mov ds, bx - mov es, bx - mov ss, bx - mov eax, dword [TRAMPOLINE_PAGE_TABLE] - mov cr3, eax - mov eax, cr4 - or eax, 1 << 5 ; Set the PAE-bit, which is the 6th bit (bit 5). - or eax, 1 << 7 - mov cr4, eax - mov ecx, 0xc0000080 - rdmsr - or eax,1 << 8 ; LME - wrmsr - mov eax, cr0 - or eax, 1 << 31 - mov cr0, eax - lgdt [LongMode_gdtr - _trampoline_start + TRAMPOLINE_START] - jmp 0x8:(Trampoline64 - _trampoline_start + TRAMPOLINE_START) - -[bits 64] -Trampoline64: - mov ax, 0x10 - mov ds, ax - mov es, ax - mov ss, ax - mov ax, 0x0 - mov fs, ax - mov gs, ax - lgdt [TRAMPOLINE_GDT] - lidt [TRAMPOLINE_IDT] - mov rsp, [TRAMPOLINE_STACK] - mov rbp, 0x0 ; Terminate stack traces here. - ; Reset RFLAGS. - push 0x0 - popf - mov rax, qword vcode64 - call vcode64 - -vcode64: - push rbp - ; Set up SSE - mov rax, cr0 - ; btr eax, 2 - ; bts eax, 1 - ; mov cr0, rax - mov rax, cr4 - bts eax, 9 - bts eax, 10 - mov cr4, rax - mov rax, qword TrampolineExit - call rax - -align 16 -LongMode_gdtr: - dw LongModeGDTEnd - LongModeGDTStart - 1 - dq LongModeGDTStart - _trampoline_start + TRAMPOLINE_START - -align 16 -LongModeGDTStart: - dq 0 ; NULL segment - dq 0x00AF98000000FFFF ; Code segment - dq 0x00CF92000000FFFF ; Data segment -LongModeGDTEnd: - -align 16 -ProtectedMode_gdtr: - dw ProtectedModeGDTEnd - ProtectedModeGDTStart - 1 - dd ProtectedModeGDTStart - _trampoline_start + TRAMPOLINE_START - -align 16 -ProtectedModeGDTStart: - dq 0 ; NULL segment - dq 0x00CF9A000000FFFF ; Code segment - dq 0x00CF92000000FFFF ; Data segment -ProtectedModeGDTEnd: - -align 16 -ProtectedMode_idtr: - dw 0 - dd 0 - dd 0 - align 16 - -global _trampoline_end -_trampoline_end: - -TrampolineExit: - call StartCPU - -times 512 - ($-$$) db 0 diff --git a/Architecture/amd64/cpu/SMPTrampoline.s b/Architecture/amd64/cpu/SMPTrampoline.s new file mode 100644 index 00000000..71794432 --- /dev/null +++ b/Architecture/amd64/cpu/SMPTrampoline.s @@ -0,0 +1,179 @@ +/* + This file is part of Fennix Kernel. + + Fennix Kernel is free software: you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation, either version 3 of + the License, or (at your option) any later version. + + Fennix Kernel is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Fennix Kernel. If not, see . +*/ + +/* This has to be the same as enum SMPTrampolineAddress. */ +TRAMPOLINE_PAGE_TABLE = 0x500 +TRAMPOLINE_START_ADDR = 0x520 +TRAMPOLINE_STACK = 0x570 +TRAMPOLINE_GDT = 0x580 +TRAMPOLINE_IDT = 0x590 +TRAMPOLINE_CORE = 0x600 +TRAMPOLINE_START = 0x2000 + +.section .text + +/* ========== 16-bit ========== */ + +.code16 +.global _trampoline_start +_trampoline_start: + cli + cld + call Trampoline16 + +Trampoline16: + mov $0x0, %ax + mov %ax, %ds + mov %ax, %es + mov %ax, %fs + mov %ax, %gs + mov %ax, %ss + + /* Load Protected Mode GDT */ + lgdt [ProtectedMode_gdtr - _trampoline_start + TRAMPOLINE_START] + + /* Enable Protected Mode */ + mov %cr0, %eax + or $0x1, %al + mov %eax, %cr0 + + /* Jump to Protected Mode */ + ljmp $0x8, $(Trampoline32 - _trampoline_start + TRAMPOLINE_START) + +/* ========== 32-bit ========== */ + +.code32 +Trampoline32: + mov $0x10, %bx + mov %bx, %ds + mov %bx, %es + mov %bx, %ss + + /* Set a page table */ + mov [TRAMPOLINE_PAGE_TABLE], %eax + mov %eax, %cr3 + + /* Enable PAE and PSE */ + mov %cr4, %eax + or $0x20, %eax /* PAE */ + or $0x80, %eax /* PSE */ + mov %eax, %cr4 + + /* Enable Long Mode */ + mov $0xC0000080, %ecx + rdmsr + or $0x100, %eax /* LME */ + wrmsr + + /* Enable paging */ + mov %cr0, %eax + or $0x80000000, %eax /* PG */ + mov %eax, %cr0 + + /* Load Long Mode GDT */ + lgdt [LongMode_gdtr - _trampoline_start + TRAMPOLINE_START] + + /* Jump to Long Mode */ + ljmp $0x8, $(Trampoline64 - _trampoline_start + TRAMPOLINE_START) + +/* ========== 64-bit ========== */ + +.code64 +Trampoline64: + mov $0x10, %ax + mov %ax, %ds + mov %ax, %es + mov %ax, %ss + + mov $0x0, %ax + mov %ax, %fs + mov %ax, %gs + + /* Set custom GDT & IDT */ + lgdt [TRAMPOLINE_GDT] + lidt [TRAMPOLINE_IDT] + + /* Set up stack */ + mov [TRAMPOLINE_STACK], %rsp + mov $0x0, %rbp + + /* Reset RFLAGS */ + push $0x0 + popf + + /* Jump to TrampolinePrepareExit */ + call TrampolineExit + +.extern StartCPU +TrampolineExit: + mov $StartCPU, %rax + call *%rax + +.align 16 +ProtectedMode_gdtr: + .word ProtectedModeGDTEnd - ProtectedModeGDTStart - 1 + .long ProtectedModeGDTStart - _trampoline_start + TRAMPOLINE_START + +.align 16 +ProtectedModeGDTStart: + /* NULL segment */ + .quad 0x0 + + /* Code segment */ + .word 0xFFFF + .word 0x0000 + .byte 0x00 + .word 0xCF9A + .byte 0x00 + + /* Data segment */ + .word 0xFFFF + .word 0x0000 + .byte 0x00 + .word 0xCF92 + .byte 0x00 +ProtectedModeGDTEnd: + nop + +.align 16 +LongMode_gdtr: + .word LongModeGDTEnd - LongModeGDTStart - 1 + .quad LongModeGDTStart - _trampoline_start + TRAMPOLINE_START + +.align 16 +LongModeGDTStart: + /* NULL segment */ + .quad 0x0 + + /* Code segment */ + .word 0xFFFF + .word 0x0000 + .byte 0x00 + .word 0xAF98 + .byte 0x00 + + /* Data segment */ + .word 0xFFFF + .word 0x0000 + .byte 0x00 + .word 0xCF92 + .byte 0x00 +LongModeGDTEnd: + nop + +.global _trampoline_end +_trampoline_end: diff --git a/Architecture/amd64/cpu/SymmetricMultiprocessing.cpp b/Architecture/amd64/cpu/SymmetricMultiprocessing.cpp index fce30d26..b1bec078 100644 --- a/Architecture/amd64/cpu/SymmetricMultiprocessing.cpp +++ b/Architecture/amd64/cpu/SymmetricMultiprocessing.cpp @@ -32,13 +32,13 @@ extern "C" uint64_t _trampoline_start, _trampoline_end; /* https://wiki.osdev.org/Memory_Map_(x86) */ enum SMPTrampolineAddress { - PAGE_TABLE = 0x500, - START_ADDR = 0x520, - STACK = 0x570, - GDT = 0x580, - IDT = 0x590, - CORE = 0x600, - TRAMPOLINE_START = 0x2000 + PAGE_TABLE = 0x500, + START_ADDR = 0x520, + STACK = 0x570, + GDT = 0x580, + IDT = 0x590, + CORE = 0x600, + TRAMPOLINE_START = 0x2000 }; std::atomic_bool CPUEnabled = false; @@ -50,92 +50,106 @@ SafeFunction CPUData *GetCPU(long id) { return &CPUs[id]; } SafeFunction CPUData *GetCurrentCPU() { - if (unlikely(!Interrupts::apic[0])) - return &CPUs[0]; /* No APIC means we are on the BSP. */ + if (unlikely(!Interrupts::apic[0])) + return &CPUs[0]; /* No APIC means we are on the BSP. */ - int CoreID = ((APIC::APIC *)Interrupts::apic[0])->Read(APIC::APIC_ID) >> 24; + int CoreID = ((APIC::APIC *)Interrupts::apic[0])->Read(APIC::APIC_ID) >> 24; - if (unlikely((&CPUs[CoreID])->IsActive != true)) - { - error("CPU %d is not active!", CoreID); - assert((&CPUs[0])->IsActive == true); /* We can't continue without the BSP. */ - return &CPUs[0]; - } + if (unlikely((&CPUs[CoreID])->IsActive != true)) + { + error("CPU %d is not active!", CoreID); + assert((&CPUs[0])->IsActive == true); /* We can't continue without the BSP. */ + return &CPUs[0]; + } - assert((&CPUs[CoreID])->Checksum == CPU_DATA_CHECKSUM); /* This should never happen. */ - return &CPUs[CoreID]; + assert((&CPUs[CoreID])->Checksum == CPU_DATA_CHECKSUM); /* This should never happen. */ + return &CPUs[CoreID]; } extern "C" void StartCPU() { - CPU::Interrupts(CPU::Disable); - int CoreID = (int)*reinterpret_cast(CORE); - CPU::InitializeFeatures(CoreID); - // Initialize GDT and IDT - Interrupts::Initialize(CoreID); - Interrupts::Enable(CoreID); - Interrupts::InitializeTimer(CoreID); - asmv("mov %0, %%rsp" ::"r"((&CPUs[CoreID])->Stack)); + CPU::Interrupts(CPU::Disable); + int CoreID = (int)*reinterpret_cast(CORE); + CPU::InitializeFeatures(CoreID); + // Initialize GDT and IDT + Interrupts::Initialize(CoreID); + Interrupts::Enable(CoreID); + Interrupts::InitializeTimer(CoreID); + asmv("mov %0, %%rsp" ::"r"((&CPUs[CoreID])->Stack)); - CPU::Interrupts(CPU::Enable); - KPrint("\e058C19CPU \e8888FF%d \e058C19is online", CoreID); - CPUEnabled.store(true, std::memory_order_release); - CPU::Halt(true); + CPU::Interrupts(CPU::Enable); + KPrint("\e058C19CPU \e8888FF%d \e058C19is online", CoreID); + CPUEnabled.store(true, std::memory_order_release); + CPU::Halt(true); } namespace SMP { - int CPUCores = 0; + int CPUCores = 0; - void Initialize(void *madt) - { - int Cores = ((ACPI::MADT *)madt)->CPUCores + 1; + void Initialize(void *_madt) + { + ACPI::MADT *madt = (ACPI::MADT *)_madt; - if (Config.Cores > ((ACPI::MADT *)madt)->CPUCores + 1) - KPrint("More cores requested than available. Using %d cores", ((ACPI::MADT *)madt)->CPUCores + 1); - else if (Config.Cores != 0) - Cores = Config.Cores; + int Cores = madt->CPUCores + 1; - CPUCores = Cores; + if (Config.Cores > madt->CPUCores + 1) + KPrint("More cores requested than available. Using %d cores", madt->CPUCores + 1); + else if (Config.Cores != 0) + Cores = Config.Cores; - uint64_t TrampolineLength = (uintptr_t)&_trampoline_end - (uintptr_t)&_trampoline_start; - Memory::Virtual().Map(0x0, 0x0, Memory::PTFlag::RW); - /* We reserved the TRAMPOLINE_START address inside Physical class. */ - Memory::Virtual().Map((void *)TRAMPOLINE_START, (void *)TRAMPOLINE_START, TrampolineLength, Memory::PTFlag::RW); - memcpy((void *)TRAMPOLINE_START, &_trampoline_start, TrampolineLength); - debug("Trampoline address: %#lx-%#lx", TRAMPOLINE_START, TRAMPOLINE_START + TrampolineLength); + CPUCores = Cores; - void *CPUTmpStack = KernelAllocator.RequestPages(TO_PAGES(STACK_SIZE + 1)); - asmv("sgdt [0x580]\n" - "sidt [0x590]\n"); - VPOKE(uintptr_t, STACK) = (uintptr_t)CPUTmpStack + STACK_SIZE; - VPOKE(uintptr_t, PAGE_TABLE) = (uintptr_t)KernelPageTable; - VPOKE(uint64_t, START_ADDR) = (uintptr_t)&StartCPU; + uint64_t TrampolineLength = (uintptr_t)&_trampoline_end - (uintptr_t)&_trampoline_start; + Memory::Virtual().Map(0x0, 0x0, Memory::PTFlag::RW); + /* We reserved the TRAMPOLINE_START address inside Physical class. */ + Memory::Virtual().Map((void *)TRAMPOLINE_START, (void *)TRAMPOLINE_START, TrampolineLength, Memory::PTFlag::RW); + memcpy((void *)TRAMPOLINE_START, &_trampoline_start, TrampolineLength); + debug("Trampoline address: %#lx-%#lx", TRAMPOLINE_START, TRAMPOLINE_START + TrampolineLength); - for (int i = 0; i < Cores; i++) - { - debug("Initializing CPU %d", i); - if ((((APIC::APIC *)Interrupts::apic[0])->Read(APIC::APIC_ID) >> 24) != ((ACPI::MADT *)madt)->lapic[i]->ACPIProcessorId) - { - VPOKE(int, CORE) = i; + void *CPUTmpStack = KernelAllocator.RequestPages(TO_PAGES(STACK_SIZE + 1)); + asmv("sgdt [0x580]"); + asmv("sidt [0x590]"); + VPOKE(uintptr_t, STACK) = (uintptr_t)CPUTmpStack + STACK_SIZE; + VPOKE(uintptr_t, PAGE_TABLE) = (uintptr_t)KernelPageTable; + VPOKE(uintptr_t, START_ADDR) = (uintptr_t)&StartCPU; - ((APIC::APIC *)Interrupts::apic[0])->Write(APIC::APIC_ICRHI, (((ACPI::MADT *)madt)->lapic[i]->APICId << 24)); - ((APIC::APIC *)Interrupts::apic[0])->Write(APIC::APIC_ICRLO, 0x500); + for (int i = 0; i < Cores; i++) + { + ACPI::MADT::LocalAPIC *lapic = madt->lapic[i]; + debug("Initializing CPU %d", lapic->APICId); + if ((((APIC::APIC *)Interrupts::apic[0])->Read(APIC::APIC_ID) >> 24) != lapic->APICId) + { + VPOKE(int, CORE) = i; - ((APIC::APIC *)Interrupts::apic[0])->SendInitIPI(((ACPI::MADT *)madt)->lapic[i]->APICId); - ((APIC::APIC *)Interrupts::apic[0])->SendStartupIPI(((ACPI::MADT *)madt)->lapic[i]->APICId, TRAMPOLINE_START); + ((APIC::APIC *)Interrupts::apic[0])->Write(APIC::APIC_ICRHI, (lapic->APICId << 24)); + ((APIC::APIC *)Interrupts::apic[0])->Write(APIC::APIC_ICRLO, 0x500); - while (!CPUEnabled.load(std::memory_order_acquire)) - CPU::Pause(); - CPUEnabled.store(false, std::memory_order_release); - trace("CPU %d loaded.", ((ACPI::MADT *)madt)->lapic[i]->APICId); - } - else - KPrint("\e058C19CPU \e8888FF%d \e058C19is the BSP", ((ACPI::MADT *)madt)->lapic[i]->APICId); - } + ((APIC::APIC *)Interrupts::apic[0])->SendInitIPI(lapic->APICId); + TimeManager->Sleep(5, Time::Units::Milliseconds); + ((APIC::APIC *)Interrupts::apic[0])->SendStartupIPI(lapic->APICId, TRAMPOLINE_START); - KernelAllocator.FreePages(CPUTmpStack, TO_PAGES(STACK_SIZE + 1)); - /* We are going to unmap the page after we are done with it. */ - Memory::Virtual().Unmap(0x0); - } + debug("Waiting for CPU %d to load...", lapic->APICId); + uint64_t Timeout = TimeManager->CalculateTarget(2, Time::Units::Seconds); + while (CPUEnabled.load(std::memory_order_acquire) == false) + { + if (TimeManager->GetCounter() > Timeout) + { + error("CPU %d failed to load!", lapic->APICId); + KPrint("\eFF8C19CPU \e8888FF%d \eFF8C19failed to load!", lapic->APICId); + break; + } + CPU::Pause(); + } + trace("CPU %d loaded.", lapic->APICId); + CPUEnabled.store(false, std::memory_order_release); + } + else + KPrint("\e058C19CPU \e8888FF%d \e058C19is the BSP", lapic->APICId); + } + + KernelAllocator.FreePages(CPUTmpStack, TO_PAGES(STACK_SIZE + 1)); + /* We are going to unmap the page after we are done with it. */ + Memory::Virtual().Unmap(0x0); + } } diff --git a/Architecture/i386/Bootstrap/Multiboot/1/Start.asm b/Architecture/i386/Bootstrap/Multiboot/1/Start.asm deleted file mode 100644 index 49bc2c27..00000000 --- a/Architecture/i386/Bootstrap/Multiboot/1/Start.asm +++ /dev/null @@ -1,22 +0,0 @@ -; This file is part of Fennix Kernel. -; -; Fennix Kernel is free software: you can redistribute it and/or -; modify it under the terms of the GNU General Public License as -; published by the Free Software Foundation, either version 3 of -; the License, or (at your option) any later version. -; -; Fennix Kernel is distributed in the hope that it will be useful, -; but WITHOUT ANY WARRANTY; without even the implied warranty of -; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -; GNU General Public License for more details. -; -; You should have received a copy of the GNU General Public License -; along with Fennix Kernel. If not, see . - -[bits 32] - -section .bootstrap.text - -global Multiboot1_start -Multiboot1_start: - int3 diff --git a/Architecture/i386/Bootstrap/Multiboot/2/Multiboot_PageTable.s_fixme b/Architecture/i386/Bootstrap/Multiboot/1/Start.s similarity index 90% rename from Architecture/i386/Bootstrap/Multiboot/2/Multiboot_PageTable.s_fixme rename to Architecture/i386/Bootstrap/Multiboot/1/Start.s index 8d58c66d..8efbeb24 100644 --- a/Architecture/i386/Bootstrap/Multiboot/2/Multiboot_PageTable.s_fixme +++ b/Architecture/i386/Bootstrap/Multiboot/1/Start.s @@ -15,6 +15,9 @@ along with Fennix Kernel. If not, see . */ -.intel_syntax noprefix - .code32 +.section .bootstrap.text + +.global Multiboot1_start +Multiboot1_start: + jmp . diff --git a/Architecture/i386/Bootstrap/Multiboot/2/Multiboot_PageTable.asm b/Architecture/i386/Bootstrap/Multiboot/2/Multiboot_PageTable.asm deleted file mode 100644 index 1fefe1fb..00000000 --- a/Architecture/i386/Bootstrap/Multiboot/2/Multiboot_PageTable.asm +++ /dev/null @@ -1,46 +0,0 @@ -; This file is part of Fennix Kernel. -; -; Fennix Kernel is free software: you can redistribute it and/or -; modify it under the terms of the GNU General Public License as -; published by the Free Software Foundation, either version 3 of -; the License, or (at your option) any later version. -; -; Fennix Kernel is distributed in the hope that it will be useful, -; but WITHOUT ANY WARRANTY; without even the implied warranty of -; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -; GNU General Public License for more details. -; -; You should have received a copy of the GNU General Public License -; along with Fennix Kernel. If not, see . - -[bits 32] - -KERNEL_VIRTUAL_BASE equ 0xC0000000 ; 3GB or 0xC0000000 -KERNEL_PAGE_NUMBER equ (KERNEL_VIRTUAL_BASE >> 22) ; 768 - -section .bootstrap.data -align 0x1000 -global BootPageTable -BootPageTable: - dd 0x00000083 - dd 0x00400083 - dd 0x00800083 - dd 0x00C00083 - dd 0x01000083 - dd 0x01400083 - dd 0x01800083 - dd 0x01C00083 - dd 0x02000083 - dd 0x02400083 - times (KERNEL_PAGE_NUMBER - 10) dd 0 - dd 0x00000083 - dd 0x00400083 - dd 0x00800083 - dd 0x00C00083 - dd 0x01000083 - dd 0x01400083 - dd 0x01800083 - dd 0x01C00083 - dd 0x02000083 - dd 0x02400083 - times (1024 - KERNEL_PAGE_NUMBER - 10) dd 0 diff --git a/Architecture/i386/Bootstrap/Multiboot/2/Multiboot_PageTable.s b/Architecture/i386/Bootstrap/Multiboot/2/Multiboot_PageTable.s new file mode 100644 index 00000000..2edfa75f --- /dev/null +++ b/Architecture/i386/Bootstrap/Multiboot/2/Multiboot_PageTable.s @@ -0,0 +1,51 @@ +/* + This file is part of Fennix Kernel. + + Fennix Kernel is free software: you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation, either version 3 of + the License, or (at your option) any later version. + + Fennix Kernel is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Fennix Kernel. If not, see . +*/ + +.code32 +KERNEL_VIRTUAL_BASE = 0xC0000000 /* 3GB */ +KERNEL_PAGE_NUMBER = 768 /* KERNEL_VIRTUAL_BASE >> 22 */ + +.section .bootstrap.data +.align 0x1000 +.global BootPageTable +BootPageTable: + .long 0x00000083 + .long 0x00400083 + .long 0x00800083 + .long 0x00C00083 + .long 0x01000083 + .long 0x01400083 + .long 0x01800083 + .long 0x01C00083 + .long 0x02000083 + .long 0x02400083 + .rept (KERNEL_PAGE_NUMBER - 10) + .long 0 + .endr + .long 0x00000083 + .long 0x00400083 + .long 0x00800083 + .long 0x00C00083 + .long 0x01000083 + .long 0x01400083 + .long 0x01800083 + .long 0x01C00083 + .long 0x02000083 + .long 0x02400083 + .rept (1024 - KERNEL_PAGE_NUMBER - 10) + .long 0 + .endr diff --git a/Architecture/i386/Bootstrap/Multiboot/2/Start.asm b/Architecture/i386/Bootstrap/Multiboot/2/Start.asm deleted file mode 100644 index ae571ac8..00000000 --- a/Architecture/i386/Bootstrap/Multiboot/2/Start.asm +++ /dev/null @@ -1,86 +0,0 @@ -; This file is part of Fennix Kernel. -; -; Fennix Kernel is free software: you can redistribute it and/or -; modify it under the terms of the GNU General Public License as -; published by the Free Software Foundation, either version 3 of -; the License, or (at your option) any later version. -; -; Fennix Kernel is distributed in the hope that it will be useful, -; but WITHOUT ANY WARRANTY; without even the implied warranty of -; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -; GNU General Public License for more details. -; -; You should have received a copy of the GNU General Public License -; along with Fennix Kernel. If not, see . - -[bits 32] -KERNEL_STACK_SIZE equ 0x4000 ; 16KB - -extern DetectCPUID -extern Detect64Bit -extern DetectPSE -extern DetectPAE -extern multiboot_main -extern LoadGDT32 -extern BootPageTable - -section .bootstrap.data -MB_HeaderMagic: - dq 0 - -MB_HeaderInfo: - dq 0 - -section .bootstrap.text - -global Multiboot2_start -Multiboot2_start: - cli - - mov [MB_HeaderMagic], eax - mov [MB_HeaderInfo], ebx - - call DetectCPUID - cmp eax, 0 - je $ - - ; call Detect64Bit - ; cmp eax, 0 - ; je $ - - call DetectPSE - cmp eax, 0 - je $ - - ; call DetectPAE - ; cmp eax, 0 - ; je $ - - mov ecx, cr4 - or ecx, 0x00000010 ; Set PSE in CR4 - ; or ecx, 0x00000020 ; Set PAE in CR4 - mov cr4, ecx - - call LoadGDT32 - - mov ecx, BootPageTable - mov cr3, ecx - - mov ecx, cr0 - or ecx, 0x80000001 ; Set PG and PE in CR0 - mov cr0, ecx - - mov esp, KernelStack + KERNEL_STACK_SIZE - mov eax, [MB_HeaderMagic] - mov ebx, [MB_HeaderInfo] - push ebx - push eax - call multiboot_main -.Hang: - hlt - jmp .Hang - -section .bootstrap.bss -align 16 -KernelStack: - resb KERNEL_STACK_SIZE diff --git a/Architecture/i386/Bootstrap/Multiboot/2/Start.s b/Architecture/i386/Bootstrap/Multiboot/2/Start.s new file mode 100644 index 00000000..472fa6bc --- /dev/null +++ b/Architecture/i386/Bootstrap/Multiboot/2/Start.s @@ -0,0 +1,79 @@ +/* + This file is part of Fennix Kernel. + + Fennix Kernel is free software: you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation, either version 3 of + the License, or (at your option) any later version. + + Fennix Kernel is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Fennix Kernel. If not, see . +*/ + +.code32 +KERNEL_STACK_SIZE = 0x4000 /* 16KB */ + +.extern DetectCPUID +.extern DetectPSE +.extern multiboot_main +.extern LoadGDT32 +.extern BootPageTable + +.section .bootstrap.data +MB_HeaderMagic: + .quad 0 + +MB_HeaderInfo: + .quad 0 + +.section .bootstrap.text + +.global Multiboot2_start +Multiboot2_start: + cli + + mov %eax, [MB_HeaderMagic] + mov %ebx, [MB_HeaderInfo] + + call DetectCPUID + cmp $0, %eax + je . + + call DetectPSE + cmp $0, %eax + je . + + mov %cr4, %ecx + or $0x00000010, %ecx /* PSE */ + mov %ecx, %cr4 + + call LoadGDT32 + + mov $BootPageTable, %ecx + mov %ecx, %cr3 + + mov %cr0, %ecx + or $0x80000000, %ecx /* PG */ + mov %ecx, %cr0 + + mov $(KernelStack + KERNEL_STACK_SIZE), %esp + mov $0x0, %ebp + + mov [MB_HeaderMagic], %eax + mov [MB_HeaderInfo], %ebx + push %ebx + push %eax + call multiboot_main +.Hang: + hlt + jmp .Hang + +.section .bootstrap.bss +.align 16 +KernelStack: + .space KERNEL_STACK_SIZE diff --git a/Makefile b/Makefile index 26e3d017..d9432cf0 100644 --- a/Makefile +++ b/Makefile @@ -11,8 +11,6 @@ NM = ../$(COMPILER_PATH)/$(COMPILER_ARCH)nm OBJCOPY = ../$(COMPILER_PATH)/$(COMPILER_ARCH)objcopy OBJDUMP = ../$(COMPILER_PATH)/$(COMPILER_ARCH)objdump GDB = ../$(COMPILER_PATH)/$(COMPILER_ARCH)gdb -RUSTC = /usr/bin/rustc -NASM = /usr/bin/nasm RUST_TARGET_PATH = Architecture/$(OSARCH)/rust-target.json @@ -22,19 +20,16 @@ GIT_COMMIT_SHORT = $(shell git rev-parse --short HEAD) BMP_SOURCES = $(shell find ./ -type f -name '*.bmp') PSF_SOURCES = $(shell find ./ -type f -name '*.psf') ifeq ($(OSARCH), amd64) -ASM_SOURCES = $(shell find ./ -type f -name '*.asm' -not -path "./Architecture/i386/*" -not -path "./Architecture/aarch64/*") S_SOURCES = $(shell find ./ -type f -name '*.S' -not -path "./Architecture/i386/*" -not -path "./Architecture/aarch64/*") s_SOURCES = $(shell find ./ -type f -name '*.s' -not -path "./Architecture/i386/*" -not -path "./Architecture/aarch64/*") C_SOURCES = $(shell find ./ -type f -name '*.c' -not -path "./Architecture/i386/*" -not -path "./Architecture/aarch64/*") CPP_SOURCES = $(shell find ./ -type f -name '*.cpp' -not -path "./Architecture/i386/*" -not -path "./Architecture/aarch64/*") else ifeq ($(OSARCH), i386) -ASM_SOURCES = $(shell find ./ -type f -name '*.asm' -not -path "./Architecture/amd64/*" -not -path "./Architecture/aarch64/*") S_SOURCES = $(shell find ./ -type f -name '*.S' -not -path "./Architecture/amd64/*" -not -path "./Architecture/aarch64/*") s_SOURCES = $(shell find ./ -type f -name '*.s' -not -path "./Architecture/amd64/*" -not -path "./Architecture/aarch64/*") C_SOURCES = $(shell find ./ -type f -name '*.c' -not -path "./Architecture/amd64/*" -not -path "./Architecture/aarch64/*") CPP_SOURCES = $(shell find ./ -type f -name '*.cpp' -not -path "./Architecture/amd64/*" -not -path "./Architecture/aarch64/*") else ifeq ($(OSARCH), aarch64) -ASM_SOURCES = $(shell find ./ -type f -name '*.asm' -not -path "./Architecture/amd64/*" -not -path "./Architecture/i386/*") S_SOURCES = $(shell find ./ -type f -name '*.S' -not -path "./Architecture/amd64/*" -not -path "./Architecture/i386/*") s_SOURCES = $(shell find ./ -type f -name '*.s' -not -path "./Architecture/amd64/*" -not -path "./Architecture/i386/*") C_SOURCES = $(shell find ./ -type f -name '*.c' -not -path "./Architecture/amd64/*" -not -path "./Architecture/i386/*") @@ -98,14 +93,6 @@ LDFLAGS += -TArchitecture/aarch64/linker.ld -fPIC -pie \ endif -ifeq ($(OSARCH), amd64) -NASMFLAGS := -f elf64 -else ifeq ($(OSARCH), i386) -NASMFLAGS := -f elf32 -else ifeq ($(OSARCH), aarch64) -NASMFLAGS := -endif - # -finstrument-functions for __cyg_profile_func_enter & __cyg_profile_func_exit. Used for profiling and debugging. ifeq ($(DEBUG), 1) # CFLAGS += --coverage @@ -119,11 +106,8 @@ ifneq ($(OSARCH), aarch64) CFLAGS += -fstack-check endif LDFLAGS += -ggdb3 -O0 - NASMFLAGS += -F dwarf -g + ASFLAGS += -g --gstabs --gdwarf-5 -D WARNCFLAG += -Wno-unused-function -Wno-maybe-uninitialized -Wno-builtin-declaration-mismatch -Wno-unknown-pragmas -Wno-unused-parameter -Wno-unused-variable -ifeq ($(TESTING), 1) - CFLAGS += -DTESTING -endif endif default: @@ -156,20 +140,13 @@ $(KERNEL_FILENAME): $(OBJ) $(info Compiling $<) $(CPP) $(CFLAGS) $(CFLAG_STACK_PROTECTOR) $(WARNCFLAG) -std=c++20 -c $< -o $@ -fno-exceptions -fno-rtti -%.o: %.asm -ifeq ($(OSARCH), aarch64) - $(error aarch64 does not support NASM) -endif - $(info Compiling $<) - $(NASM) $< $(NASMFLAGS) -o $@ - %.o: %.S $(info Compiling $<) - $(AS) -c $< -o $@ + $(AS) $(ASFLAGS) -c $< -o $@ %.o: %.s $(info Compiling $<) - $(AS) -c $< -o $@ + $(AS) $(ASFLAGS) -c $< -o $@ %.o: %.psf ifeq ($(OSARCH), amd64) diff --git a/include/cpu.hpp b/include/cpu.hpp index fcea0ad4..3a6582d6 100644 --- a/include/cpu.hpp +++ b/include/cpu.hpp @@ -139,7 +139,7 @@ namespace CPU /** * @brief Pause the CPU */ - SafeFunction static inline void Pause(bool Loop = false) + SafeFunction static __always_inline inline void Pause(bool Loop = false) { do { @@ -166,15 +166,15 @@ namespace CPU { asmv("CPUStopLoop:\n" "msr daifset, #2\n" // Disable IRQs (bit 1 of the DAIF register) - "wfi\n" // Wait for Interrupt (puts the processor in low-power state until an interrupt occurs) - "b CPUStopLoop"); // Branch to the beginning of the loop + "wfi\n" // Wait for Interrupt (puts the processor in low-power state until an interrupt occurs) + "b CPUStopLoop"); // Branch to the beginning of the loop #endif } /** * @brief Halt the CPU */ - SafeFunction static inline void Halt(bool Loop = false) + SafeFunction static __always_inline inline void Halt(bool Loop = false) { do { @@ -206,7 +206,7 @@ namespace CPU void InitializeFeatures(long Core); /** @brief Get CPU counter value. */ - uintptr_t Counter(); + uint64_t Counter(); namespace x32 { @@ -280,7 +280,7 @@ namespace CPU uint32_t eax; // Accumulator uint32_t InterruptNumber; // Interrupt Number - uint32_t ErrorCode; // Error code + uint32_t ErrorCode; // Error code uint32_t eip; // Instruction Pointer uint32_t cs; // Code Segment @@ -598,7 +598,7 @@ namespace CPU uint64_t rax; // Accumulator uint64_t InterruptNumber; // Interrupt Number - uint64_t ErrorCode; // Error code + uint64_t ErrorCode; // Error code uint64_t rip; // Instruction Pointer uint64_t cs; // Code Segment @@ -911,9 +911,9 @@ namespace CPU uint64_t x29; // Frame pointer uint64_t x30; // Program counter - uint64_t sp_el0; // Stack pointer - uint64_t elr_el1; // Exception Link Register - uint64_t spsr_el1; // Saved Program Status Register + uint64_t sp_el0; // Stack pointer + uint64_t elr_el1; // Exception Link Register + uint64_t spsr_el1; // Saved Program Status Register uint64_t ErrorCode /* esr_el1 */; // Exception Syndrome Register uint64_t InterruptNumber /* iar_el1 */; // Interrupt Acknowledge Register