diff --git a/Kernel/.github/workflows/flawfinder.yml b/Kernel/.github/workflows/flawfinder.yml
new file mode 100644
index 00000000..9aab577d
--- /dev/null
+++ b/Kernel/.github/workflows/flawfinder.yml
@@ -0,0 +1,38 @@
+# This workflow uses actions that are not certified by GitHub.
+# They are provided by a third-party and are governed by
+# separate terms of service, privacy policy, and support
+# documentation.
+
+name: flawfinder
+
+on:
+ push:
+ branches: [ "main" ]
+ pull_request:
+ # The branches below must be a subset of the branches above
+ branches: [ "main" ]
+ schedule:
+ - cron: '21 1 * * 1'
+
+jobs:
+ flawfinder:
+ name: Flawfinder
+ runs-on: ubuntu-latest
+ permissions:
+ actions: read
+ contents: read
+ security-events: write
+ steps:
+ - name: Checkout code
+ uses: actions/checkout@v3
+
+ - name: flawfinder_scan
+ uses: david-a-wheeler/flawfinder@8e4a779ad59dbfaee5da586aa9210853b701959c
+ with:
+ arguments: '--sarif ./'
+ output: 'flawfinder_results.sarif'
+
+ - name: Upload analysis results to GitHub Security tab
+ uses: github/codeql-action/upload-sarif@v2
+ with:
+ sarif_file: ${{github.workspace}}/flawfinder_results.sarif
diff --git a/Kernel/.gitignore b/Kernel/.gitignore
new file mode 100644
index 00000000..7379e127
--- /dev/null
+++ b/Kernel/.gitignore
@@ -0,0 +1,7 @@
+*.o
+*.su
+*.gcno
+*.map
+*.fsys
+*.log
+.dccache
diff --git a/Kernel/.vscode/c_boilerplates.code-snippets b/Kernel/.vscode/c_boilerplates.code-snippets
new file mode 100644
index 00000000..c91ee465
--- /dev/null
+++ b/Kernel/.vscode/c_boilerplates.code-snippets
@@ -0,0 +1,69 @@
+{
+ "Fennix Kernel Header": {
+ "prefix": [
+ "head",
+ ],
+ "body": [
+ "/*",
+ " 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 .",
+ "*/",
+ "",
+ "#ifndef __FENNIX_KERNEL_${2:header}_H__",
+ "#define __FENNIX_KERNEL_${2:header}_H__",
+ "",
+ "#include ",
+ "",
+ "$0",
+ "",
+ "#endif // !__FENNIX_KERNEL_${2:header}_H__",
+ ""
+ ],
+ "description": "Create kernel header."
+ },
+ "Fennix Kernel brief": {
+ "prefix": [
+ "brief",
+ ],
+ "body": [
+ "/** @brief $0 */"
+ ],
+ "description": "Create kernel documentation brief."
+ },
+ "License": {
+ "prefix": [
+ "license",
+ ],
+ "body": [
+ "/*",
+ " 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 .",
+ "*/"
+ ],
+ "description": "Create kernel license."
+ }
+}
diff --git a/Kernel/.vscode/c_cpp_properties.json b/Kernel/.vscode/c_cpp_properties.json
new file mode 100644
index 00000000..ffff0894
--- /dev/null
+++ b/Kernel/.vscode/c_cpp_properties.json
@@ -0,0 +1,219 @@
+{
+ "configurations": [
+ {
+ "name": "Fennix x64 (Linux, GCC, debug)",
+ "includePath": [
+ "${workspaceFolder}/include",
+ "${workspaceFolder}/include/**",
+ "${workspaceFolder}/include_std",
+ "${workspaceFolder}/include_std/**"
+ ],
+ "defines": [
+ "__debug_vscode__",
+ "KERNEL_NAME=\"Fennix\"",
+ "KERNEL_VERSION=\"1.0\"",
+ "GIT_COMMIT=\"0000000000000000000000000000000000000000\"",
+ "GIT_COMMIT_SHORT=\"0000000\"",
+ "a64",
+ "a86",
+ "DEBUG=\"1\""
+ ],
+ "compilerPath": "${workspaceFolder}/../tools/cross/bin/amd64-elf-gcc",
+ "cStandard": "c17",
+ "cppStandard": "c++20",
+ "intelliSenseMode": "gcc-x64",
+ "configurationProvider": "ms-vscode.makefile-tools",
+ "compilerArgs": [
+ // Compiler flags
+ "-fno-pic",
+ "-fno-pie",
+ "-mno-red-zone",
+ "-march=core2",
+ "-pipe",
+ "-mcmodel=kernel",
+ "-fno-builtin",
+
+ // Warnings
+ "-Wall",
+ "-Wextra",
+ "-Wfloat-equal",
+ "-Wpointer-arith",
+ "-Wcast-align",
+ "-Wredundant-decls",
+ "-Winit-self",
+ "-Wswitch-default",
+ "-Wstrict-overflow=5",
+ "-Wconversion",
+
+ // C++ flags
+ "-fno-rtti",
+ "-fexceptions",
+
+ // Linker flags
+ "-T${workspaceFolder}/Architecture/amd64/linker.ld",
+ "-Wl,-static,--no-dynamic-linker,-ztext",
+ "-nostdlib",
+ "-nodefaultlibs",
+ "-nolibc",
+ "-zmax-page-size=0x1000",
+ "-shared",
+
+ // Debug flags
+ "-ggdb3",
+ "-O0",
+ "-fdiagnostics-color=always",
+ "-fverbose-asm",
+ "-fstack-usage",
+ "-fstack-check",
+ "-fsanitize=undefined",
+
+ // VSCode flags
+ "-ffreestanding",
+ "-nostdinc",
+ "-nostdinc++"
+ ]
+ },
+ {
+ "name": "Fennix x32 (Linux, GCC, debug)",
+ "includePath": [
+ "${workspaceFolder}/include",
+ "${workspaceFolder}/include/**",
+ "${workspaceFolder}/include_std",
+ "${workspaceFolder}/include_std/**"
+ ],
+ "defines": [
+ "__debug_vscode__",
+ "KERNEL_NAME=\"Fennix\"",
+ "KERNEL_VERSION=\"1.0\"",
+ "GIT_COMMIT=\"0000000000000000000000000000000000000000\"",
+ "GIT_COMMIT_SHORT=\"0000000\"",
+ "a32",
+ "a86",
+ "DEBUG=\"1\""
+ ],
+ "compilerPath": "${workspaceFolder}/../tools/cross/bin/i386-elf-gcc",
+ "cStandard": "c17",
+ "cppStandard": "c++20",
+ "intelliSenseMode": "gcc-x86",
+ "configurationProvider": "ms-vscode.makefile-tools",
+ "compilerArgs": [
+ // Compiler flags
+ "-fno-pic",
+ "-fno-pie",
+ "-mno-80387",
+ "-mno-mmx",
+ "-mno-3dnow",
+ "-mno-red-zone",
+ "-march=pentium",
+ "-pipe",
+ "-msoft-float",
+ "-fno-builtin",
+
+ // Warnings
+ "-Wall",
+ "-Wextra",
+ "-Wfloat-equal",
+ "-Wpointer-arith",
+ "-Wcast-align",
+ "-Wredundant-decls",
+ "-Winit-self",
+ "-Wswitch-default",
+ "-Wstrict-overflow=5",
+ "-Wconversion",
+
+ // C++ flags
+ "-fno-rtti",
+ "-fexceptions",
+
+ // Linker flags
+ "-T${workspaceFolder}/Architecture/i386/linker.ld",
+ "-Wl,-static,--no-dynamic-linker,-ztext",
+ "-nostdlib",
+ "-nodefaultlibs",
+ "-nolibc",
+ "-zmax-page-size=0x1000",
+ "-shared",
+
+ // Debug flags
+ "-ggdb3",
+ "-O0",
+ "-fdiagnostics-color=always",
+ "-fverbose-asm",
+ "-fstack-usage",
+ "-fstack-check",
+ "-fsanitize=undefined",
+
+ // VSCode flags
+ "-ffreestanding",
+ "-nostdinc",
+ "-nostdinc++"
+ ]
+ },
+ {
+ "name": "Fennix Aarch64 (Linux, GCC, debug)",
+ "includePath": [
+ "${workspaceFolder}/include",
+ "${workspaceFolder}/include/**",
+ "${workspaceFolder}/include_std",
+ "${workspaceFolder}/include_std/**"
+ ],
+ "defines": [
+ "__debug_vscode__",
+ "KERNEL_NAME=\"Fennix\"",
+ "KERNEL_VERSION=\"1.0\"",
+ "GIT_COMMIT=\"0000000000000000000000000000000000000000\"",
+ "GIT_COMMIT_SHORT=\"0000000\"",
+ "aa64",
+ "DEBUG=\"1\""
+ ],
+ "compilerPath": "${workspaceFolder}/../tools/cross/bin/aarch64-elf-gcc",
+ "cStandard": "c17",
+ "cppStandard": "c++20",
+ "intelliSenseMode": "linux-gcc-arm64",
+ "configurationProvider": "ms-vscode.makefile-tools",
+ "compilerArgs": [
+ // Compiler flags
+ "-pipe",
+ "-fno-builtin",
+ "-msoft-float",
+ "-fPIC",
+ "-Wstack-protector",
+
+ // Warnings
+ "-Wall",
+ "-Wextra",
+ "-Wfloat-equal",
+ "-Wpointer-arith",
+ "-Wcast-align",
+ "-Wredundant-decls",
+ "-Winit-self",
+ "-Wswitch-default",
+ "-Wstrict-overflow=5",
+ "-Wconversion",
+
+ // C++ flags
+ "-fno-rtti",
+ "-fexceptions",
+
+ // Linker flags
+ "-T${workspaceFolder}/Architecture/aarch64/linker.ld",
+ "-fPIC",
+
+ // Debug flags
+ "-ggdb3",
+ "-O0",
+ "-fdiagnostics-color=always",
+ "-fverbose-asm",
+ "-fstack-usage",
+ "-fstack-check",
+ "-fsanitize=undefined",
+
+ // VSCode flags
+ "-ffreestanding",
+ "-nostdinc",
+ "-nostdinc++"
+ ]
+ }
+ ],
+ "version": 4
+}
\ No newline at end of file
diff --git a/Kernel/.vscode/extensions.json b/Kernel/.vscode/extensions.json
new file mode 100644
index 00000000..42ea9d06
--- /dev/null
+++ b/Kernel/.vscode/extensions.json
@@ -0,0 +1,13 @@
+{
+ "recommendations": [
+ "ms-vscode.cpptools",
+ "wayou.vscode-todo-highlight",
+ "gruntfuggly.todo-tree",
+ "13xforever.language-x86-64-assembly",
+ "webfreak.debug",
+ "zixuanwang.linkerscript",
+ "maziac.hex-hover-converter",
+ "cschlosser.doxdocgen",
+ "streetsidesoftware.code-spell-checker"
+ ]
+}
\ No newline at end of file
diff --git a/Kernel/.vscode/launch.json b/Kernel/.vscode/launch.json
new file mode 100644
index 00000000..80f2cb16
--- /dev/null
+++ b/Kernel/.vscode/launch.json
@@ -0,0 +1,40 @@
+{
+ "version": "0.2.0",
+ "configurations": [
+ {
+ "name": "Attach to a running VM instance",
+ "type": "cppdbg",
+ "request": "launch",
+ "program": "${workspaceRoot}/kernel.fsys",
+ "cwd": "${workspaceRoot}",
+ "args": [],
+ "targetArchitecture": "x64",
+ "MIMode": "gdb",
+ "miDebuggerPath": "/usr/bin/gdb",
+ "miDebuggerArgs": "",
+ "externalConsole": false,
+ "additionalSOLibSearchPath": "${workspaceRoot}",
+ "customLaunchSetupCommands": [
+ {
+ "text": "target remote localhost:1234",
+ "description": "Connect to QEMU remote debugger"
+ }
+ ],
+ "setupCommands": [
+ {
+ "description": "Enable pretty-printing for gdb",
+ "text": "-enable-pretty-printing",
+ "ignoreFailures": true
+ },
+ {
+ "text": "set breakpoint pending on",
+ "description": "Make breakpoint pending on future shared library load."
+ },
+ {
+ "text": "file ${workspaceRoot}/kernel.fsys",
+ "description": "Load binary."
+ },
+ ]
+ }
+ ]
+}
\ No newline at end of file
diff --git a/Kernel/.vscode/settings.json b/Kernel/.vscode/settings.json
new file mode 100644
index 00000000..2d09fa10
--- /dev/null
+++ b/Kernel/.vscode/settings.json
@@ -0,0 +1,19 @@
+{
+ "C_Cpp.errorSquiggles": "Enabled",
+ "C_Cpp.autocompleteAddParentheses": true,
+ "C_Cpp.codeAnalysis.clangTidy.enabled": true,
+ "C_Cpp.clang_format_style": "Visual Studio",
+ "C_Cpp.default.intelliSenseMode": "gcc-x64",
+ "C_Cpp.default.cStandard": "c17",
+ "C_Cpp.default.cppStandard": "c++20",
+ "C_Cpp.intelliSenseMemoryLimit": 16384,
+ "editor.smoothScrolling": true,
+ "editor.cursorSmoothCaretAnimation": "on",
+ "C_Cpp.codeAnalysis.clangTidy.checks.disabled": [
+ "clang-analyzer-security.insecureAPI.strcpy",
+ "clang-diagnostic-unknown-warning-option",
+ "clang-analyzer-security.insecureAPI.DeprecatedOrUnsafeBufferHandling",
+ "clang-diagnostic-implicit-exception-spec-mismatch",
+ "clang-diagnostic-unknown-attributes"
+ ]
+}
\ No newline at end of file
diff --git a/Kernel/Architecture/aarch64/Bootstrap/boot.S b/Kernel/Architecture/aarch64/Bootstrap/boot.S
new file mode 100644
index 00000000..45ec22f1
--- /dev/null
+++ b/Kernel/Architecture/aarch64/Bootstrap/boot.S
@@ -0,0 +1,36 @@
+/* Based on this tutorial:
+ https://github.com/s-matyukevich/raspberry-pi-os */
+
+.section ".text.boot"
+
+.extern _bss_start
+.extern _bss_end
+
+.extern arm64Entry
+memzero:
+ str xzr, [x0], #8
+ subs x1, x1, #8
+ b.gt memzero
+ ret
+
+.global _start
+_start:
+ mrs x0, mpidr_el1
+ and x0, x0, #0xFF
+ cbz x0, _start2
+ b CPU_Loop
+
+_start2:
+ adr x0, _bss_start
+ adr x1, _bss_end
+ sub x1, x1, x0
+ bl memzero
+ mov sp, #0x200000
+ bl arm64Entry
+
+Halt:
+ wfe
+ b Halt
+
+CPU_Loop:
+ b CPU_Loop
diff --git a/Kernel/Architecture/aarch64/Entry.cpp b/Kernel/Architecture/aarch64/Entry.cpp
new file mode 100644
index 00000000..857cea09
--- /dev/null
+++ b/Kernel/Architecture/aarch64/Entry.cpp
@@ -0,0 +1,27 @@
+/*
+ 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 .
+*/
+
+#include
+
+#include
+#include
+
+EXTERNC void arm64Entry(uint64_t dtb_ptr32, uint64_t x1, uint64_t x2, uint64_t x3)
+{
+ trace("Hello, World!");
+ CPU::Halt(true);
+}
diff --git a/Kernel/Architecture/aarch64/SystemCalls.cpp b/Kernel/Architecture/aarch64/SystemCalls.cpp
new file mode 100644
index 00000000..aea86378
--- /dev/null
+++ b/Kernel/Architecture/aarch64/SystemCalls.cpp
@@ -0,0 +1,31 @@
+/*
+ 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 .
+*/
+
+#include
+
+#include
+
+extern "C" __naked __used __no_stack_protector void SystemCallHandlerStub()
+{
+
+}
+
+extern "C" uint64_t SystemCallsHandler(SyscallsFrame *regs);
+
+void InitializeSystemCalls()
+{
+}
diff --git a/Kernel/Architecture/aarch64/cpu/SymmetricMultiprocessing.cpp b/Kernel/Architecture/aarch64/cpu/SymmetricMultiprocessing.cpp
new file mode 100644
index 00000000..f6c89b95
--- /dev/null
+++ b/Kernel/Architecture/aarch64/cpu/SymmetricMultiprocessing.cpp
@@ -0,0 +1,59 @@
+/*
+ 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 .
+*/
+
+#include
+
+#include
+#include
+#include
+
+#include "../../../kernel.h"
+
+volatile bool CPUEnabled = false;
+
+#pragma GCC diagnostic ignored "-Wmissing-field-initializers"
+static __aligned(0x1000) CPUData CPUs[MAX_CPU] = {0};
+
+CPUData *GetCPU(uint64_t id) { return &CPUs[id]; }
+
+CPUData *GetCurrentCPU()
+{
+ uint64_t ret = 0;
+
+ if (!CPUs[ret].IsActive)
+ {
+ error("CPU %d is not active!", ret);
+ return &CPUs[0];
+ }
+
+ if (CPUs[ret].Checksum != CPU_DATA_CHECKSUM)
+ {
+ error("CPU %d data is corrupted!", ret);
+ return &CPUs[0];
+ }
+ return &CPUs[ret];
+}
+
+namespace SMP
+{
+ int CPUCores = 0;
+
+ void Initialize(void *madt)
+ {
+ fixme("SMP::Initialize() is not implemented!");
+ }
+}
diff --git a/Kernel/Architecture/aarch64/linker.ld b/Kernel/Architecture/aarch64/linker.ld
new file mode 100644
index 00000000..bb8c142e
--- /dev/null
+++ b/Kernel/Architecture/aarch64/linker.ld
@@ -0,0 +1,83 @@
+/*
+ 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 .
+*/
+
+ENTRY(_start)
+
+SECTIONS
+{
+ .text.boot :
+ {
+ *(.text.boot)
+ . += CONSTANT(MAXPAGESIZE);
+ _bss_start = .;
+ *(.text.bss)
+ _bss_end = .;
+ }
+
+ _kernel_start = .;
+ .text :
+ {
+ KEEP(*(.text.boot))
+ *(.text .text.*)
+ }
+ . = ALIGN(4096);
+ _kernel_text_end = .;
+
+ .data :
+ {
+ *(.data .data.*)
+ }
+ . = ALIGN(4096);
+ _kernel_data_end = .;
+
+ .rodata :
+ {
+ *(.rodata .rodata.*)
+ }
+ . = ALIGN(4096);
+ _kernel_rodata_end = .;
+
+ .init_array :
+ {
+ PROVIDE_HIDDEN(__init_array_start = .);
+ KEEP(*(.init_array .ctors))
+ KEEP(*(SORT_BY_INIT_PRIORITY(.init_array.*) SORT_BY_INIT_PRIORITY(.ctors.*)))
+ PROVIDE_HIDDEN (__init_array_end = .);
+ }
+
+ .fini_array :
+ {
+ PROVIDE_HIDDEN(__fini_array_start = .);
+ KEEP(*(SORT_BY_INIT_PRIORITY(.fini_array.*) SORT_BY_INIT_PRIORITY(.dtors.*)))
+ KEEP(*(.fini_array .dtors))
+ PROVIDE_HIDDEN (__fini_array_end = .);
+ }
+
+ .bss :
+ {
+ *(.bss .bss.*)
+ }
+ . = ALIGN(4096);
+ _kernel_end = .;
+ _bss_size = _kernel_end - _kernel_rodata_end;
+
+ /DISCARD/ :
+ {
+ *(.comment*)
+ *(.note*)
+ }
+}
diff --git a/Kernel/Architecture/aarch64/runtime/crt0.S b/Kernel/Architecture/aarch64/runtime/crt0.S
new file mode 100644
index 00000000..ec4b0f0c
--- /dev/null
+++ b/Kernel/Architecture/aarch64/runtime/crt0.S
@@ -0,0 +1,17 @@
+// .section ".text.boot"
+//
+// .global _start
+// .org 0x80000
+// _start:
+// ldr x5, =_start
+// mov sp, x5
+// ldr x5, =_kernel_rodata_end
+// ldr w6, =_bss_size
+// 1: cbz w6, 2f
+// str xzr, [x5], #8
+// sub w6, w6, #1
+// cbnz w6, 1b
+// 2: bl arm64Entry
+// Halt:
+// wfe
+// b Halt
diff --git a/Kernel/Architecture/aarch64/runtime/crt1.S b/Kernel/Architecture/aarch64/runtime/crt1.S
new file mode 100644
index 00000000..d25abc91
--- /dev/null
+++ b/Kernel/Architecture/aarch64/runtime/crt1.S
@@ -0,0 +1,17 @@
+// .section ".text.boot"
+
+// .global _start
+// .org 0x80000
+// _start:
+// ldr x5, =_start
+// mov sp, x5
+// ldr x5, =_kernel_rodata_end
+// ldr w6, =_bss_size
+// 1: cbz w6, 2f
+// str xzr, [x5], #8
+// sub w6, w6, #1
+// cbnz w6, 1b
+// 2: bl arm64Entry
+// Halt:
+// wfe
+// b Halt
diff --git a/Kernel/Architecture/aarch64/runtime/crtbegin.c b/Kernel/Architecture/aarch64/runtime/crtbegin.c
new file mode 100644
index 00000000..507125b3
--- /dev/null
+++ b/Kernel/Architecture/aarch64/runtime/crtbegin.c
@@ -0,0 +1 @@
+// C++ constructor/destructor stuff
\ No newline at end of file
diff --git a/Kernel/Architecture/aarch64/runtime/crtend.c b/Kernel/Architecture/aarch64/runtime/crtend.c
new file mode 100644
index 00000000..507125b3
--- /dev/null
+++ b/Kernel/Architecture/aarch64/runtime/crtend.c
@@ -0,0 +1 @@
+// C++ constructor/destructor stuff
\ No newline at end of file
diff --git a/Kernel/Architecture/aarch64/runtime/crti.S b/Kernel/Architecture/aarch64/runtime/crti.S
new file mode 100644
index 00000000..d3886db5
--- /dev/null
+++ b/Kernel/Architecture/aarch64/runtime/crti.S
@@ -0,0 +1,13 @@
+// .section .init
+// .global _init
+// .type _init, @function
+// _init:
+// push %rbp
+// movq %rsp, %rbp
+
+// .section .fini
+// .global _fini
+// .type _fini, @function
+// _fini:
+// push %rbp
+// movq %rsp, %rbp
diff --git a/Kernel/Architecture/aarch64/runtime/crtn.S b/Kernel/Architecture/aarch64/runtime/crtn.S
new file mode 100644
index 00000000..21c198b8
--- /dev/null
+++ b/Kernel/Architecture/aarch64/runtime/crtn.S
@@ -0,0 +1,7 @@
+.section .init
+// popq %rbp
+ ret
+
+.section .fini
+// popq %rbp
+ ret
diff --git a/Kernel/Architecture/amd64/AdvancedConfigurationAndPowerInterface.cpp b/Kernel/Architecture/amd64/AdvancedConfigurationAndPowerInterface.cpp
new file mode 100644
index 00000000..2d6499ac
--- /dev/null
+++ b/Kernel/Architecture/amd64/AdvancedConfigurationAndPowerInterface.cpp
@@ -0,0 +1,155 @@
+/*
+ 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 .
+*/
+
+#include "acpi.hpp"
+
+#include
+#include
+
+#include "../../kernel.h"
+
+#pragma GCC diagnostic ignored "-Wint-to-pointer-cast"
+
+namespace ACPI
+{
+ void *ACPI::FindTable(ACPI::ACPIHeader *ACPIHeader, char *Signature)
+ {
+ for (uint64_t t = 0; t < ((ACPIHeader->Length - sizeof(ACPI::ACPIHeader)) / (XSDTSupported ? 8 : 4)); t++)
+ {
+ // TODO: Should I be concerned about unaligned memory access?
+ ACPI::ACPIHeader *SDTHdr = nullptr;
+ if (XSDTSupported)
+ SDTHdr = (ACPI::ACPIHeader *)(*(uint64_t *)((uint64_t)ACPIHeader + sizeof(ACPI::ACPIHeader) + (t * 8)));
+ else
+ SDTHdr = (ACPI::ACPIHeader *)(*(uint32_t *)((uint64_t)ACPIHeader + sizeof(ACPI::ACPIHeader) + (t * 4)));
+
+ for (int i = 0; i < 4; i++)
+ {
+ if (SDTHdr->Signature[i] != Signature[i])
+ break;
+ if (i == 3)
+ {
+ trace("%s found at address %p", Signature, (uintptr_t)SDTHdr);
+ return SDTHdr;
+ }
+ }
+ }
+ // warn("%s not found!", Signature);
+ return nullptr;
+ }
+
+ void ACPI::SearchTables(ACPIHeader *Header)
+ {
+ if (!Header)
+ return;
+
+ HPET = (HPETHeader *)FindTable(Header, (char *)"HPET");
+ FADT = (FADTHeader *)FindTable(Header, (char *)"FACP");
+ MCFG = (MCFGHeader *)FindTable(Header, (char *)"MCFG");
+ BGRT = (BGRTHeader *)FindTable(Header, (char *)"BGRT");
+ SRAT = (SRATHeader *)FindTable(Header, (char *)"SRAT");
+ TPM2 = (TPM2Header *)FindTable(Header, (char *)"TPM2");
+ TCPA = (TCPAHeader *)FindTable(Header, (char *)"TCPA");
+ WAET = (WAETHeader *)FindTable(Header, (char *)"WAET");
+ MADT = (MADTHeader *)FindTable(Header, (char *)"APIC");
+ HEST = (HESTHeader *)FindTable(Header, (char *)"HEST");
+ FindTable(Header, (char *)"BERT");
+ FindTable(Header, (char *)"CPEP");
+ FindTable(Header, (char *)"DSDT");
+ FindTable(Header, (char *)"ECDT");
+ FindTable(Header, (char *)"EINJ");
+ FindTable(Header, (char *)"ERST");
+ FindTable(Header, (char *)"FACS");
+ FindTable(Header, (char *)"MSCT");
+ FindTable(Header, (char *)"MPST");
+ FindTable(Header, (char *)"OEMx");
+ FindTable(Header, (char *)"PMTT");
+ FindTable(Header, (char *)"PSDT");
+ FindTable(Header, (char *)"RASF");
+ FindTable(Header, (char *)"RSDT");
+ FindTable(Header, (char *)"SBST");
+ FindTable(Header, (char *)"SLIT");
+ FindTable(Header, (char *)"SSDT");
+ FindTable(Header, (char *)"XSDT");
+ FindTable(Header, (char *)"DRTM");
+ FindTable(Header, (char *)"FPDT");
+ FindTable(Header, (char *)"GTDT");
+ FindTable(Header, (char *)"PCCT");
+ FindTable(Header, (char *)"S3PT");
+ FindTable(Header, (char *)"MATR");
+ FindTable(Header, (char *)"MSDM");
+ FindTable(Header, (char *)"WPBT");
+ FindTable(Header, (char *)"OSDT");
+ FindTable(Header, (char *)"RSDP");
+ FindTable(Header, (char *)"NFIT");
+ FindTable(Header, (char *)"ASF!");
+ FindTable(Header, (char *)"BOOT");
+ FindTable(Header, (char *)"CSRT");
+ FindTable(Header, (char *)"DBG2");
+ FindTable(Header, (char *)"DBGP");
+ FindTable(Header, (char *)"DMAR");
+ FindTable(Header, (char *)"IBFT");
+ FindTable(Header, (char *)"IORT");
+ FindTable(Header, (char *)"IVRS");
+ FindTable(Header, (char *)"LPIT");
+ FindTable(Header, (char *)"MCHI");
+ FindTable(Header, (char *)"MTMR");
+ FindTable(Header, (char *)"SLIC");
+ FindTable(Header, (char *)"SPCR");
+ FindTable(Header, (char *)"SPMI");
+ FindTable(Header, (char *)"UEFI");
+ FindTable(Header, (char *)"VRTC");
+ FindTable(Header, (char *)"WDAT");
+ FindTable(Header, (char *)"WDDT");
+ FindTable(Header, (char *)"WDRT");
+ FindTable(Header, (char *)"ATKG");
+ FindTable(Header, (char *)"GSCI");
+ FindTable(Header, (char *)"IEIT");
+ FindTable(Header, (char *)"HMAT");
+ FindTable(Header, (char *)"CEDT");
+ FindTable(Header, (char *)"AEST");
+ }
+
+ ACPI::ACPI()
+ {
+ trace("Initializing ACPI");
+ if (bInfo.RSDP->Revision >= 2 && bInfo.RSDP->XSDTAddress)
+ {
+ debug("XSDT supported");
+ XSDTSupported = true;
+ XSDT = (ACPIHeader *)(bInfo.RSDP->XSDTAddress);
+ }
+ else
+ {
+ debug("RSDT supported");
+ XSDT = (ACPIHeader *)(uintptr_t)bInfo.RSDP->RSDTAddress;
+ }
+
+ this->SearchTables(XSDT);
+
+ if (FADT)
+ {
+ outb(s_cst(uint16_t, FADT->SMI_CommandPort), FADT->AcpiEnable);
+ while (!(inw(s_cst(uint16_t, FADT->PM1aControlBlock)) & 1))
+ ;
+ }
+ }
+
+ ACPI::~ACPI()
+ {
+ }
+}
diff --git a/Kernel/Architecture/amd64/Bootstrap/GDT32.asm b/Kernel/Architecture/amd64/Bootstrap/GDT32.asm
new file mode 100644
index 00000000..e9fa9804
--- /dev/null
+++ b/Kernel/Architecture/amd64/Bootstrap/GDT32.asm
@@ -0,0 +1,47 @@
+[bits 32]
+section .bootstrap.text
+
+align 32
+global gdtr
+gdtr:
+ dw GDT32_END - GDT32 - 1
+ dd GDT32
+
+align 32
+GDT32:
+ dq 0x0
+
+ dw 0xffff
+ dw 0x0000
+ db 0x00
+ dw 0xcf9a
+ db 0x00
+
+ dw 0xffff
+ dw 0x0000
+ db 0x00
+ dw 0xcf92
+ db 0x00
+
+ dw 0x0100
+ dw 0x1000
+ db 0x00
+ dw 0x4092
+ db 0x00
+GDT32_END:
+
+global LoadGDT32
+LoadGDT32:
+ lgdt [gdtr]
+
+ 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
+
+ ret
diff --git a/Kernel/Architecture/amd64/Bootstrap/Header_Multiboot.asm b/Kernel/Architecture/amd64/Bootstrap/Header_Multiboot.asm
new file mode 100644
index 00000000..71a6efe8
--- /dev/null
+++ b/Kernel/Architecture/amd64/Bootstrap/Header_Multiboot.asm
@@ -0,0 +1,5 @@
+section .multiboot
+align 4
+ dd 0x1BADB002
+ dd 1 << 0 | 1 << 1
+ dd -(0x1BADB002 + (1 << 0 | 1 << 1))
diff --git a/Kernel/Architecture/amd64/Bootstrap/Header_Multiboot2.asm b/Kernel/Architecture/amd64/Bootstrap/Header_Multiboot2.asm
new file mode 100644
index 00000000..756dcb89
--- /dev/null
+++ b/Kernel/Architecture/amd64/Bootstrap/Header_Multiboot2.asm
@@ -0,0 +1,64 @@
+; https://www.gnu.org/software/grub/manual/multiboot2/multiboot.html
+section .multiboot2
+align 4096
+HEADER_START:
+ dd 0xE85250D6
+ dd 0
+ dd (HEADER_END - HEADER_START)
+ dd 0x100000000 - (HEADER_END - HEADER_START) - 0 - 0xE85250D6
+align 8
+MB2_INFO_REQUEST_TAG_START:
+ dw 1
+ dw 0
+ dd MB2_INFO_REQUEST_TAG_END - MB2_INFO_REQUEST_TAG_START
+ dd 1 ; Command Line
+ dd 2 ; Boot Loader Name
+ dd 3 ; Module
+ dd 4 ; Basic Memory Information
+ dd 5 ; BIOS Boot Device
+ dd 6 ; Memory Map
+ dd 7 ; VBE
+ dd 8 ; Framebuffer
+ dd 9 ; ELF Sections
+ dd 10 ; APM Table
+ dd 11 ; EFI 32-bit System Table Pointer
+ dd 12 ; EFI 64-bit System Table Pointer
+ ; dd 13 ; SMBIOS
+ dd 14 ; ACPI Old
+ dd 15 ; ACPI New
+ dd 16 ; Network
+ dd 17 ; EFI Memory Map
+ dd 18 ; EFI Boot Services Notifier
+ dd 19 ; EFI 32-bit Image Handle Pointer
+ dd 20 ; EFI 64-bit Image Handle Pointer
+ dd 21 ; Load Base Address
+MB2_INFO_REQUEST_TAG_END:
+align 8
+MB2_FRAMEBUFFER_TAG_START:
+ dw 5
+ dw 1
+ dd MB2_FRAMEBUFFER_TAG_END - MB2_FRAMEBUFFER_TAG_START
+ dd 0
+ dd 0
+ dd 32
+MB2_FRAMEBUFFER_TAG_END:
+align 8
+MB2_EGA_SUPPORT_TAG_START:
+ dw 4
+ dw 0
+ dd MB2_EGA_SUPPORT_TAG_END - MB2_EGA_SUPPORT_TAG_START
+ dd 1 ; https://www.gnu.org/software/grub/manual/multiboot2/html_node/Console-header-tags.html
+MB2_EGA_SUPPORT_TAG_END:
+align 8
+MB2_MODULE_ALIGN_TAG_START:
+ dw 6
+ dw 0
+ dd MB2_MODULE_ALIGN_TAG_END - MB2_MODULE_ALIGN_TAG_START
+MB2_MODULE_ALIGN_TAG_END:
+align 8
+MB2_TAG_START:
+ dw 0
+ dw 0
+ dd MB2_TAG_END - MB2_TAG_START
+MB2_TAG_END:
+HEADER_END:
diff --git a/Kernel/Architecture/amd64/Bootstrap/Limine.c b/Kernel/Architecture/amd64/Bootstrap/Limine.c
new file mode 100644
index 00000000..eceb740e
--- /dev/null
+++ b/Kernel/Architecture/amd64/Bootstrap/Limine.c
@@ -0,0 +1,346 @@
+/*
+ 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 .
+*/
+
+#include
+#include
+#include
+#include
+
+#include "../../../../tools/limine/limine.h"
+#include "../../../kernel.h"
+
+void InitLimine();
+
+static volatile struct limine_entry_point_request EntryPointRequest = {
+ .id = LIMINE_ENTRY_POINT_REQUEST,
+ .revision = 0,
+ .response = NULL,
+ .entry = InitLimine};
+static volatile struct limine_bootloader_info_request BootloaderInfoRequest = {
+ .id = LIMINE_BOOTLOADER_INFO_REQUEST,
+ .revision = 0};
+static volatile struct limine_terminal_request TerminalRequest = {
+ .id = LIMINE_TERMINAL_REQUEST,
+ .revision = 0};
+static volatile struct limine_framebuffer_request FramebufferRequest = {
+ .id = LIMINE_FRAMEBUFFER_REQUEST,
+ .revision = 0};
+static volatile struct limine_memmap_request MemmapRequest = {
+ .id = LIMINE_MEMMAP_REQUEST,
+ .revision = 0};
+static volatile struct limine_kernel_address_request KernelAddressRequest = {
+ .id = LIMINE_KERNEL_ADDRESS_REQUEST,
+ .revision = 0};
+static volatile struct limine_rsdp_request RsdpRequest = {
+ .id = LIMINE_RSDP_REQUEST,
+ .revision = 0};
+static volatile struct limine_kernel_file_request KernelFileRequest = {
+ .id = LIMINE_KERNEL_FILE_REQUEST,
+ .revision = 0};
+static volatile struct limine_module_request ModuleRequest = {
+ .id = LIMINE_MODULE_REQUEST,
+ .revision = 0};
+static volatile struct limine_smbios_request SmbiosRequest = {
+ .id = LIMINE_SMBIOS_REQUEST,
+ .revision = 0};
+
+void *TempStackPtr = NULL;
+__naked __used __no_stack_protector void InitLimine()
+{
+ asmv("mov %%rsp, %0"
+ : "=r"(TempStackPtr));
+
+ asmv("mov %0, %%rsp"
+ :
+ : "r"((uintptr_t)TempStackPtr - 0xFFFF800000000000));
+
+ asmv("mov $0, %rax\n"
+ "mov $0, %rbx\n"
+ "mov $0, %rcx\n"
+ "mov $0, %rdx\n"
+ "mov $0, %rsi\n"
+ "mov $0, %rdi\n"
+ "mov $0, %rbp\n"
+ "mov $0, %r8\n"
+ "mov $0, %r9\n"
+ "mov $0, %r10\n"
+ "mov $0, %r11\n"
+ "mov $0, %r12\n"
+ "mov $0, %r13\n"
+ "mov $0, %r14\n"
+ "mov $0, %r15");
+
+ asmv("jmp InitLimineAfterStack");
+}
+
+SafeFunction NIF void InitLimineAfterStack()
+{
+ struct BootInfo binfo = {};
+ struct limine_bootloader_info_response *BootloaderInfoResponse = BootloaderInfoRequest.response;
+ info("Bootloader: %s %s", BootloaderInfoResponse->name, BootloaderInfoResponse->version);
+
+ struct limine_terminal_response *TerminalResponse = TerminalRequest.response;
+
+ if (TerminalResponse == NULL || TerminalResponse->terminal_count < 1)
+ {
+ warn("No terminal available.");
+ inf_loop asmv("hlt");
+ }
+ TerminalResponse->write(TerminalResponse->terminals[0], "\033[37mPlease wait... ", 20);
+
+ struct limine_framebuffer_response *FrameBufferResponse = FramebufferRequest.response;
+ struct limine_memmap_response *MemmapResponse = MemmapRequest.response;
+ struct limine_kernel_address_response *KernelAddressResponse = KernelAddressRequest.response;
+ struct limine_rsdp_response *RsdpResponse = RsdpRequest.response;
+ struct limine_kernel_file_response *KernelFileResponse = KernelFileRequest.response;
+ struct limine_module_response *ModuleResponse = ModuleRequest.response;
+ struct limine_smbios_response *SmbiosResponse = SmbiosRequest.response;
+
+ if (FrameBufferResponse == NULL || FrameBufferResponse->framebuffer_count < 1)
+ {
+ error("No framebuffer available [%#lx;%ld]", FrameBufferResponse,
+ (FrameBufferResponse == NULL) ? 0 : FrameBufferResponse->framebuffer_count);
+
+ TerminalResponse->write(TerminalResponse->terminals[0], "No framebuffer available", 24);
+ inf_loop asmv("hlt");
+ }
+
+ if (MemmapResponse == NULL || MemmapResponse->entry_count < 1)
+ {
+ error("No memory map available [%#lx;%ld]", MemmapResponse,
+ (MemmapResponse == NULL) ? 0 : MemmapResponse->entry_count);
+
+ TerminalResponse->write(TerminalResponse->terminals[0], "No memory map available", 23);
+ inf_loop asmv("hlt");
+ }
+
+ if (KernelAddressResponse == NULL)
+ {
+ error("No kernel address available [%#lx]", KernelAddressResponse);
+
+ TerminalResponse->write(TerminalResponse->terminals[0], "No kernel address available", 27);
+ inf_loop asmv("hlt");
+ }
+
+ if (RsdpResponse == NULL || RsdpResponse->address == 0)
+ {
+ error("No RSDP address available [%#lx;%#lx]", RsdpResponse,
+ (RsdpResponse == NULL) ? 0 : RsdpResponse->address);
+
+ TerminalResponse->write(TerminalResponse->terminals[0], "No RSDP address available", 25);
+ inf_loop asmv("hlt");
+ }
+
+ if (KernelFileResponse == NULL || KernelFileResponse->kernel_file == NULL)
+ {
+ error("No kernel file available [%#lx;%#lx]", KernelFileResponse,
+ (KernelFileResponse == NULL) ? 0 : KernelFileResponse->kernel_file);
+
+ TerminalResponse->write(TerminalResponse->terminals[0], "No kernel file available", 24);
+ inf_loop asmv("hlt");
+ }
+
+ if (ModuleResponse == NULL || ModuleResponse->module_count < 1)
+ {
+ error("No module information available [%#lx;%ld]", ModuleResponse,
+ (ModuleResponse == NULL) ? 0 : ModuleResponse->module_count);
+
+ TerminalResponse->write(TerminalResponse->terminals[0], "No module information available", 31);
+ inf_loop asmv("hlt");
+ }
+
+ /* Actual parsing starts here */
+
+ for (uint64_t i = 0; i < FrameBufferResponse->framebuffer_count; i++)
+ {
+ struct limine_framebuffer *framebuffer = FrameBufferResponse->framebuffers[i];
+ switch (framebuffer->memory_model)
+ {
+ case LIMINE_FRAMEBUFFER_RGB:
+ binfo.Framebuffer[i].Type = RGB;
+ break;
+ default:
+ {
+ error("Unsupported framebuffer memory model %d", framebuffer->memory_model);
+ TerminalResponse->write(TerminalResponse->terminals[0], "Unsupported framebuffer memory model", 37);
+ inf_loop asmv("hlt");
+ }
+ }
+ binfo.Framebuffer[i].BaseAddress = (void *)((uintptr_t)framebuffer->address - 0xFFFF800000000000);
+ binfo.Framebuffer[i].Width = (uint32_t)framebuffer->width;
+ binfo.Framebuffer[i].Height = (uint32_t)framebuffer->height;
+ binfo.Framebuffer[i].Pitch = (uint32_t)framebuffer->pitch;
+ binfo.Framebuffer[i].BitsPerPixel = framebuffer->bpp;
+ binfo.Framebuffer[i].RedMaskSize = framebuffer->red_mask_size;
+ binfo.Framebuffer[i].RedMaskShift = framebuffer->red_mask_shift;
+ binfo.Framebuffer[i].GreenMaskSize = framebuffer->green_mask_size;
+ binfo.Framebuffer[i].GreenMaskShift = framebuffer->green_mask_shift;
+ binfo.Framebuffer[i].BlueMaskSize = framebuffer->blue_mask_size;
+ binfo.Framebuffer[i].BlueMaskShift = framebuffer->blue_mask_shift;
+ binfo.Framebuffer[i].ExtendedDisplayIdentificationData = framebuffer->edid;
+ binfo.Framebuffer[i].EDIDSize = framebuffer->edid_size;
+
+ debug("Framebuffer %d: %dx%d %d bpp", i,
+ binfo.Framebuffer[i].Width,
+ binfo.Framebuffer[i].Height,
+ binfo.Framebuffer[i].BitsPerPixel);
+
+ debug("More info:\nAddress: %#lx\nPitch: %ld\nType: %d\nRedMaskSize: %d\nRedMaskShift: %d\nGreenMaskSize: %d\nGreenMaskShift: %d\nBlueMaskSize: %d\nBlueMaskShift: %d\nEDID: %#lx\nEDIDSize: %d",
+ binfo.Framebuffer[i].BaseAddress,
+ binfo.Framebuffer[i].Pitch,
+ binfo.Framebuffer[i].Type,
+ binfo.Framebuffer[i].RedMaskSize,
+ binfo.Framebuffer[i].RedMaskShift,
+ binfo.Framebuffer[i].GreenMaskSize,
+ binfo.Framebuffer[i].GreenMaskShift,
+ binfo.Framebuffer[i].BlueMaskSize,
+ binfo.Framebuffer[i].BlueMaskShift,
+ binfo.Framebuffer[i].ExtendedDisplayIdentificationData,
+ binfo.Framebuffer[i].EDIDSize);
+ }
+
+ binfo.Memory.Entries = MemmapResponse->entry_count;
+ for (uint64_t i = 0; i < MemmapResponse->entry_count; i++)
+ {
+ if (MemmapResponse->entry_count > MAX_MEMORY_ENTRIES)
+ {
+ warn("Too many memory entries, skipping the rest...");
+ break;
+ }
+
+ struct limine_memmap_entry *entry = MemmapResponse->entries[i];
+ if (!entry)
+ {
+ warn("Null memory entry %ld (%#lx), skipping...", i, entry);
+ continue;
+ }
+
+ binfo.Memory.Size += entry->length;
+ switch (entry->type)
+ {
+ case LIMINE_MEMMAP_USABLE:
+ binfo.Memory.Entry[i].BaseAddress = (void *)entry->base;
+ binfo.Memory.Entry[i].Length = entry->length;
+ binfo.Memory.Entry[i].Type = Usable;
+ break;
+ case LIMINE_MEMMAP_RESERVED:
+ binfo.Memory.Entry[i].BaseAddress = (void *)entry->base;
+ binfo.Memory.Entry[i].Length = entry->length;
+ binfo.Memory.Entry[i].Type = Reserved;
+ break;
+ case LIMINE_MEMMAP_ACPI_RECLAIMABLE:
+ binfo.Memory.Entry[i].BaseAddress = (void *)entry->base;
+ binfo.Memory.Entry[i].Length = entry->length;
+ binfo.Memory.Entry[i].Type = ACPIReclaimable;
+ break;
+ case LIMINE_MEMMAP_ACPI_NVS:
+ binfo.Memory.Entry[i].BaseAddress = (void *)entry->base;
+ binfo.Memory.Entry[i].Length = entry->length;
+ binfo.Memory.Entry[i].Type = ACPINVS;
+ break;
+ case LIMINE_MEMMAP_BAD_MEMORY:
+ binfo.Memory.Entry[i].BaseAddress = (void *)entry->base;
+ binfo.Memory.Entry[i].Length = entry->length;
+ binfo.Memory.Entry[i].Type = BadMemory;
+ break;
+ case LIMINE_MEMMAP_BOOTLOADER_RECLAIMABLE:
+ binfo.Memory.Entry[i].BaseAddress = (void *)entry->base;
+ binfo.Memory.Entry[i].Length = entry->length;
+ binfo.Memory.Entry[i].Type = BootloaderReclaimable;
+ break;
+ case LIMINE_MEMMAP_KERNEL_AND_MODULES:
+ binfo.Memory.Entry[i].BaseAddress = (void *)entry->base;
+ binfo.Memory.Entry[i].Length = entry->length;
+ binfo.Memory.Entry[i].Type = KernelAndModules;
+ break;
+ case LIMINE_MEMMAP_FRAMEBUFFER:
+ binfo.Memory.Entry[i].BaseAddress = (void *)entry->base;
+ binfo.Memory.Entry[i].Length = entry->length;
+ binfo.Memory.Entry[i].Type = Framebuffer;
+ break;
+ default:
+ binfo.Memory.Entry[i].BaseAddress = (void *)entry->base;
+ binfo.Memory.Entry[i].Length = entry->length;
+ binfo.Memory.Entry[i].Type = Unknown;
+ break;
+ }
+ }
+
+ for (uint64_t i = 0; i < ModuleResponse->module_count; i++)
+ {
+ if (i > MAX_MODULES)
+ {
+ warn("Too many modules, skipping the rest...");
+ break;
+ }
+
+ binfo.Modules[i].Address = (void *)((uint64_t)ModuleResponse->modules[i]->address - 0xFFFF800000000000);
+ binfo.Modules[i].Size = ModuleResponse->modules[i]->size;
+
+ strncpy(binfo.Modules[i].Path,
+ ModuleResponse->modules[i]->path,
+ strlen(ModuleResponse->modules[i]->path) + 1);
+
+ strncpy(binfo.Modules[i].CommandLine,
+ ModuleResponse->modules[i]->cmdline,
+ strlen(ModuleResponse->modules[i]->cmdline) + 1);
+
+ debug("Module %d:\nAddress: %#lx\nPath: \"%s\"\nCommand Line: \"%s\"\nSize: %ld",
+ i,
+ binfo.Modules[i].Address,
+ binfo.Modules[i].Path,
+ binfo.Modules[i].CommandLine,
+ binfo.Modules[i].Size);
+ }
+
+ binfo.RSDP = (struct RSDPInfo *)((uintptr_t)RsdpResponse->address - 0xFFFF800000000000);
+ debug("RSDP: %#lx [Signature: \"%.8s\"] [OEM: \"%.6s\"]",
+ binfo.RSDP, binfo.RSDP->Signature, binfo.RSDP->OEMID);
+
+ if (SmbiosResponse->entry_64 != NULL)
+ binfo.SMBIOSPtr = (void *)((uintptr_t)SmbiosResponse->entry_64 - 0xFFFF800000000000);
+ else if (SmbiosResponse->entry_32 != NULL)
+ binfo.SMBIOSPtr = (void *)((uintptr_t)SmbiosResponse->entry_32 - 0xFFFF800000000000);
+ else
+ binfo.SMBIOSPtr = NULL;
+ debug("SMBIOS: %#lx %#lx (binfo: %#lx)",
+ SmbiosResponse->entry_32,
+ SmbiosResponse->entry_64,
+ binfo.SMBIOSPtr);
+
+ binfo.Kernel.PhysicalBase = (void *)KernelAddressResponse->physical_base;
+ binfo.Kernel.VirtualBase = (void *)KernelAddressResponse->virtual_base;
+ binfo.Kernel.FileBase = (void *)((uintptr_t)KernelFileResponse->kernel_file->address - 0xFFFF800000000000);
+ binfo.Kernel.Size = KernelFileResponse->kernel_file->size;
+
+ strncpy(binfo.Kernel.CommandLine,
+ KernelFileResponse->kernel_file->cmdline,
+ strlen(KernelFileResponse->kernel_file->cmdline) + 1);
+
+ debug("Kernel physical address: %#lx", binfo.Kernel.PhysicalBase);
+ debug("Kernel virtual address: %#lx", binfo.Kernel.VirtualBase);
+
+ strncpy(binfo.Bootloader.Name,
+ BootloaderInfoResponse->name,
+ strlen(BootloaderInfoResponse->name) + 1);
+
+ strncpy(binfo.Bootloader.Version,
+ BootloaderInfoResponse->version,
+ strlen(BootloaderInfoResponse->version) + 1);
+
+ Entry(&binfo);
+}
diff --git a/Kernel/Architecture/amd64/Bootstrap/Multiboot.cpp b/Kernel/Architecture/amd64/Bootstrap/Multiboot.cpp
new file mode 100644
index 00000000..68657920
--- /dev/null
+++ b/Kernel/Architecture/amd64/Bootstrap/Multiboot.cpp
@@ -0,0 +1,299 @@
+#include
+
+#include
+#include
+#include
+
+#include "../../../kernel.h"
+
+EXTERNC void multiboot_main(uint64_t Magic, uint64_t Info)
+{
+ if (Info == NULL || Magic == NULL)
+ {
+ if (Magic == NULL)
+ error("Multiboot magic is NULL");
+ if (Info == NULL)
+ error("Multiboot info is NULL");
+ CPU::Stop();
+ }
+ else if (Magic != MULTIBOOT2_BOOTLOADER_MAGIC)
+ {
+ error("Multiboot magic is invalid (%#x != %#x)", Magic, MULTIBOOT2_BOOTLOADER_MAGIC);
+ CPU::Stop();
+ }
+
+ BootInfo mb2binfo{};
+
+ // Clear the BSS
+ // memset_unsafe(&_kernel_rodata_end, 0, &_kernel_end - &_kernel_rodata_end);
+
+ {
+ uint64_t div = 1193180 / 1000;
+ outb(0x43, 0xB6);
+ outb(0x42, (uint8_t)div);
+ outb(0x42, (uint8_t)(div >> 8));
+ uint8_t tmp = inb(0x61);
+ if (tmp != (tmp | 3))
+ outb(0x61, tmp | 3);
+
+ int pos = 0;
+ auto InfoAddress = Info;
+ for (auto Tag = (struct multiboot_tag *)((uint8_t *)InfoAddress + 8);
+ ;
+ Tag = (struct multiboot_tag *)((multiboot_uint8_t *)Tag + ((Tag->size + 7) & ~7)))
+ {
+ if (Tag->type == MULTIBOOT_TAG_TYPE_END)
+ {
+ debug("End of multiboot2 tags");
+ break;
+ }
+
+ switch (Tag->type)
+ {
+ case MULTIBOOT_TAG_TYPE_CMDLINE:
+ {
+ strncpy(mb2binfo.Kernel.CommandLine,
+ ((multiboot_tag_string *)Tag)->string,
+ strlen(((multiboot_tag_string *)Tag)->string));
+ debug("Kernel command line: %s", mb2binfo.Kernel.CommandLine);
+ break;
+ }
+ case MULTIBOOT_TAG_TYPE_BOOT_LOADER_NAME:
+ {
+ strncpy(mb2binfo.Bootloader.Name,
+ ((multiboot_tag_string *)Tag)->string,
+ strlen(((multiboot_tag_string *)Tag)->string));
+ debug("Bootloader name: %s", mb2binfo.Bootloader.Name);
+ break;
+ }
+ case MULTIBOOT_TAG_TYPE_MODULE:
+ {
+ multiboot_tag_module *module = (multiboot_tag_module *)Tag;
+ static int module_count = 0;
+ mb2binfo.Modules[module_count].Address = (void *)(uint64_t)module->mod_start;
+ mb2binfo.Modules[module_count].Size = module->size;
+ strncpy(mb2binfo.Modules[module_count].Path, "(null)", 6);
+ strncpy(mb2binfo.Modules[module_count].CommandLine, module->cmdline,
+ strlen(module->cmdline));
+ debug("Module: %s", mb2binfo.Modules[module_count].Path);
+ module_count++;
+ break;
+ }
+ case MULTIBOOT_TAG_TYPE_BASIC_MEMINFO:
+ {
+ multiboot_tag_basic_meminfo *meminfo = (multiboot_tag_basic_meminfo *)Tag;
+ fixme("basic_meminfo->[mem_lower: %#x, mem_upper: %#x]",
+ meminfo->mem_lower, meminfo->mem_upper);
+ break;
+ }
+ case MULTIBOOT_TAG_TYPE_BOOTDEV:
+ {
+ multiboot_tag_bootdev *bootdev = (multiboot_tag_bootdev *)Tag;
+ fixme("bootdev->[biosdev: %#x, slice: %#x, part: %#x]",
+ bootdev->biosdev, bootdev->slice, bootdev->part);
+ break;
+ }
+ case MULTIBOOT_TAG_TYPE_MMAP:
+ {
+ multiboot_tag_mmap *mmap = (multiboot_tag_mmap *)Tag;
+ size_t EntryCount = mmap->size / sizeof(multiboot_mmap_entry);
+ mb2binfo.Memory.Entries = EntryCount;
+ for (uint32_t i = 0; i < EntryCount; i++)
+ {
+ if (EntryCount > MAX_MEMORY_ENTRIES)
+ {
+ warn("Too many memory entries, skipping the rest...");
+ break;
+ }
+ multiboot_mmap_entry entry = mmap->entries[i];
+ mb2binfo.Memory.Size += entry.len;
+ switch (entry.type)
+ {
+ case MULTIBOOT_MEMORY_AVAILABLE:
+ mb2binfo.Memory.Entry[i].BaseAddress = (void *)entry.addr;
+ mb2binfo.Memory.Entry[i].Length = entry.len;
+ mb2binfo.Memory.Entry[i].Type = Usable;
+ break;
+ case MULTIBOOT_MEMORY_RESERVED:
+ mb2binfo.Memory.Entry[i].BaseAddress = (void *)entry.addr;
+ mb2binfo.Memory.Entry[i].Length = entry.len;
+ mb2binfo.Memory.Entry[i].Type = Reserved;
+ break;
+ case MULTIBOOT_MEMORY_ACPI_RECLAIMABLE:
+ mb2binfo.Memory.Entry[i].BaseAddress = (void *)entry.addr;
+ mb2binfo.Memory.Entry[i].Length = entry.len;
+ mb2binfo.Memory.Entry[i].Type = ACPIReclaimable;
+ break;
+ case MULTIBOOT_MEMORY_NVS:
+ mb2binfo.Memory.Entry[i].BaseAddress = (void *)entry.addr;
+ mb2binfo.Memory.Entry[i].Length = entry.len;
+ mb2binfo.Memory.Entry[i].Type = ACPINVS;
+ break;
+ case MULTIBOOT_MEMORY_BADRAM:
+ mb2binfo.Memory.Entry[i].BaseAddress = (void *)entry.addr;
+ mb2binfo.Memory.Entry[i].Length = entry.len;
+ mb2binfo.Memory.Entry[i].Type = BadMemory;
+ break;
+ default:
+ mb2binfo.Memory.Entry[i].BaseAddress = (void *)entry.addr;
+ mb2binfo.Memory.Entry[i].Length = entry.len;
+ mb2binfo.Memory.Entry[i].Type = Unknown;
+ break;
+ }
+ debug("Memory entry: [BaseAddress: %#x, Length: %#x, Type: %d]",
+ mb2binfo.Memory.Entry[i].BaseAddress,
+ mb2binfo.Memory.Entry[i].Length,
+ mb2binfo.Memory.Entry[i].Type);
+ }
+ break;
+ }
+ case MULTIBOOT_TAG_TYPE_VBE:
+ {
+ multiboot_tag_vbe *vbe = (multiboot_tag_vbe *)Tag;
+ fixme("vbe->[vbe_mode: %#x, vbe_interface_seg: %#x, vbe_interface_off: %#x, vbe_interface_len: %#x]",
+ vbe->vbe_mode, vbe->vbe_interface_seg, vbe->vbe_interface_off, vbe->vbe_interface_len);
+ break;
+ }
+ case MULTIBOOT_TAG_TYPE_FRAMEBUFFER:
+ {
+ multiboot_tag_framebuffer *fb = (multiboot_tag_framebuffer *)Tag;
+ static int fb_count = 0;
+ mb2binfo.Framebuffer[fb_count].BaseAddress = (void *)fb->common.framebuffer_addr;
+ mb2binfo.Framebuffer[fb_count].Width = fb->common.framebuffer_width;
+ mb2binfo.Framebuffer[fb_count].Height = fb->common.framebuffer_height;
+ mb2binfo.Framebuffer[fb_count].Pitch = fb->common.framebuffer_pitch;
+ mb2binfo.Framebuffer[fb_count].BitsPerPixel = fb->common.framebuffer_bpp;
+ switch (fb->common.framebuffer_type)
+ {
+ case MULTIBOOT_FRAMEBUFFER_TYPE_INDEXED:
+ {
+ mb2binfo.Framebuffer[fb_count].Type = Indexed;
+ break;
+ }
+ case MULTIBOOT_FRAMEBUFFER_TYPE_RGB:
+ {
+ mb2binfo.Framebuffer[fb_count].Type = RGB;
+ mb2binfo.Framebuffer[fb_count].RedMaskSize = fb->framebuffer_red_mask_size;
+ mb2binfo.Framebuffer[fb_count].RedMaskShift = fb->framebuffer_red_field_position;
+ mb2binfo.Framebuffer[fb_count].GreenMaskSize = fb->framebuffer_green_mask_size;
+ mb2binfo.Framebuffer[fb_count].GreenMaskShift = fb->framebuffer_green_field_position;
+ mb2binfo.Framebuffer[fb_count].BlueMaskSize = fb->framebuffer_blue_mask_size;
+ mb2binfo.Framebuffer[fb_count].BlueMaskShift = fb->framebuffer_blue_field_position;
+ break;
+ }
+ case MULTIBOOT_FRAMEBUFFER_TYPE_EGA_TEXT:
+ {
+ mb2binfo.Framebuffer[fb_count].Type = EGA;
+ break;
+ }
+ default:
+ {
+ mb2binfo.Framebuffer[fb_count].Type = Unknown_Framebuffer_Type;
+ break;
+ }
+ }
+ debug("Framebuffer %d: %dx%d %d bpp", fb_count, fb->common.framebuffer_width, fb->common.framebuffer_height, fb->common.framebuffer_bpp);
+ debug("More info:\nAddress: %p\nPitch: %lld\nMemoryModel: %d\nRedMaskSize: %d\nRedMaskShift: %d\nGreenMaskSize: %d\nGreenMaskShift: %d\nBlueMaskSize: %d\nBlueMaskShift: %d",
+ fb->common.framebuffer_addr, fb->common.framebuffer_pitch, fb->common.framebuffer_type,
+ fb->framebuffer_red_mask_size, fb->framebuffer_red_field_position, fb->framebuffer_green_mask_size,
+ fb->framebuffer_green_field_position, fb->framebuffer_blue_mask_size, fb->framebuffer_blue_field_position);
+ fb_count++;
+ break;
+ }
+ case MULTIBOOT_TAG_TYPE_ELF_SECTIONS:
+ {
+ multiboot_tag_elf_sections *elf = (multiboot_tag_elf_sections *)Tag;
+ fixme("elf_sections->[num=%d, size=%d, entsize=%d, shndx=%d]",
+ elf->num, elf->size, elf->entsize, elf->shndx);
+ break;
+ }
+ case MULTIBOOT_TAG_TYPE_APM:
+ {
+ multiboot_tag_apm *apm = (multiboot_tag_apm *)Tag;
+ fixme("apm->[version: %d, cseg: %d, offset: %d, cseg_16: %d, dseg: %d, flags: %d, cseg_len: %d, cseg_16_len: %d, dseg_len: %d]",
+ apm->version, apm->cseg, apm->offset, apm->cseg_16, apm->dseg, apm->flags, apm->cseg_len, apm->cseg_16_len, apm->dseg_len);
+ break;
+ }
+ case MULTIBOOT_TAG_TYPE_EFI32:
+ {
+ multiboot_tag_efi32 *efi32 = (multiboot_tag_efi32 *)Tag;
+ fixme("efi32->[pointer: %p, size: %d]", efi32->pointer, efi32->size);
+ break;
+ }
+ case MULTIBOOT_TAG_TYPE_EFI64:
+ {
+ multiboot_tag_efi64 *efi64 = (multiboot_tag_efi64 *)Tag;
+ fixme("efi64->[pointer: %p, size: %d]", efi64->pointer, efi64->size);
+ break;
+ }
+ case MULTIBOOT_TAG_TYPE_SMBIOS:
+ {
+ multiboot_tag_smbios *smbios = (multiboot_tag_smbios *)Tag;
+ fixme("smbios->[major: %d, minor: %d]", smbios->major, smbios->minor);
+ break;
+ }
+ case MULTIBOOT_TAG_TYPE_ACPI_OLD:
+ {
+ mb2binfo.RSDP = (BootInfo::RSDPInfo *)((multiboot_tag_old_acpi *)Tag)->rsdp;
+ debug("OLD ACPI RSDP: %p", mb2binfo.RSDP);
+ break;
+ }
+ case MULTIBOOT_TAG_TYPE_ACPI_NEW:
+ {
+ mb2binfo.RSDP = (BootInfo::RSDPInfo *)((multiboot_tag_new_acpi *)Tag)->rsdp;
+ debug("NEW ACPI RSDP: %p", mb2binfo.RSDP);
+ break;
+ }
+ case MULTIBOOT_TAG_TYPE_NETWORK:
+ {
+ multiboot_tag_network *net = (multiboot_tag_network *)Tag;
+ fixme("network->[dhcpack: %p]", net->dhcpack);
+ break;
+ }
+ case MULTIBOOT_TAG_TYPE_EFI_MMAP:
+ {
+ multiboot_tag_efi_mmap *efi_mmap = (multiboot_tag_efi_mmap *)Tag;
+ fixme("efi_mmap->[descr_size: %d, descr_vers: %d, efi_mmap: %p]",
+ efi_mmap->descr_size, efi_mmap->descr_vers, efi_mmap->efi_mmap);
+ break;
+ }
+ case MULTIBOOT_TAG_TYPE_EFI_BS:
+ {
+ fixme("efi_bs->[%p] (unknown structure)", Tag);
+ break;
+ }
+ case MULTIBOOT_TAG_TYPE_EFI32_IH:
+ {
+ multiboot_tag_efi32_ih *efi32_ih = (multiboot_tag_efi32_ih *)Tag;
+ fixme("efi32_ih->[pointer: %p]", efi32_ih->pointer);
+ break;
+ }
+ case MULTIBOOT_TAG_TYPE_EFI64_IH:
+ {
+ multiboot_tag_efi64_ih *efi64_ih = (multiboot_tag_efi64_ih *)Tag;
+ fixme("efi64_ih->[pointer: %p]", efi64_ih->pointer);
+ break;
+ }
+ case MULTIBOOT_TAG_TYPE_LOAD_BASE_ADDR:
+ {
+ multiboot_tag_load_base_addr *load_base_addr = (multiboot_tag_load_base_addr *)Tag;
+ mb2binfo.Kernel.PhysicalBase = (void *)(uint64_t)load_base_addr->load_base_addr;
+ mb2binfo.Kernel.VirtualBase = (void *)(uint64_t)(load_base_addr->load_base_addr + 0xFFFFFFFF80000000);
+ mb2binfo.Kernel.Size = ((uint64_t)&_kernel_end - (uint64_t)&_kernel_start) + ((uint64_t)&_bootstrap_end - (uint64_t)&_bootstrap_start);
+ debug("Kernel base: %p (physical) %p (virtual)", mb2binfo.Kernel.PhysicalBase, mb2binfo.Kernel.VirtualBase);
+ break;
+ }
+ default:
+ {
+ error("Unknown multiboot2 tag type: %d", Tag->type);
+ break;
+ }
+ }
+ }
+
+ tmp = inb(0x61) & 0xFC;
+ outb(0x61, tmp);
+ }
+
+ Entry(&mb2binfo);
+}
diff --git a/Kernel/Architecture/amd64/Bootstrap/Multiboot64bitMap.cpp b/Kernel/Architecture/amd64/Bootstrap/Multiboot64bitMap.cpp
new file mode 100644
index 00000000..9cfcac91
--- /dev/null
+++ b/Kernel/Architecture/amd64/Bootstrap/Multiboot64bitMap.cpp
@@ -0,0 +1,287 @@
+#include
+
+union __attribute__((packed)) PageTableEntry
+{
+ struct
+ {
+ bool Present : 1; // 0
+ bool ReadWrite : 1; // 1
+ bool UserSupervisor : 1; // 2
+ bool WriteThrough : 1; // 3
+ bool CacheDisable : 1; // 4
+ bool Accessed : 1; // 5
+ bool Dirty : 1; // 6
+ bool PageAttributeTable : 1; // 7
+ bool Global : 1; // 8
+ uint8_t Available0 : 3; // 9-11
+ uint64_t Address : 40; // 12-51
+ uint32_t Available1 : 7; // 52-58
+ uint8_t ProtectionKey : 4; // 59-62
+ bool ExecuteDisable : 1; // 63
+ };
+ uint64_t raw;
+
+ __always_inline inline SafeFunction NIF void SetAddress(uintptr_t _Address)
+ {
+ _Address &= 0x000000FFFFFFFFFF;
+ this->raw &= 0xFFF0000000000FFF;
+ this->raw |= (_Address << 12);
+ }
+
+ __always_inline inline SafeFunction NIF uintptr_t GetAddress() { return (this->raw & 0x000FFFFFFFFFF000) >> 12; }
+};
+
+struct __attribute__((packed)) PageTableEntryPtr
+{
+ PageTableEntry Entries[512];
+};
+
+union __attribute__((packed)) PageDirectoryEntry
+{
+ struct
+ {
+ bool Present : 1; // 0
+ bool ReadWrite : 1; // 1
+ bool UserSupervisor : 1; // 2
+ bool WriteThrough : 1; // 3
+ bool CacheDisable : 1; // 4
+ bool Accessed : 1; // 5
+ bool Available0 : 1; // 6
+ bool PageSize : 1; // 7
+ uint8_t Available1 : 4; // 8-11
+ uint64_t Address : 40; // 12-51
+ uint32_t Available2 : 11; // 52-62
+ bool ExecuteDisable : 1; // 63
+ };
+ uint64_t raw;
+
+ __always_inline inline SafeFunction NIF void SetAddress(uintptr_t _Address)
+ {
+ _Address &= 0x000000FFFFFFFFFF;
+ this->raw &= 0xFFF0000000000FFF;
+ this->raw |= (_Address << 12);
+ }
+
+ __always_inline inline SafeFunction NIF uintptr_t GetAddress() { return (this->raw & 0x000FFFFFFFFFF000) >> 12; }
+};
+
+struct __attribute__((packed)) PageDirectoryEntryPtr
+{
+ PageDirectoryEntry Entries[512];
+};
+
+union __attribute__((packed)) PageDirectoryPointerTableEntry
+{
+ struct
+ {
+ bool Present : 1; // 0
+ bool ReadWrite : 1; // 1
+ bool UserSupervisor : 1; // 2
+ bool WriteThrough : 1; // 3
+ bool CacheDisable : 1; // 4
+ bool Accessed : 1; // 5
+ bool Available0 : 1; // 6
+ bool PageSize : 1; // 7
+ uint8_t Available1 : 4; // 8-11
+ uint64_t Address : 40; // 12-51
+ uint32_t Available2 : 11; // 52-62
+ bool ExecuteDisable : 1; // 63
+ };
+ uint64_t raw;
+
+ __always_inline inline SafeFunction NIF void SetAddress(uintptr_t _Address)
+ {
+ _Address &= 0x000000FFFFFFFFFF;
+ this->raw &= 0xFFF0000000000FFF;
+ this->raw |= (_Address << 12);
+ }
+
+ __always_inline inline SafeFunction NIF uintptr_t GetAddress() { return (this->raw & 0x000FFFFFFFFFF000) >> 12; }
+};
+
+struct __attribute__((packed)) PageDirectoryPointerTableEntryPtr
+{
+ PageDirectoryPointerTableEntry Entries[512];
+};
+
+union __attribute__((packed)) PageMapLevel4
+{
+ struct
+ {
+ bool Present : 1; // 0
+ bool ReadWrite : 1; // 1
+ bool UserSupervisor : 1; // 2
+ bool WriteThrough : 1; // 3
+ bool CacheDisable : 1; // 4
+ bool Accessed : 1; // 5
+ bool Available0 : 1; // 6
+ bool Reserved0 : 1; // 7
+ uint8_t Available1 : 4; // 8-11
+ uint64_t Address : 40; // 12-51
+ uint32_t Available2 : 11; // 52-62
+ bool ExecuteDisable : 1; // 63
+ };
+ uint64_t raw;
+
+ __always_inline inline SafeFunction NIF void SetAddress(uintptr_t _Address)
+ {
+ _Address &= 0x000000FFFFFFFFFF;
+ this->raw &= 0xFFF0000000000FFF;
+ this->raw |= (_Address << 12);
+ }
+
+ __always_inline inline SafeFunction NIF uintptr_t GetAddress() { return (this->raw & 0x000FFFFFFFFFF000) >> 12; }
+};
+
+struct PageTable4
+{
+ PageMapLevel4 Entries[512];
+} __attribute__((aligned(0x1000)));
+
+extern "C" char BootPageTable[];
+extern uintptr_t _kernel_start, _kernel_end;
+
+__attribute__((section(".bootstrap.data"))) static PageTable4 *BPTable = (PageTable4 *)BootPageTable;
+__attribute__((section(".bootstrap.data"))) static size_t BPT_Allocated = 0x4000;
+
+__always_inline inline SafeFunction NIF void *RequestPage()
+{
+ void *Page = (void *)(BootPageTable + BPT_Allocated);
+ BPT_Allocated += 0x1000;
+ if (BPT_Allocated >= 0x10000) /* The length of BootPageTable */
+ {
+ while (true)
+ ;
+ }
+ return Page;
+}
+
+class PageMapIndexer
+{
+public:
+ uintptr_t PMLIndex = 0;
+ uintptr_t PDPTEIndex = 0;
+ uintptr_t PDEIndex = 0;
+ uintptr_t PTEIndex = 0;
+ __always_inline inline SafeFunction NIF PageMapIndexer(uintptr_t VirtualAddress)
+ {
+ uintptr_t Address = VirtualAddress;
+ Address >>= 12;
+ this->PTEIndex = Address & 0x1FF;
+ Address >>= 9;
+ this->PDEIndex = Address & 0x1FF;
+ Address >>= 9;
+ this->PDPTEIndex = Address & 0x1FF;
+ Address >>= 9;
+ this->PMLIndex = Address & 0x1FF;
+ }
+};
+
+__attribute__((section(".bootstrap.text"))) SafeFunction NIF void MB2_64_Map(void *VirtualAddress, void *PhysicalAddress, uint64_t Flags)
+{
+ PageMapIndexer Index = PageMapIndexer((uintptr_t)VirtualAddress);
+ // Clear any flags that are not 1 << 0 (Present) - 1 << 5 (Accessed) because rest are for page table entries only
+ uint64_t DirectoryFlags = Flags & 0x3F;
+
+ PageMapLevel4 PML4 = BPTable->Entries[Index.PMLIndex];
+ PageDirectoryPointerTableEntryPtr *PDPTEPtr = nullptr;
+ if (!PML4.Present)
+ {
+ PDPTEPtr = (PageDirectoryPointerTableEntryPtr *)RequestPage();
+ if (PDPTEPtr == nullptr)
+ return;
+ {
+ void *ptr = PDPTEPtr;
+ uint8_t value = 0;
+ size_t num = 0x1000;
+ uint8_t *p = (uint8_t *)ptr;
+ for (size_t i = 0; i < num; i++)
+ p[i] = value;
+ }
+ PML4.Present = true;
+ PML4.SetAddress((uintptr_t)PDPTEPtr >> 12);
+ }
+ else
+ PDPTEPtr = (PageDirectoryPointerTableEntryPtr *)((uintptr_t)PML4.GetAddress() << 12);
+ PML4.raw |= DirectoryFlags;
+ BPTable->Entries[Index.PMLIndex] = PML4;
+
+ PageDirectoryPointerTableEntry PDPTE = PDPTEPtr->Entries[Index.PDPTEIndex];
+ PageDirectoryEntryPtr *PDEPtr = nullptr;
+ if (!PDPTE.Present)
+ {
+ PDEPtr = (PageDirectoryEntryPtr *)RequestPage();
+ if (PDEPtr == nullptr)
+ return;
+ {
+ void *ptr = PDEPtr;
+ uint8_t value = 0;
+ size_t num = 0x1000;
+ uint8_t *p = (uint8_t *)ptr;
+ for (size_t i = 0; i < num; i++)
+ p[i] = value;
+ }
+ PDPTE.Present = true;
+ PDPTE.SetAddress((uintptr_t)PDEPtr >> 12);
+ }
+ else
+ PDEPtr = (PageDirectoryEntryPtr *)((uintptr_t)PDPTE.GetAddress() << 12);
+ PDPTE.raw |= DirectoryFlags;
+ PDPTEPtr->Entries[Index.PDPTEIndex] = PDPTE;
+
+ PageDirectoryEntry PDE = PDEPtr->Entries[Index.PDEIndex];
+ PageTableEntryPtr *PTEPtr = nullptr;
+ if (!PDE.Present)
+ {
+ PTEPtr = (PageTableEntryPtr *)RequestPage();
+ if (PTEPtr == nullptr)
+ return;
+ {
+ void *ptr = PTEPtr;
+ uint8_t value = 0;
+ size_t num = 0x1000;
+ uint8_t *p = (uint8_t *)ptr;
+ for (size_t i = 0; i < num; i++)
+ p[i] = value;
+ }
+ PDE.Present = true;
+ PDE.SetAddress((uintptr_t)PTEPtr >> 12);
+ }
+ else
+ PTEPtr = (PageTableEntryPtr *)((uintptr_t)PDE.GetAddress() << 12);
+ PDE.raw |= DirectoryFlags;
+ PDEPtr->Entries[Index.PDEIndex] = PDE;
+
+ PageTableEntry PTE = PTEPtr->Entries[Index.PTEIndex];
+ PTE.Present = true;
+ PTE.raw |= Flags;
+ PTE.SetAddress((uintptr_t)PhysicalAddress >> 12);
+ PTEPtr->Entries[Index.PTEIndex] = PTE;
+ asmv("invlpg (%0)"
+ :
+ : "r"(VirtualAddress)
+ : "memory");
+}
+
+EXTERNC __attribute__((section(".bootstrap.text"))) SafeFunction NIF __attribute__((section(".bootstrap.text"))) void UpdatePageTable64()
+{
+ BPTable = (PageTable4 *)BootPageTable;
+
+ // for (size_t i = 0; i < 0x10000000; i += 0x1000)
+ // MB2_64_Map((void *)i, (void *)i, 0x3);
+
+ uintptr_t KernelStart = (uintptr_t)&_kernel_start;
+ uintptr_t KernelEnd = (uintptr_t)&_kernel_end;
+ uintptr_t PhysicalStart = KernelStart - 0xFFFFFFFF80000000;
+ for (uintptr_t i = KernelStart; i < KernelEnd; i += 0x1000)
+ {
+ MB2_64_Map((void *)i, (void *)PhysicalStart, 0x3);
+ PhysicalStart += 0x1000;
+ }
+
+ asmv("mov %%cr3, %%rax\n"
+ "mov %%rax, %%cr3\n"
+ :
+ :
+ : "rax");
+}
diff --git a/Kernel/Architecture/amd64/Bootstrap/Multiboot_Init.asm b/Kernel/Architecture/amd64/Bootstrap/Multiboot_Init.asm
new file mode 100644
index 00000000..a72c3fcc
--- /dev/null
+++ b/Kernel/Architecture/amd64/Bootstrap/Multiboot_Init.asm
@@ -0,0 +1,114 @@
+[bits 32]
+KERNEL_STACK_SIZE equ 0x4000 ; 16KB
+
+extern multiboot_main
+extern LoadGDT32
+extern BootPageTable
+extern UpdatePageTable
+
+section .bootstrap.data
+
+MB_HeaderMagic:
+ dq 0
+
+MB_HeaderInfo:
+ dq 0
+
+section .bootstrap.text
+
+global _start
+_start:
+ cli
+
+ mov [MB_HeaderMagic], eax
+ mov [MB_HeaderInfo], ebx
+
+ 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, 0x80000000 | 0x1 ; 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
+
+
+
+; Access bits
+PRESENT equ 1 << 7
+NOT_SYS equ 1 << 4
+EXEC equ 1 << 3
+DC equ 1 << 2
+RW equ 1 << 1
+ACCESSED equ 1 << 0
+
+; Flags bits
+GRAN_4K equ 1 << 7
+SZ_32 equ 1 << 6
+LONG_MODE equ 1 << 5
+
+section .bootstrap.data
+GDT64:
+ .null: equ $ - GDT64
+ dq 0
+ .code: equ $ - GDT64
+ dd 0xFFFF
+ db 0
+ db PRESENT | NOT_SYS | EXEC | RW
+ db GRAN_4K | LONG_MODE | 0xF
+ db 0
+ .data: equ $ - GDT64
+ dd 0xFFFF
+ db 0
+ db PRESENT | NOT_SYS | RW
+ db GRAN_4K | SZ_32 | 0xF
+ db 0
+ .tss: equ $ - GDT64
+ dd 0x00000068
+ dd 0x00CF8900
+ .Ptr:
+ dw $ - GDT64 - 1
+ dq GDT64
+
+section .bootstrap.bss
+align 16
+KernelStack:
+ resb KERNEL_STACK_SIZE
diff --git a/Kernel/Architecture/amd64/Bootstrap/Multiboot_PageTable.asm b/Kernel/Architecture/amd64/Bootstrap/Multiboot_PageTable.asm
new file mode 100644
index 00000000..cc5caf3f
--- /dev/null
+++ b/Kernel/Architecture/amd64/Bootstrap/Multiboot_PageTable.asm
@@ -0,0 +1,45 @@
+PAGE_TABLE_SIZE equ 0x4 ; 1GB
+[bits 32]
+
+section .bootstrap.data
+align 0x1000
+global BootPageTable
+BootPageTable:
+ times (0x10000) dq 0 ; 0x4000
+
+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/Kernel/Architecture/amd64/DifferentiatedSystemDescriptionTable.cpp b/Kernel/Architecture/amd64/DifferentiatedSystemDescriptionTable.cpp
new file mode 100644
index 00000000..202fb25c
--- /dev/null
+++ b/Kernel/Architecture/amd64/DifferentiatedSystemDescriptionTable.cpp
@@ -0,0 +1,255 @@
+/*
+ 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 .
+*/
+
+#include "acpi.hpp"
+
+#include
+#include
+#include
+#include
+
+#include "cpu/apic.hpp"
+#include "../../kernel.h"
+
+#define ACPI_TIMER 0x0001
+#define ACPI_BUSMASTER 0x0010
+#define ACPI_GLOBAL 0x0020
+#define ACPI_POWER_BUTTON 0x0100
+#define ACPI_SLEEP_BUTTON 0x0200
+#define ACPI_RTC_ALARM 0x0400
+#define ACPI_PCIE_WAKE 0x4000
+#define ACPI_WAKE 0x8000
+
+namespace ACPI
+{
+ __always_inline inline bool IsCanonical(uint64_t Address)
+ {
+ return ((Address <= 0x00007FFFFFFFFFFF) || ((Address >= 0xFFFF800000000000) && (Address <= 0xFFFFFFFFFFFFFFFF)));
+ }
+
+#define ACPI_ENABLED 0x0001
+#define ACPI_SLEEP 0x2000
+
+#define ACPI_GAS_MMIO 0
+#define ACPI_GAS_IO 1
+#define ACPI_GAS_PCI 2
+
+ void DSDT::OnInterruptReceived(CPU::x64::TrapFrame *Frame)
+ {
+ debug("SCI Handle Triggered");
+ uint16_t Event = 0;
+ {
+ uint16_t a = 0, b = 0;
+ if (acpi->FADT->PM1aEventBlock)
+ {
+ a = inw(s_cst(uint16_t, acpi->FADT->PM1aEventBlock));
+ outw(s_cst(uint16_t, acpi->FADT->PM1aEventBlock), a);
+ }
+ if (acpi->FADT->PM1bEventBlock)
+ {
+ b = inw(s_cst(uint16_t, acpi->FADT->PM1bEventBlock));
+ outw(s_cst(uint16_t, acpi->FADT->PM1bEventBlock), b);
+ }
+ Event = a | b;
+ }
+
+ debug("SCI Event: %#lx", Event);
+ if (Event & ACPI_BUSMASTER)
+ {
+ fixme("ACPI Busmaster");
+ }
+ else if (Event & ACPI_GLOBAL)
+ {
+ fixme("ACPI Global");
+ }
+ else if (Event & ACPI_POWER_BUTTON)
+ {
+ if (TaskManager)
+ {
+ TaskManager->CreateThread(TaskManager->CreateProcess(nullptr,
+ "Shutdown",
+ Tasking::TaskTrustLevel::Kernel),
+ (Tasking::IP)KST_Shutdown);
+ }
+ else
+ KernelShutdownThread(false);
+ }
+ else if (Event & ACPI_SLEEP_BUTTON)
+ {
+ fixme("ACPI Sleep Button");
+ }
+ else if (Event & ACPI_RTC_ALARM)
+ {
+ fixme("ACPI RTC Alarm");
+ }
+ else if (Event & ACPI_PCIE_WAKE)
+ {
+ fixme("ACPI PCIe Wake");
+ }
+ else if (Event & ACPI_WAKE)
+ {
+ fixme("ACPI Wake");
+ }
+ else if (Event & ACPI_TIMER)
+ {
+ fixme("ACPI Timer");
+ }
+ else
+ {
+ error("ACPI unknown event %#lx on CPU %d", Event, GetCurrentCPU()->ID);
+ CPU::Stop();
+ }
+ UNUSED(Frame);
+ }
+
+ void DSDT::Shutdown()
+ {
+ trace("Shutting down...");
+ if (SCI_EN == 1)
+ {
+ outw(s_cst(uint16_t, acpi->FADT->PM1aControlBlock),
+ s_cst(uint16_t,
+ (inw(s_cst(uint16_t,
+ acpi->FADT->PM1aControlBlock)) &
+ 0xE3FF) |
+ ((SLP_TYPa << 10) | ACPI_SLEEP)));
+
+ if (acpi->FADT->PM1bControlBlock)
+ outw(s_cst(uint16_t, acpi->FADT->PM1bControlBlock),
+ s_cst(uint16_t,
+ (inw(
+ s_cst(uint16_t, acpi->FADT->PM1bControlBlock)) &
+ 0xE3FF) |
+ ((SLP_TYPb << 10) | ACPI_SLEEP)));
+
+ outw(s_cst(uint16_t, PM1a_CNT), SLP_TYPa | SLP_EN);
+ if (PM1b_CNT)
+ outw(s_cst(uint16_t, PM1b_CNT), SLP_TYPb | SLP_EN);
+ }
+ }
+
+ void DSDT::Reboot()
+ {
+ trace("Rebooting...");
+ switch (acpi->FADT->ResetReg.AddressSpace)
+ {
+ case ACPI_GAS_MMIO:
+ {
+ *(uint8_t *)(acpi->FADT->ResetReg.Address) = acpi->FADT->ResetValue;
+ break;
+ }
+ case ACPI_GAS_IO:
+ {
+ outb(s_cst(uint16_t, acpi->FADT->ResetReg.Address), acpi->FADT->ResetValue);
+ break;
+ }
+ case ACPI_GAS_PCI:
+ {
+ fixme("ACPI_GAS_PCI not supported.");
+ /*
+ seg - 0
+ bus - 0
+ dev - (FADT->ResetReg.Address >> 32) & 0xFFFF
+ function - (FADT->ResetReg.Address >> 16) & 0xFFFF
+ offset - FADT->ResetReg.Address & 0xFFFF
+ value - FADT->ResetValue
+ */
+ break;
+ }
+ default:
+ {
+ error("Unknown reset register address space: %d", acpi->FADT->ResetReg.AddressSpace);
+ break;
+ }
+ }
+ }
+
+ DSDT::DSDT(ACPI *acpi) : Interrupts::Handler(acpi->FADT->SCI_Interrupt)
+ {
+ this->acpi = acpi;
+ uint64_t Address = ((IsCanonical(acpi->FADT->X_Dsdt) && acpi->XSDTSupported) ? acpi->FADT->X_Dsdt : acpi->FADT->Dsdt);
+ uint8_t *S5Address = (uint8_t *)(Address) + 36;
+ ACPI::ACPI::ACPIHeader *Header = (ACPI::ACPI::ACPIHeader *)Address;
+ uint64_t Length = Header->Length;
+ while (Length-- > 0)
+ {
+ if (!memcmp(S5Address, "_S5_", 4))
+ break;
+ S5Address++;
+ }
+ if (Length <= 0)
+ {
+ warn("_S5 not present in ACPI");
+ return;
+ }
+ if ((*(S5Address - 1) == 0x08 || (*(S5Address - 2) == 0x08 && *(S5Address - 1) == '\\')) && *(S5Address + 4) == 0x12)
+ {
+ S5Address += 5;
+ S5Address += ((*S5Address & 0xC0) >> 6) + 2;
+ if (*S5Address == 0x0A)
+ S5Address++;
+ SLP_TYPa = s_cst(uint16_t, *(S5Address) << 10);
+ S5Address++;
+ if (*S5Address == 0x0A)
+ S5Address++;
+ SLP_TYPb = s_cst(uint16_t, *(S5Address) << 10);
+ SMI_CMD = acpi->FADT->SMI_CommandPort;
+ ACPI_ENABLE = acpi->FADT->AcpiEnable;
+ ACPI_DISABLE = acpi->FADT->AcpiDisable;
+ PM1a_CNT = acpi->FADT->PM1aControlBlock;
+ PM1b_CNT = acpi->FADT->PM1bControlBlock;
+ PM1_CNT_LEN = acpi->FADT->PM1ControlLength;
+ SLP_EN = 1 << 13;
+ SCI_EN = 1;
+ trace("ACPI Shutdown is supported");
+ ACPIShutdownSupported = true;
+
+ uint16_t value = ACPI_POWER_BUTTON | ACPI_SLEEP_BUTTON | ACPI_WAKE;
+ {
+ uint16_t a = s_cst(uint16_t, acpi->FADT->PM1aEventBlock + (acpi->FADT->PM1EventLength / 2));
+ uint16_t b = s_cst(uint16_t, acpi->FADT->PM1bEventBlock + (acpi->FADT->PM1EventLength / 2));
+ debug("SCI Event: %#llx [a:%#x b:%#x]", value, a, b);
+ if (acpi->FADT->PM1aEventBlock)
+ outw(a, value);
+ if (acpi->FADT->PM1bEventBlock)
+ outw(b, value);
+ }
+
+ {
+ uint16_t a = 0, b = 0;
+ if (acpi->FADT->PM1aEventBlock)
+ {
+ a = inw(s_cst(uint16_t, acpi->FADT->PM1aEventBlock));
+ outw(s_cst(uint16_t, acpi->FADT->PM1aEventBlock), a);
+ }
+ if (acpi->FADT->PM1bEventBlock)
+ {
+ b = inw(s_cst(uint16_t, acpi->FADT->PM1bEventBlock));
+ outw(s_cst(uint16_t, acpi->FADT->PM1bEventBlock), b);
+ }
+ }
+ ((APIC::APIC *)Interrupts::apic[0])->RedirectIRQ(0, acpi->FADT->SCI_Interrupt, 1);
+ return;
+ }
+ warn("Failed to parse _S5 in ACPI");
+ SCI_EN = 0;
+ }
+
+ DSDT::~DSDT()
+ {
+ }
+}
diff --git a/Kernel/Architecture/amd64/MultipleAPICDescriptionTable.cpp b/Kernel/Architecture/amd64/MultipleAPICDescriptionTable.cpp
new file mode 100644
index 00000000..70177fc3
--- /dev/null
+++ b/Kernel/Architecture/amd64/MultipleAPICDescriptionTable.cpp
@@ -0,0 +1,91 @@
+/*
+ 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 .
+*/
+
+#include "acpi.hpp"
+
+#include
+#include
+
+#include "../../kernel.h"
+
+namespace ACPI
+{
+ MADT::MADT(ACPI::MADTHeader *madt)
+ {
+ trace("Initializing MADT");
+ CPUCores = 0;
+ LAPICAddress = (LAPIC *)(uintptr_t)madt->LocalControllerAddress;
+ for (uint8_t *ptr = (uint8_t *)(madt->Entries);
+ (uintptr_t)(ptr) < (uintptr_t)(madt) + madt->Header.Length;
+ ptr += *(ptr + 1))
+ {
+ switch (*(ptr))
+ {
+ case 0:
+ {
+ if (ptr[4] & 1)
+ {
+ lapic.push_back((LocalAPIC *)ptr);
+ KPrint("Local APIC \e8888FF%d\eCCCCCC (APIC \e8888FF%d\eCCCCCC) found.", lapic.back()->ACPIProcessorId, lapic.back()->APICId);
+ CPUCores++;
+ }
+ break;
+ }
+ case 1:
+ {
+ ioapic.push_back((MADTIOApic *)ptr);
+ KPrint("I/O APIC \e8888FF%d\eCCCCCC (Address \e8888FF%#lx\eCCCCCC) found.", ioapic.back()->APICID, ioapic.back()->Address);
+ Memory::Virtual(KernelPageTable).Map((void *)(uintptr_t)ioapic.back()->Address, (void *)(uintptr_t)ioapic.back()->Address, Memory::PTFlag::RW | Memory::PTFlag::PCD); // Make sure that the address is mapped.
+ break;
+ }
+ case 2:
+ {
+ iso.push_back((MADTIso *)ptr);
+ KPrint("ISO (IRQ:\e8888FF%#lx\eCCCCCC, BUS:\e8888FF%#lx\eCCCCCC, GSI:\e8888FF%#lx\eCCCCCC, %s\eCCCCCC/%s\eCCCCCC) found.",
+ iso.back()->IRQSource, iso.back()->BuSSource, iso.back()->GSI,
+ iso.back()->Flags & 0x00000004 ? "\e1770FFActive High" : "\e475EFFActive Low",
+ iso.back()->Flags & 0x00000100 ? "\e00962DEdge Triggered" : "\e008F58Level Triggered");
+ break;
+ }
+ case 4:
+ {
+ nmi.push_back((MADTNmi *)ptr);
+ KPrint("NMI \e8888FF%#lx\eCCCCCC (lint:\e8888FF%#lx\eCCCCCC) found.", nmi.back()->processor, nmi.back()->lint);
+ break;
+ }
+ case 5:
+ {
+ LAPICAddress = (LAPIC *)ptr;
+ KPrint("APIC found at \e8888FF%#lx\eCCCCCC", LAPICAddress);
+ break;
+ }
+ default:
+ {
+ KPrint("Unknown MADT entry \e8888FF%#lx\eCCCCCC", *(ptr));
+ break;
+ }
+ }
+ Memory::Virtual(KernelPageTable).Map((void *)LAPICAddress, (void *)LAPICAddress, Memory::PTFlag::RW | Memory::PTFlag::PCD); // I should map more than one page?
+ }
+ CPUCores--; // We start at 0 (BSP) and end at 11 (APs), so we have 12 cores.
+ KPrint("Total CPU cores: %d", CPUCores + 1);
+ }
+
+ MADT::~MADT()
+ {
+ }
+}
diff --git a/Kernel/Architecture/amd64/SystemCalls.cpp b/Kernel/Architecture/amd64/SystemCalls.cpp
new file mode 100644
index 00000000..25775b34
--- /dev/null
+++ b/Kernel/Architecture/amd64/SystemCalls.cpp
@@ -0,0 +1,92 @@
+/*
+ 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 .
+*/
+
+#include
+
+#include
+
+#include "cpu/gdt.hpp"
+
+// https://supercip971.github.io/02-wingos-syscalls.html
+using namespace CPU::x64;
+
+// "Core/SystemCalls.cpp"
+extern "C" uint64_t SystemCallsHandler(SyscallsFrame *regs);
+
+extern "C" void SystemCallHandlerStub();
+
+extern "C" __naked __used __no_stack_protector __aligned(16) void SystemCallHandlerStub()
+{
+ asmv("swapgs\n"
+
+ "mov %rsp, %gs:0x8\n" // CPUData->TempStack
+ "mov %gs:0x0, %rsp\n" // CPUData->SystemCallStack
+ "push $0x1b\n" // user data segment
+ "push %gs:0x8\n" // saved stack
+ "push %r11\n" // saved rflags
+ "push $0x23\n" // user code segment
+ "push %rcx\n" // Current RIP
+
+ "push %rax\n"
+ "push %rbx\n"
+ "push %rcx\n"
+ "push %rdx\n"
+ "push %rsi\n"
+ "push %rdi\n"
+ "push %rbp\n"
+ "push %r8\n"
+ "push %r9\n"
+ "push %r10\n"
+ "push %r11\n"
+ "push %r12\n"
+ "push %r13\n"
+ "push %r14\n"
+ "push %r15\n"
+
+ "mov %rsp, %rdi\n"
+ "mov $0, %rbp\n"
+ "call SystemCallsHandler\n"
+
+ "pop %r15\n"
+ "pop %r14\n"
+ "pop %r13\n"
+ "pop %r12\n"
+ "pop %r11\n"
+ "pop %r10\n"
+ "pop %r9\n"
+ "pop %r8\n"
+ "pop %rbp\n"
+ "pop %rdi\n"
+ "pop %rsi\n"
+ "pop %rdx\n"
+ "pop %rcx\n"
+ "pop %rbx\n"
+
+ "mov %gs:0x8, %rsp\n" // CPUData->TempStack
+
+ "swapgs\n"
+ "sti\n"
+ "sysretq\n");
+}
+
+void InitializeSystemCalls()
+{
+ wrmsr(MSR_EFER, rdmsr(MSR_EFER) | 1);
+ wrmsr(MSR_STAR, ((uint64_t)(GDT_KERNEL_CODE) << 32) | ((uint64_t)(GDT_KERNEL_DATA | 3) << 48));
+ wrmsr(MSR_LSTAR, (uint64_t)SystemCallHandlerStub);
+ wrmsr(MSR_SYSCALL_MASK, (uint64_t)(1 << 9));
+}
diff --git a/Kernel/Architecture/amd64/acpi.hpp b/Kernel/Architecture/amd64/acpi.hpp
new file mode 100644
index 00000000..1a71f712
--- /dev/null
+++ b/Kernel/Architecture/amd64/acpi.hpp
@@ -0,0 +1,294 @@
+/*
+ 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 .
+*/
+
+#ifndef __FENNIX_KERNEL_ACPI_H__
+#define __FENNIX_KERNEL_ACPI_H__
+
+#include
+
+#include
+#include
+#include
+#include
+
+namespace ACPI
+{
+ class ACPI
+ {
+ public:
+ struct ACPIHeader
+ {
+ unsigned char Signature[4];
+ uint32_t Length;
+ uint8_t Revision;
+ uint8_t Checksum;
+ uint8_t OEMID[6];
+ uint8_t OEMTableID[8];
+ uint32_t OEMRevision;
+ uint32_t CreatorID;
+ uint32_t CreatorRevision;
+ } __packed;
+
+ struct GenericAddressStructure
+ {
+ uint8_t AddressSpace;
+ uint8_t BitWidth;
+ uint8_t BitOffset;
+ uint8_t AccessSize;
+ uint64_t Address;
+ } __packed;
+
+ struct MCFGHeader
+ {
+ struct ACPIHeader Header;
+ uint64_t Reserved;
+ } __packed;
+
+ struct HPETHeader
+ {
+ ACPIHeader Header;
+ uint8_t HardwareRevID;
+ uint8_t ComparatorCount : 5;
+ uint8_t CounterSize : 1;
+ uint8_t Reserved : 1;
+ uint8_t LegacyReplacement : 1;
+ uint16_t PCIVendorID;
+ struct GenericAddressStructure Address;
+ uint8_t HPETNumber;
+ uint16_t MinimumTick;
+ uint8_t PageProtection;
+ } __packed;
+
+ struct FADTHeader
+ {
+ ACPIHeader Header;
+ uint32_t FirmwareCtrl;
+ uint32_t Dsdt;
+ uint8_t Reserved;
+ uint8_t PreferredPowerManagementProfile;
+ uint16_t SCI_Interrupt;
+ uint32_t SMI_CommandPort;
+ uint8_t AcpiEnable;
+ uint8_t AcpiDisable;
+ uint8_t S4BIOS_REQ;
+ uint8_t PSTATE_Control;
+ uint32_t PM1aEventBlock;
+ uint32_t PM1bEventBlock;
+ uint32_t PM1aControlBlock;
+ uint32_t PM1bControlBlock;
+ uint32_t PM2ControlBlock;
+ uint32_t PMTimerBlock;
+ uint32_t GPE0Block;
+ uint32_t GPE1Block;
+ uint8_t PM1EventLength;
+ uint8_t PM1ControlLength;
+ uint8_t PM2ControlLength;
+ uint8_t PMTimerLength;
+ uint8_t GPE0Length;
+ uint8_t GPE1Length;
+ uint8_t GPE1Base;
+ uint8_t CStateControl;
+ uint16_t WorstC2Latency;
+ uint16_t WorstC3Latency;
+ uint16_t FlushSize;
+ uint16_t FlushStride;
+ uint8_t DutyOffset;
+ uint8_t DutyWidth;
+ uint8_t DayAlarm;
+ uint8_t MonthAlarm;
+ uint8_t Century;
+ uint16_t BootArchitectureFlags;
+ uint8_t Reserved2;
+ uint32_t Flags;
+ struct GenericAddressStructure ResetReg;
+ uint8_t ResetValue;
+ uint8_t Reserved3[3];
+ uint64_t X_FirmwareControl;
+ uint64_t X_Dsdt;
+ struct GenericAddressStructure X_PM1aEventBlock;
+ struct GenericAddressStructure X_PM1bEventBlock;
+ struct GenericAddressStructure X_PM1aControlBlock;
+ struct GenericAddressStructure X_PM1bControlBlock;
+ struct GenericAddressStructure X_PM2ControlBlock;
+ struct GenericAddressStructure X_PMTimerBlock;
+ struct GenericAddressStructure X_GPE0Block;
+ struct GenericAddressStructure X_GPE1Block;
+ } __packed;
+
+ struct BGRTHeader
+ {
+ ACPIHeader Header;
+ uint16_t Version;
+ uint8_t Status;
+ uint8_t ImageType;
+ uint64_t ImageAddress;
+ uint32_t ImageOffsetX;
+ uint32_t ImageOffsetY;
+ };
+
+ struct SRATHeader
+ {
+ ACPIHeader Header;
+ uint32_t TableRevision; // Must be value 1
+ uint64_t Reserved; // Reserved, must be zero
+ };
+
+ struct TPM2Header
+ {
+ ACPIHeader Header;
+ uint32_t Flags;
+ uint64_t ControlAddress;
+ uint32_t StartMethod;
+ };
+
+ struct TCPAHeader
+ {
+ ACPIHeader Header;
+ uint16_t Reserved;
+ uint32_t MaxLogLength;
+ uint64_t LogAddress;
+ };
+
+ struct WAETHeader
+ {
+ ACPIHeader Header;
+ uint32_t Flags;
+ };
+
+ struct HESTHeader
+ {
+ ACPIHeader Header;
+ uint32_t ErrorSourceCount;
+ };
+
+ struct MADTHeader
+ {
+ ACPIHeader Header;
+ uint32_t LocalControllerAddress;
+ uint32_t Flags;
+ char Entries[];
+ } __packed;
+
+ ACPIHeader *XSDT = nullptr;
+ MCFGHeader *MCFG = nullptr;
+ HPETHeader *HPET = nullptr;
+ FADTHeader *FADT = nullptr;
+ BGRTHeader *BGRT = nullptr;
+ SRATHeader *SRAT = nullptr;
+ TPM2Header *TPM2 = nullptr;
+ TCPAHeader *TCPA = nullptr;
+ WAETHeader *WAET = nullptr;
+ MADTHeader *MADT = nullptr;
+ HESTHeader *HEST = nullptr;
+ bool XSDTSupported = false;
+
+ void *FindTable(ACPIHeader *ACPIHeader, char *Signature);
+ void SearchTables(ACPIHeader *Header);
+ ACPI();
+ ~ACPI();
+ };
+
+ class MADT
+ {
+ public:
+ struct APICHeader
+ {
+ uint8_t Type;
+ uint8_t Length;
+ } __packed;
+
+ struct MADTIOApic
+ {
+ struct APICHeader Header;
+ uint8_t APICID;
+ uint8_t reserved;
+ uint32_t Address;
+ uint32_t GSIBase;
+ } __packed;
+
+ struct MADTIso
+ {
+ struct APICHeader Header;
+ uint8_t BuSSource;
+ uint8_t IRQSource;
+ uint32_t GSI;
+ uint16_t Flags;
+ } __packed;
+
+ struct MADTNmi
+ {
+ struct APICHeader Header;
+ uint8_t processor;
+ uint16_t flags;
+ uint8_t lint;
+ } __packed;
+
+ struct LocalAPIC
+ {
+ struct APICHeader Header;
+ uint8_t ACPIProcessorId;
+ uint8_t APICId;
+ uint32_t Flags;
+ } __packed;
+
+ struct LAPIC
+ {
+ uint8_t id;
+ uintptr_t PhysicalAddress;
+ void *VirtualAddress;
+ };
+
+ std::vector ioapic;
+ std::vector iso;
+ std::vector nmi;
+ std::vector lapic;
+ struct LAPIC *LAPICAddress;
+ uint16_t CPUCores;
+
+ MADT(ACPI::MADTHeader *madt);
+ ~MADT();
+ };
+
+ class DSDT : public Interrupts::Handler
+ {
+ private:
+ uint32_t SMI_CMD = 0;
+ uint8_t ACPI_ENABLE = 0;
+ uint8_t ACPI_DISABLE = 0;
+ uint32_t PM1a_CNT = 0;
+ uint32_t PM1b_CNT = 0;
+ uint16_t SLP_TYPa = 0;
+ uint16_t SLP_TYPb = 0;
+ uint16_t SLP_EN = 0;
+ uint16_t SCI_EN = 0;
+ uint8_t PM1_CNT_LEN = 0;
+
+ ACPI *acpi;
+ void OnInterruptReceived(CPU::x64::TrapFrame *Frame);
+
+ public:
+ bool ACPIShutdownSupported = false;
+
+ void Reboot();
+ void Shutdown();
+
+ DSDT(ACPI *acpi);
+ ~DSDT();
+ };
+}
+
+#endif // !__FENNIX_KERNEL_ACPI_H__
diff --git a/Kernel/Architecture/amd64/cpu/AdvancedProgrammableInterruptController.cpp b/Kernel/Architecture/amd64/cpu/AdvancedProgrammableInterruptController.cpp
new file mode 100644
index 00000000..c19b7358
--- /dev/null
+++ b/Kernel/Architecture/amd64/cpu/AdvancedProgrammableInterruptController.cpp
@@ -0,0 +1,403 @@
+/*
+ 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 .
+*/
+
+#include "apic.hpp"
+
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include "../../../kernel.h"
+#include "../acpi.hpp"
+
+NewLock(APICLock);
+
+using namespace CPU::x64;
+using namespace CPU::x86;
+
+/*
+In constructor ‘APIC::APIC::APIC(int)’:
+warning: left shift count >= width of type
+| APICBaseAddress = BaseStruct.ApicBaseLo << 12u | BaseStruct.ApicBaseHi << 32u;
+| ~~~~~~~~~~~~~~~~~~~~~~^~~~~~
+*/
+#pragma GCC diagnostic ignored "-Wshift-count-overflow"
+
+namespace APIC
+{
+ // 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)
+ {
+#ifdef DEBUG
+ 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;
+ }
+ }
+
+ 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);
+#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();
+ }
+ }
+
+ 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;
+ }
+
+ 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::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::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;
+ }
+
+ 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;
+ }
+
+ if (IOAPICTarget == -1)
+ {
+ error("No ISO table found for I/O APIC");
+ return;
+ }
+
+ // TODO: IOAPICRedirectEntry Entry = {.raw = 0};
+
+ if (Flags & ActiveHighLow)
+ Value |= (1 << 13);
+
+ if (Flags & EdgeLevel)
+ Value |= (1 << 15);
+
+ if (!Status)
+ Value |= (1 << 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));
+ }
+
+ 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);
+ }
+
+ 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);
+
+ 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);
+ }
+
+ 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));
+ }
+
+ 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;
+
+ 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));
+
+ static int once = 0;
+ if (!once++)
+ {
+ // Disable PIT
+ outb(0x43, 0x28);
+ outb(0x40, 0x0);
+
+ // Disable PIC
+ outb(0x21, 0xFF);
+ outb(0xA1, 0xFF);
+ }
+ }
+
+ APIC::~APIC() {}
+
+ 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));
+ }
+
+ 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);
+
+ this->lapic->Write(APIC_TDCR, Divider);
+ this->lapic->Write(APIC_TICR, 0xFFFFFFFF);
+
+ 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);
+
+ // 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);
+ }
+
+ Timer::~Timer()
+ {
+ }
+}
diff --git a/Kernel/Architecture/amd64/cpu/GlobalDescriptorTable.cpp b/Kernel/Architecture/amd64/cpu/GlobalDescriptorTable.cpp
new file mode 100644
index 00000000..5dc43dea
--- /dev/null
+++ b/Kernel/Architecture/amd64/cpu/GlobalDescriptorTable.cpp
@@ -0,0 +1,214 @@
+/*
+ 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 .
+*/
+
+#include "gdt.hpp"
+
+#include
+#include
+#include
+#include
+
+namespace GlobalDescriptorTable
+{
+ static GlobalDescriptorTableEntries GDTEntriesTemplate = {
+ .Null =
+ {
+ .Length = 0x0,
+ .BaseLow = 0x0,
+ .BaseMiddle = 0x0,
+ .Access = {.Raw = 0x0},
+ .Flags = {.Raw = 0x0},
+ .BaseHigh = 0x0,
+ },
+
+ .Code =
+ {
+ .Length = 0x0,
+ .BaseLow = 0x0,
+ .BaseMiddle = 0x0,
+ .Access = {
+ .A = 0,
+ .RW = 1,
+ .DC = 0,
+ .E = 1,
+ .S = 1,
+ .DPL = 0,
+ .P = 1,
+ },
+ .Flags = {
+ .Unknown = 0x0,
+ .L = 1,
+ },
+ .BaseHigh = 0x0,
+ },
+
+ .Data = {
+ .Length = 0x0,
+ .BaseLow = 0x0,
+ .BaseMiddle = 0x0,
+ .Access = {
+ .A = 0,
+ .RW = 1,
+ .DC = 0,
+ .E = 0,
+ .S = 1,
+ .DPL = 0,
+ .P = 1,
+ },
+ .Flags = {.Raw = 0x0},
+ .BaseHigh = 0x0,
+ },
+
+ .UserData = {
+ .Length = 0x0,
+ .BaseLow = 0x0,
+ .BaseMiddle = 0x0,
+ .Access = {
+ .A = 0,
+ .RW = 1,
+ .DC = 0,
+ .E = 0,
+ .S = 1,
+ .DPL = 3,
+ .P = 1,
+ },
+ .Flags = {
+ .Raw = 0x0,
+ },
+ .BaseHigh = 0x0,
+ },
+
+ .UserCode = {
+ .Length = 0x0,
+ .BaseLow = 0x0,
+ .BaseMiddle = 0x0,
+ .Access = {
+ .A = 0,
+ .RW = 1,
+ .DC = 0,
+ .E = 1,
+ .S = 1,
+ .DPL = 3,
+ .P = 1,
+ },
+ .Flags = {
+ .Unknown = 0x0,
+ .L = 1,
+ },
+ .BaseHigh = 0x0,
+ },
+
+ .TaskStateSegment = {},
+ };
+
+ GlobalDescriptorTableEntries GDTEntries[MAX_CPU] __aligned(16);
+ GlobalDescriptorTableDescriptor gdt[MAX_CPU] __aligned(16);
+
+ TaskStateSegment tss[MAX_CPU] = {
+ 0,
+ {0, 0, 0},
+ 0,
+ {0, 0, 0, 0, 0, 0, 0},
+ 0,
+ 0,
+ 0,
+ };
+
+ void *CPUStackPointer[MAX_CPU];
+
+ SafeFunction void Init(int Core)
+ {
+ memcpy(&GDTEntries[Core], &GDTEntriesTemplate, sizeof(GlobalDescriptorTableEntries));
+ gdt[Core] = {.Length = sizeof(GlobalDescriptorTableEntries) - 1, .Entries = &GDTEntries[Core]};
+
+ debug("Kernel: Code Access: %ld; Data Access: %ld", GDTEntries[Core].Code.Access.Raw, GDTEntries[Core].Data.Access.Raw);
+ debug("Kernel: Code Flags: %ld; Data Flags: %ld", GDTEntries[Core].Code.Flags.Raw, GDTEntries[Core].Data.Flags.Raw);
+ debug("User: Code Access: %ld; Data Access: %ld", GDTEntries[Core].UserCode.Access.Raw, GDTEntries[Core].UserData.Access.Raw);
+ debug("User: Code Flags: %ld; Data Flags: %ld", GDTEntries[Core].UserCode.Flags.Raw, GDTEntries[Core].UserData.Flags.Raw);
+ CPU::x64::lgdt(&gdt[Core]);
+
+ asmv("movq %%rsp, %%rax\n"
+ "pushq $16\n"
+ "pushq %%rax\n"
+ "pushfq\n"
+ "pushq $8\n"
+ "pushq $1f\n"
+ "iretq\n"
+ "1:\n"
+ "movw $16, %%ax\n"
+ "movw %%ax, %%ds\n"
+ "movw %%ax, %%es\n" ::
+ : "memory", "rax");
+
+ CPUStackPointer[Core] = KernelAllocator.RequestPages(TO_PAGES(STACK_SIZE + 1));
+ memset(CPUStackPointer[Core], 0, STACK_SIZE);
+ debug("CPU %d Stack Pointer: %#lx-%#lx (%d pages)", Core,
+ CPUStackPointer[Core], (uintptr_t)CPUStackPointer[Core] + STACK_SIZE,
+ TO_PAGES(STACK_SIZE + 1));
+
+ uintptr_t Base = (uintptr_t)&tss[Core];
+ size_t Limit = Base + sizeof(TaskStateSegment);
+ gdt[Core].Entries->TaskStateSegment.Length = Limit & 0xFFFF;
+ gdt[Core].Entries->TaskStateSegment.BaseLow = Base & 0xFFFF;
+ gdt[Core].Entries->TaskStateSegment.BaseMiddle = (Base >> 16) & 0xFF;
+ gdt[Core].Entries->TaskStateSegment.BaseHigh = (Base >> 24) & 0xFF;
+ gdt[Core].Entries->TaskStateSegment.BaseUpper = s_cst(uint32_t, (Base >> 32) & 0xFFFFFFFF);
+ gdt[Core].Entries->TaskStateSegment.Flags = {.A = 1, .RW = 0, .DC = 0, .E = 1, .S = 0, .DPL = 0, .P = 1};
+ gdt[Core].Entries->TaskStateSegment.Granularity = (0 << 4) | ((Limit >> 16) & 0xF);
+
+ tss[Core].IOMapBaseAddressOffset = sizeof(TaskStateSegment);
+ tss[Core].StackPointer[0] = (uint64_t)CPUStackPointer[Core] + STACK_SIZE;
+
+ for (size_t i = 0; i < sizeof(tss[Core].InterruptStackTable) / sizeof(tss[Core].InterruptStackTable[7]); i++)
+ {
+ void *NewStack = KernelAllocator.RequestPages(TO_PAGES(STACK_SIZE + 1));
+
+ tss[Core].InterruptStackTable[i] = (uint64_t)NewStack + STACK_SIZE;
+ memset((void *)(tss[Core].InterruptStackTable[i] - STACK_SIZE), 0, STACK_SIZE);
+ debug("IST-%d: %#lx-%#lx", i, NewStack, (uintptr_t)NewStack + STACK_SIZE);
+ }
+
+ CPU::x64::ltr(GDT_TSS);
+
+ debug("GDT_KERNEL_CODE: %#lx", GDT_KERNEL_CODE);
+ debug("GDT_KERNEL_DATA: %#lx", GDT_KERNEL_DATA);
+ debug("GDT_USER_CODE: %#lx", GDT_USER_CODE);
+ debug("GDT_USER_DATA: %#lx", GDT_USER_DATA);
+ debug("GDT_TSS: %#lx", GDT_TSS);
+ debug("Global Descriptor Table initialized");
+ }
+
+ SafeFunction void SetKernelStack(void *Stack)
+ {
+ long CPUID = GetCurrentCPU()->ID;
+ if (Stack != nullptr)
+ tss[CPUID].StackPointer[0] = (uint64_t)Stack;
+ else
+ tss[CPUID].StackPointer[0] = (uint64_t)CPUStackPointer[CPUID] + STACK_SIZE;
+
+ /*
+ FIXME: There's a bug in kernel which if
+ we won't update "tss[CPUID].StackPointer[0]"
+ with the current stack pointer, the kernel
+ will crash.
+ */
+ asmv("mov %%rsp, %0"
+ : "=r"(tss[CPUID].StackPointer[0]));
+ }
+
+ void *GetKernelStack() { return (void *)tss[GetCurrentCPU()->ID].StackPointer[0]; }
+}
diff --git a/Kernel/Architecture/amd64/cpu/InterruptDescriptorTable.cpp b/Kernel/Architecture/amd64/cpu/InterruptDescriptorTable.cpp
new file mode 100644
index 00000000..3cf6f9c3
--- /dev/null
+++ b/Kernel/Architecture/amd64/cpu/InterruptDescriptorTable.cpp
@@ -0,0 +1,757 @@
+/*
+ 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 .
+*/
+
+#include "idt.hpp"
+
+#include
+#include
+#include
+#include
+
+#include "gdt.hpp"
+#include "../../../kernel.h"
+
+/* conversion from ‘uint64_t’ {aka ‘long unsigned int’} to ‘unsigned char:2’ may change value */
+#pragma GCC diagnostic ignored "-Wconversion"
+
+extern "C" void MainInterruptHandler(void *Data);
+extern "C" void ExceptionHandler(void *Data);
+
+namespace InterruptDescriptorTable
+{
+ static InterruptDescriptorTableEntry Entries[0x100];
+
+ InterruptDescriptorTableDescriptor idtd = {
+ .Length = sizeof(Entries) - 1,
+ .Entries = Entries,
+ };
+
+ void SetEntry(uint8_t Index,
+ void (*Base)(),
+ InterruptStackTableType InterruptStackTable,
+ InterruptGateType Gate,
+ InterruptRingType Ring,
+ bool Present,
+ uint16_t SegmentSelector)
+ {
+ Entries[Index].BaseLow = s_cst(uint16_t, ((uint64_t)Base & 0xFFFF));
+ Entries[Index].BaseHigh = s_cst(uint64_t, ((uint64_t)Base >> 16 /* & 0xFFFF */));
+ Entries[Index].SegmentSelector = SegmentSelector;
+ Entries[Index].Flags = Gate;
+ Entries[Index].Reserved1 = 0;
+ Entries[Index].Reserved2 = 0;
+ Entries[Index].Reserved3 = 0;
+ Entries[Index].InterruptStackTable = InterruptStackTable;
+ Entries[Index].Ring = Ring;
+ Entries[Index].Present = Present;
+ }
+
+ extern "C" __naked __used __no_stack_protector __aligned(16) void ExceptionHandlerStub()
+ {
+ asm("cld\n"
+ "cli\n"
+
+ "pushq %rax\n"
+ "pushq %rbx\n"
+ "pushq %rcx\n"
+ "pushq %rdx\n"
+ "pushq %rsi\n"
+ "pushq %rdi\n"
+ "pushq %rbp\n"
+ "pushq %r8\n"
+ "pushq %r9\n"
+ "pushq %r10\n"
+ "pushq %r11\n"
+ "pushq %r12\n"
+ "pushq %r13\n"
+ "pushq %r14\n"
+ "pushq %r15\n"
+
+ "movq %rsp, %rdi\n"
+ "call ExceptionHandler\n"
+
+ "popq %r15\n"
+ "popq %r14\n"
+ "popq %r13\n"
+ "popq %r12\n"
+ "popq %r11\n"
+ "popq %r10\n"
+ "popq %r9\n"
+ "popq %r8\n"
+ "popq %rbp\n"
+ "popq %rdi\n"
+ "popq %rsi\n"
+ "popq %rdx\n"
+ "popq %rcx\n"
+ "popq %rbx\n"
+ "popq %rax\n"
+
+ "addq $16, %rsp\n"
+
+ "iretq"); // pop CS RIP RFLAGS SS RSP
+ }
+
+ extern "C" __naked __used __no_stack_protector __aligned(16) void InterruptHandlerStub()
+ {
+ asm("cld\n"
+ "cli\n"
+
+ "pushq %rax\n"
+ "pushq %rbx\n"
+ "pushq %rcx\n"
+ "pushq %rdx\n"
+ "pushq %rsi\n"
+ "pushq %rdi\n"
+ "pushq %rbp\n"
+ "pushq %r8\n"
+ "pushq %r9\n"
+ "pushq %r10\n"
+ "pushq %r11\n"
+ "pushq %r12\n"
+ "pushq %r13\n"
+ "pushq %r14\n"
+ "pushq %r15\n"
+
+ "movq %rsp, %rdi\n"
+ "call MainInterruptHandler\n"
+
+ "popq %r15\n"
+ "popq %r14\n"
+ "popq %r13\n"
+ "popq %r12\n"
+ "popq %r11\n"
+ "popq %r10\n"
+ "popq %r9\n"
+ "popq %r8\n"
+ "popq %rbp\n"
+ "popq %rdi\n"
+ "popq %rsi\n"
+ "popq %rdx\n"
+ "popq %rcx\n"
+ "popq %rbx\n"
+ "popq %rax\n"
+
+ "addq $16, %rsp\n"
+
+ "sti\n"
+ "iretq"); // pop CS RIP RFLAGS SS RSP
+ }
+
+#pragma region Exceptions
+
+#define EXCEPTION_HANDLER(num) \
+ __naked __used __no_stack_protector __aligned(16) static void InterruptHandler_##num() \
+ { \
+ asm("pushq $0\npushq $" #num "\n" \
+ "jmp ExceptionHandlerStub"); \
+ }
+
+#define EXCEPTION_ERROR_HANDLER(num) \
+ __naked __used __no_stack_protector __aligned(16) static void InterruptHandler_##num() \
+ { \
+ asm("pushq $" #num "\n" \
+ "jmp ExceptionHandlerStub"); \
+ }
+
+#define INTERRUPT_HANDLER(num) \
+ __naked __used __no_stack_protector __aligned(16) void InterruptHandler_##num() \
+ { \
+ asm("pushq $0\npushq $" #num "\n" \
+ "jmp InterruptHandlerStub\n"); \
+ }
+
+ /* ISR */
+
+ EXCEPTION_HANDLER(0x0);
+ EXCEPTION_HANDLER(0x1);
+ EXCEPTION_HANDLER(0x2);
+ EXCEPTION_HANDLER(0x3);
+ EXCEPTION_HANDLER(0x4);
+ EXCEPTION_HANDLER(0x5);
+ EXCEPTION_HANDLER(0x6);
+ EXCEPTION_HANDLER(0x7);
+ EXCEPTION_ERROR_HANDLER(0x8);
+ EXCEPTION_HANDLER(0x9);
+ EXCEPTION_ERROR_HANDLER(0xa);
+ EXCEPTION_ERROR_HANDLER(0xb);
+ EXCEPTION_ERROR_HANDLER(0xc);
+ EXCEPTION_ERROR_HANDLER(0xd);
+ EXCEPTION_ERROR_HANDLER(0xe);
+ EXCEPTION_HANDLER(0xf);
+ EXCEPTION_ERROR_HANDLER(0x10);
+ EXCEPTION_HANDLER(0x11);
+ EXCEPTION_HANDLER(0x12);
+ EXCEPTION_HANDLER(0x13);
+ EXCEPTION_HANDLER(0x14);
+ EXCEPTION_HANDLER(0x15);
+ EXCEPTION_HANDLER(0x16);
+ EXCEPTION_HANDLER(0x17);
+ EXCEPTION_HANDLER(0x18);
+ EXCEPTION_HANDLER(0x19);
+ EXCEPTION_HANDLER(0x1a);
+ EXCEPTION_HANDLER(0x1b);
+ EXCEPTION_HANDLER(0x1c);
+ EXCEPTION_HANDLER(0x1d);
+ EXCEPTION_HANDLER(0x1e);
+ EXCEPTION_HANDLER(0x1f);
+
+ /* IRQ */
+
+ INTERRUPT_HANDLER(0x20)
+ INTERRUPT_HANDLER(0x21)
+ INTERRUPT_HANDLER(0x22)
+ INTERRUPT_HANDLER(0x23)
+ INTERRUPT_HANDLER(0x24)
+ INTERRUPT_HANDLER(0x25)
+ INTERRUPT_HANDLER(0x26)
+ INTERRUPT_HANDLER(0x27)
+ INTERRUPT_HANDLER(0x28)
+ INTERRUPT_HANDLER(0x29)
+ INTERRUPT_HANDLER(0x2a)
+ INTERRUPT_HANDLER(0x2b)
+ INTERRUPT_HANDLER(0x2c)
+ INTERRUPT_HANDLER(0x2d)
+ INTERRUPT_HANDLER(0x2e)
+ INTERRUPT_HANDLER(0x2f)
+
+ /* Reserved by OS */
+
+ INTERRUPT_HANDLER(0x30)
+ INTERRUPT_HANDLER(0x31)
+ INTERRUPT_HANDLER(0x32)
+ INTERRUPT_HANDLER(0x33)
+ INTERRUPT_HANDLER(0x34)
+ INTERRUPT_HANDLER(0x35)
+ INTERRUPT_HANDLER(0x36)
+ INTERRUPT_HANDLER(0x37)
+ INTERRUPT_HANDLER(0x38)
+ INTERRUPT_HANDLER(0x39)
+ INTERRUPT_HANDLER(0x3a)
+ INTERRUPT_HANDLER(0x3b)
+ INTERRUPT_HANDLER(0x3c)
+ INTERRUPT_HANDLER(0x3d)
+
+ /* Free */
+
+ INTERRUPT_HANDLER(0x3e)
+ INTERRUPT_HANDLER(0x3f)
+ INTERRUPT_HANDLER(0x40)
+ INTERRUPT_HANDLER(0x41)
+ INTERRUPT_HANDLER(0x42)
+ INTERRUPT_HANDLER(0x43)
+ INTERRUPT_HANDLER(0x44)
+ INTERRUPT_HANDLER(0x45)
+ INTERRUPT_HANDLER(0x46)
+ INTERRUPT_HANDLER(0x47)
+ INTERRUPT_HANDLER(0x48)
+ INTERRUPT_HANDLER(0x49)
+ INTERRUPT_HANDLER(0x4a)
+ INTERRUPT_HANDLER(0x4b)
+ INTERRUPT_HANDLER(0x4c)
+ INTERRUPT_HANDLER(0x4d)
+ INTERRUPT_HANDLER(0x4e)
+ INTERRUPT_HANDLER(0x4f)
+ INTERRUPT_HANDLER(0x50)
+ INTERRUPT_HANDLER(0x51)
+ INTERRUPT_HANDLER(0x52)
+ INTERRUPT_HANDLER(0x53)
+ INTERRUPT_HANDLER(0x54)
+ INTERRUPT_HANDLER(0x55)
+ INTERRUPT_HANDLER(0x56)
+ INTERRUPT_HANDLER(0x57)
+ INTERRUPT_HANDLER(0x58)
+ INTERRUPT_HANDLER(0x59)
+ INTERRUPT_HANDLER(0x5a)
+ INTERRUPT_HANDLER(0x5b)
+ INTERRUPT_HANDLER(0x5c)
+ INTERRUPT_HANDLER(0x5d)
+ INTERRUPT_HANDLER(0x5e)
+ INTERRUPT_HANDLER(0x5f)
+ INTERRUPT_HANDLER(0x60)
+ INTERRUPT_HANDLER(0x61)
+ INTERRUPT_HANDLER(0x62)
+ INTERRUPT_HANDLER(0x63)
+ INTERRUPT_HANDLER(0x64)
+ INTERRUPT_HANDLER(0x65)
+ INTERRUPT_HANDLER(0x66)
+ INTERRUPT_HANDLER(0x67)
+ INTERRUPT_HANDLER(0x68)
+ INTERRUPT_HANDLER(0x69)
+ INTERRUPT_HANDLER(0x6a)
+ INTERRUPT_HANDLER(0x6b)
+ INTERRUPT_HANDLER(0x6c)
+ INTERRUPT_HANDLER(0x6d)
+ INTERRUPT_HANDLER(0x6e)
+ INTERRUPT_HANDLER(0x6f)
+ INTERRUPT_HANDLER(0x70)
+ INTERRUPT_HANDLER(0x71)
+ INTERRUPT_HANDLER(0x72)
+ INTERRUPT_HANDLER(0x73)
+ INTERRUPT_HANDLER(0x74)
+ INTERRUPT_HANDLER(0x75)
+ INTERRUPT_HANDLER(0x76)
+ INTERRUPT_HANDLER(0x77)
+ INTERRUPT_HANDLER(0x78)
+ INTERRUPT_HANDLER(0x79)
+ INTERRUPT_HANDLER(0x7a)
+ INTERRUPT_HANDLER(0x7b)
+ INTERRUPT_HANDLER(0x7c)
+ INTERRUPT_HANDLER(0x7d)
+ INTERRUPT_HANDLER(0x7e)
+ INTERRUPT_HANDLER(0x7f)
+ INTERRUPT_HANDLER(0x80)
+ INTERRUPT_HANDLER(0x81)
+ INTERRUPT_HANDLER(0x82)
+ INTERRUPT_HANDLER(0x83)
+ INTERRUPT_HANDLER(0x84)
+ INTERRUPT_HANDLER(0x85)
+ INTERRUPT_HANDLER(0x86)
+ INTERRUPT_HANDLER(0x87)
+ INTERRUPT_HANDLER(0x88)
+ INTERRUPT_HANDLER(0x89)
+ INTERRUPT_HANDLER(0x8a)
+ INTERRUPT_HANDLER(0x8b)
+ INTERRUPT_HANDLER(0x8c)
+ INTERRUPT_HANDLER(0x8d)
+ INTERRUPT_HANDLER(0x8e)
+ INTERRUPT_HANDLER(0x8f)
+ INTERRUPT_HANDLER(0x90)
+ INTERRUPT_HANDLER(0x91)
+ INTERRUPT_HANDLER(0x92)
+ INTERRUPT_HANDLER(0x93)
+ INTERRUPT_HANDLER(0x94)
+ INTERRUPT_HANDLER(0x95)
+ INTERRUPT_HANDLER(0x96)
+ INTERRUPT_HANDLER(0x97)
+ INTERRUPT_HANDLER(0x98)
+ INTERRUPT_HANDLER(0x99)
+ INTERRUPT_HANDLER(0x9a)
+ INTERRUPT_HANDLER(0x9b)
+ INTERRUPT_HANDLER(0x9c)
+ INTERRUPT_HANDLER(0x9d)
+ INTERRUPT_HANDLER(0x9e)
+ INTERRUPT_HANDLER(0x9f)
+ INTERRUPT_HANDLER(0xa0)
+ INTERRUPT_HANDLER(0xa1)
+ INTERRUPT_HANDLER(0xa2)
+ INTERRUPT_HANDLER(0xa3)
+ INTERRUPT_HANDLER(0xa4)
+ INTERRUPT_HANDLER(0xa5)
+ INTERRUPT_HANDLER(0xa6)
+ INTERRUPT_HANDLER(0xa7)
+ INTERRUPT_HANDLER(0xa8)
+ INTERRUPT_HANDLER(0xa9)
+ INTERRUPT_HANDLER(0xaa)
+ INTERRUPT_HANDLER(0xab)
+ INTERRUPT_HANDLER(0xac)
+ INTERRUPT_HANDLER(0xad)
+ INTERRUPT_HANDLER(0xae)
+ INTERRUPT_HANDLER(0xaf)
+ INTERRUPT_HANDLER(0xb0)
+ INTERRUPT_HANDLER(0xb1)
+ INTERRUPT_HANDLER(0xb2)
+ INTERRUPT_HANDLER(0xb3)
+ INTERRUPT_HANDLER(0xb4)
+ INTERRUPT_HANDLER(0xb5)
+ INTERRUPT_HANDLER(0xb6)
+ INTERRUPT_HANDLER(0xb7)
+ INTERRUPT_HANDLER(0xb8)
+ INTERRUPT_HANDLER(0xb9)
+ INTERRUPT_HANDLER(0xba)
+ INTERRUPT_HANDLER(0xbb)
+ INTERRUPT_HANDLER(0xbc)
+ INTERRUPT_HANDLER(0xbd)
+ INTERRUPT_HANDLER(0xbe)
+ INTERRUPT_HANDLER(0xbf)
+ INTERRUPT_HANDLER(0xc0)
+ INTERRUPT_HANDLER(0xc1)
+ INTERRUPT_HANDLER(0xc2)
+ INTERRUPT_HANDLER(0xc3)
+ INTERRUPT_HANDLER(0xc4)
+ INTERRUPT_HANDLER(0xc5)
+ INTERRUPT_HANDLER(0xc6)
+ INTERRUPT_HANDLER(0xc7)
+ INTERRUPT_HANDLER(0xc8)
+ INTERRUPT_HANDLER(0xc9)
+ INTERRUPT_HANDLER(0xca)
+ INTERRUPT_HANDLER(0xcb)
+ INTERRUPT_HANDLER(0xcc)
+ INTERRUPT_HANDLER(0xcd)
+ INTERRUPT_HANDLER(0xce)
+ INTERRUPT_HANDLER(0xcf)
+ INTERRUPT_HANDLER(0xd0)
+ INTERRUPT_HANDLER(0xd1)
+ INTERRUPT_HANDLER(0xd2)
+ INTERRUPT_HANDLER(0xd3)
+ INTERRUPT_HANDLER(0xd4)
+ INTERRUPT_HANDLER(0xd5)
+ INTERRUPT_HANDLER(0xd6)
+ INTERRUPT_HANDLER(0xd7)
+ INTERRUPT_HANDLER(0xd8)
+ INTERRUPT_HANDLER(0xd9)
+ INTERRUPT_HANDLER(0xda)
+ INTERRUPT_HANDLER(0xdb)
+ INTERRUPT_HANDLER(0xdc)
+ INTERRUPT_HANDLER(0xdd)
+ INTERRUPT_HANDLER(0xde)
+ INTERRUPT_HANDLER(0xdf)
+ INTERRUPT_HANDLER(0xe0)
+ INTERRUPT_HANDLER(0xe1)
+ INTERRUPT_HANDLER(0xe2)
+ INTERRUPT_HANDLER(0xe3)
+ INTERRUPT_HANDLER(0xe4)
+ INTERRUPT_HANDLER(0xe5)
+ INTERRUPT_HANDLER(0xe6)
+ INTERRUPT_HANDLER(0xe7)
+ INTERRUPT_HANDLER(0xe8)
+ INTERRUPT_HANDLER(0xe9)
+ INTERRUPT_HANDLER(0xea)
+ INTERRUPT_HANDLER(0xeb)
+ INTERRUPT_HANDLER(0xec)
+ INTERRUPT_HANDLER(0xed)
+ INTERRUPT_HANDLER(0xee)
+ INTERRUPT_HANDLER(0xef)
+ INTERRUPT_HANDLER(0xf0)
+ INTERRUPT_HANDLER(0xf1)
+ INTERRUPT_HANDLER(0xf2)
+ INTERRUPT_HANDLER(0xf3)
+ INTERRUPT_HANDLER(0xf4)
+ INTERRUPT_HANDLER(0xf5)
+ INTERRUPT_HANDLER(0xf6)
+ INTERRUPT_HANDLER(0xf7)
+ INTERRUPT_HANDLER(0xf8)
+ INTERRUPT_HANDLER(0xf9)
+ INTERRUPT_HANDLER(0xfa)
+ INTERRUPT_HANDLER(0xfb)
+ INTERRUPT_HANDLER(0xfc)
+ INTERRUPT_HANDLER(0xfd)
+ INTERRUPT_HANDLER(0xfe)
+ INTERRUPT_HANDLER(0xff)
+
+#pragma endregion Exceptions
+
+ void Init(int Core)
+ {
+ if (Core == 0) /* Disable PIC using BSP */
+ {
+ // PIC
+ outb(0x20, 0x10 | 0x1);
+ outb(0x80, 0);
+ outb(0xA0, 0x10 | 0x10);
+ outb(0x80, 0);
+
+ outb(0x21, 0x20);
+ outb(0x80, 0);
+ outb(0xA1, 0x28);
+ outb(0x80, 0);
+
+ outb(0x21, 0x04);
+ outb(0x80, 0);
+ outb(0xA1, 0x02);
+ outb(0x80, 0);
+
+ outb(0x21, 1);
+ outb(0x80, 0);
+ outb(0xA1, 1);
+ outb(0x80, 0);
+
+ // Masking and disabling PIC
+ outb(0x21, 0xff);
+ outb(0x80, 0);
+ outb(0xA1, 0xff);
+ }
+
+ /* ISR */
+
+#ifdef DEBUG
+ // if (!DebuggerIsAttached)
+ if (true)
+ {
+#endif
+ SetEntry(0x0, InterruptHandler_0x0, IST1, TRAP_32BIT, RING0, true, GDT_KERNEL_CODE);
+ SetEntry(0x1, InterruptHandler_0x1, IST1, TRAP_32BIT, RING0, true, GDT_KERNEL_CODE);
+ SetEntry(0x2, InterruptHandler_0x2, IST2, TRAP_32BIT, RING0, true, GDT_KERNEL_CODE);
+ SetEntry(0x3, InterruptHandler_0x3, IST1, TRAP_32BIT, RING3, (!DebuggerIsAttached), GDT_KERNEL_CODE); /* Do not handle breakpoints if we are debugging the kernel. */
+ SetEntry(0x4, InterruptHandler_0x4, IST1, TRAP_32BIT, RING0, true, GDT_KERNEL_CODE);
+ SetEntry(0x5, InterruptHandler_0x5, IST1, TRAP_32BIT, RING0, true, GDT_KERNEL_CODE);
+ SetEntry(0x6, InterruptHandler_0x6, IST1, TRAP_32BIT, RING0, true, GDT_KERNEL_CODE);
+ SetEntry(0x7, InterruptHandler_0x7, IST1, TRAP_32BIT, RING0, true, GDT_KERNEL_CODE);
+ SetEntry(0x8, InterruptHandler_0x8, IST3, TRAP_32BIT, RING0, true, GDT_KERNEL_CODE);
+ SetEntry(0x9, InterruptHandler_0x9, IST1, TRAP_32BIT, RING0, true, GDT_KERNEL_CODE);
+ SetEntry(0xa, InterruptHandler_0xa, IST1, TRAP_32BIT, RING0, true, GDT_KERNEL_CODE);
+ SetEntry(0xb, InterruptHandler_0xb, IST1, TRAP_32BIT, RING0, true, GDT_KERNEL_CODE);
+ SetEntry(0xc, InterruptHandler_0xc, IST3, TRAP_32BIT, RING0, true, GDT_KERNEL_CODE);
+ SetEntry(0xd, InterruptHandler_0xd, IST3, TRAP_32BIT, RING0, true, GDT_KERNEL_CODE);
+ SetEntry(0xe, InterruptHandler_0xe, IST3, TRAP_32BIT, RING0, true, GDT_KERNEL_CODE);
+ SetEntry(0xf, InterruptHandler_0xf, IST1, TRAP_32BIT, RING0, true, GDT_KERNEL_CODE);
+ SetEntry(0x10, InterruptHandler_0x10, IST1, TRAP_32BIT, RING0, true, GDT_KERNEL_CODE);
+ SetEntry(0x11, InterruptHandler_0x11, IST1, TRAP_32BIT, RING0, true, GDT_KERNEL_CODE);
+ SetEntry(0x12, InterruptHandler_0x12, IST1, TRAP_32BIT, RING0, true, GDT_KERNEL_CODE);
+ SetEntry(0x13, InterruptHandler_0x13, IST1, TRAP_32BIT, RING0, true, GDT_KERNEL_CODE);
+ SetEntry(0x14, InterruptHandler_0x14, IST1, TRAP_32BIT, RING0, true, GDT_KERNEL_CODE);
+ SetEntry(0x15, InterruptHandler_0x15, IST1, TRAP_32BIT, RING0, true, GDT_KERNEL_CODE);
+ SetEntry(0x16, InterruptHandler_0x16, IST1, TRAP_32BIT, RING0, true, GDT_KERNEL_CODE);
+ SetEntry(0x17, InterruptHandler_0x17, IST1, TRAP_32BIT, RING0, true, GDT_KERNEL_CODE);
+ SetEntry(0x18, InterruptHandler_0x18, IST1, TRAP_32BIT, RING0, true, GDT_KERNEL_CODE);
+ SetEntry(0x19, InterruptHandler_0x19, IST1, TRAP_32BIT, RING0, true, GDT_KERNEL_CODE);
+ SetEntry(0x1a, InterruptHandler_0x1a, IST1, TRAP_32BIT, RING0, true, GDT_KERNEL_CODE);
+ SetEntry(0x1b, InterruptHandler_0x1b, IST1, TRAP_32BIT, RING0, true, GDT_KERNEL_CODE);
+ SetEntry(0x1c, InterruptHandler_0x1c, IST1, TRAP_32BIT, RING0, true, GDT_KERNEL_CODE);
+ SetEntry(0x1d, InterruptHandler_0x1d, IST1, TRAP_32BIT, RING0, true, GDT_KERNEL_CODE);
+ SetEntry(0x1e, InterruptHandler_0x1e, IST1, TRAP_32BIT, RING0, true, GDT_KERNEL_CODE);
+ SetEntry(0x1f, InterruptHandler_0x1f, IST1, TRAP_32BIT, RING0, true, GDT_KERNEL_CODE);
+#ifdef DEBUG
+ }
+ else
+ KPrint("\eFFA500The debugger is attached, not setting up the ISR.");
+#endif
+
+ /* IRQ */
+
+ SetEntry(0x20, InterruptHandler_0x20, IST0, TRAP_32BIT, RING0, true, GDT_KERNEL_CODE);
+ SetEntry(0x21, InterruptHandler_0x21, IST0, TRAP_32BIT, RING0, true, GDT_KERNEL_CODE);
+ SetEntry(0x22, InterruptHandler_0x22, IST0, TRAP_32BIT, RING0, true, GDT_KERNEL_CODE);
+ SetEntry(0x23, InterruptHandler_0x23, IST0, TRAP_32BIT, RING0, true, GDT_KERNEL_CODE);
+ SetEntry(0x24, InterruptHandler_0x24, IST0, TRAP_32BIT, RING0, true, GDT_KERNEL_CODE);
+ SetEntry(0x25, InterruptHandler_0x25, IST0, TRAP_32BIT, RING0, true, GDT_KERNEL_CODE);
+ SetEntry(0x26, InterruptHandler_0x26, IST0, TRAP_32BIT, RING0, true, GDT_KERNEL_CODE);
+ SetEntry(0x27, InterruptHandler_0x27, IST0, TRAP_32BIT, RING0, true, GDT_KERNEL_CODE);
+ SetEntry(0x28, InterruptHandler_0x28, IST0, TRAP_32BIT, RING0, true, GDT_KERNEL_CODE);
+ SetEntry(0x29, InterruptHandler_0x29, IST0, TRAP_32BIT, RING0, true, GDT_KERNEL_CODE);
+ SetEntry(0x2a, InterruptHandler_0x2a, IST0, TRAP_32BIT, RING0, true, GDT_KERNEL_CODE);
+ SetEntry(0x2b, InterruptHandler_0x2b, IST0, TRAP_32BIT, RING0, true, GDT_KERNEL_CODE);
+ SetEntry(0x2c, InterruptHandler_0x2c, IST0, TRAP_32BIT, RING0, true, GDT_KERNEL_CODE);
+ SetEntry(0x2d, InterruptHandler_0x2d, IST0, TRAP_32BIT, RING0, true, GDT_KERNEL_CODE);
+ SetEntry(0x2e, InterruptHandler_0x2e, IST0, TRAP_32BIT, RING0, true, GDT_KERNEL_CODE);
+ SetEntry(0x2f, InterruptHandler_0x2f, IST0, TRAP_32BIT, RING0, true, GDT_KERNEL_CODE);
+
+ /* Reserved by OS */
+
+ SetEntry(0x30, InterruptHandler_0x30, IST0, TRAP_32BIT, RING0, true, GDT_KERNEL_CODE);
+ SetEntry(0x31, InterruptHandler_0x31, IST0, TRAP_32BIT, RING0, true, GDT_KERNEL_CODE);
+ SetEntry(0x32, InterruptHandler_0x32, IST0, TRAP_32BIT, RING0, true, GDT_KERNEL_CODE);
+ SetEntry(0x33, InterruptHandler_0x33, IST0, TRAP_32BIT, RING0, true, GDT_KERNEL_CODE);
+ SetEntry(0x34, InterruptHandler_0x34, IST0, TRAP_32BIT, RING0, true, GDT_KERNEL_CODE);
+ SetEntry(0x35, InterruptHandler_0x35, IST0, TRAP_32BIT, RING0, true, GDT_KERNEL_CODE);
+ SetEntry(0x36, InterruptHandler_0x36, IST0, TRAP_32BIT, RING0, true, GDT_KERNEL_CODE);
+ SetEntry(0x37, InterruptHandler_0x37, IST0, TRAP_32BIT, RING0, true, GDT_KERNEL_CODE);
+ SetEntry(0x38, InterruptHandler_0x38, IST0, TRAP_32BIT, RING0, true, GDT_KERNEL_CODE);
+ SetEntry(0x39, InterruptHandler_0x39, IST0, TRAP_32BIT, RING0, true, GDT_KERNEL_CODE);
+ SetEntry(0x3a, InterruptHandler_0x3a, IST0, TRAP_32BIT, RING0, true, GDT_KERNEL_CODE);
+ SetEntry(0x3b, InterruptHandler_0x3b, IST0, TRAP_32BIT, RING0, true, GDT_KERNEL_CODE);
+ SetEntry(0x3c, InterruptHandler_0x3c, IST0, TRAP_32BIT, RING0, true, GDT_KERNEL_CODE);
+ SetEntry(0x3d, InterruptHandler_0x3d, IST0, TRAP_32BIT, RING0, true, GDT_KERNEL_CODE);
+
+ /* Free */
+
+ SetEntry(0x3e, InterruptHandler_0x3e, IST0, TRAP_32BIT, RING0, true, GDT_KERNEL_CODE);
+ SetEntry(0x3f, InterruptHandler_0x3f, IST0, TRAP_32BIT, RING0, true, GDT_KERNEL_CODE);
+ SetEntry(0x40, InterruptHandler_0x40, IST0, TRAP_32BIT, RING0, true, GDT_KERNEL_CODE);
+ SetEntry(0x41, InterruptHandler_0x41, IST0, TRAP_32BIT, RING0, true, GDT_KERNEL_CODE);
+ SetEntry(0x42, InterruptHandler_0x42, IST0, TRAP_32BIT, RING0, true, GDT_KERNEL_CODE);
+ SetEntry(0x43, InterruptHandler_0x43, IST0, TRAP_32BIT, RING0, true, GDT_KERNEL_CODE);
+ SetEntry(0x44, InterruptHandler_0x44, IST0, TRAP_32BIT, RING0, true, GDT_KERNEL_CODE);
+ SetEntry(0x45, InterruptHandler_0x45, IST0, TRAP_32BIT, RING0, true, GDT_KERNEL_CODE);
+ SetEntry(0x46, InterruptHandler_0x46, IST0, TRAP_32BIT, RING0, true, GDT_KERNEL_CODE);
+ SetEntry(0x47, InterruptHandler_0x47, IST0, TRAP_32BIT, RING0, true, GDT_KERNEL_CODE);
+ SetEntry(0x48, InterruptHandler_0x48, IST0, TRAP_32BIT, RING0, true, GDT_KERNEL_CODE);
+ SetEntry(0x49, InterruptHandler_0x49, IST0, TRAP_32BIT, RING0, true, GDT_KERNEL_CODE);
+ SetEntry(0x4a, InterruptHandler_0x4a, IST0, TRAP_32BIT, RING0, true, GDT_KERNEL_CODE);
+ SetEntry(0x4b, InterruptHandler_0x4b, IST0, TRAP_32BIT, RING0, true, GDT_KERNEL_CODE);
+ SetEntry(0x4c, InterruptHandler_0x4c, IST0, TRAP_32BIT, RING0, true, GDT_KERNEL_CODE);
+ SetEntry(0x4d, InterruptHandler_0x4d, IST0, TRAP_32BIT, RING0, true, GDT_KERNEL_CODE);
+ SetEntry(0x4e, InterruptHandler_0x4e, IST0, TRAP_32BIT, RING0, true, GDT_KERNEL_CODE);
+ SetEntry(0x4f, InterruptHandler_0x4f, IST0, TRAP_32BIT, RING0, true, GDT_KERNEL_CODE);
+ SetEntry(0x50, InterruptHandler_0x50, IST0, TRAP_32BIT, RING0, true, GDT_KERNEL_CODE);
+ SetEntry(0x51, InterruptHandler_0x51, IST0, TRAP_32BIT, RING0, true, GDT_KERNEL_CODE);
+ SetEntry(0x52, InterruptHandler_0x52, IST0, TRAP_32BIT, RING0, true, GDT_KERNEL_CODE);
+ SetEntry(0x53, InterruptHandler_0x53, IST0, TRAP_32BIT, RING0, true, GDT_KERNEL_CODE);
+ SetEntry(0x54, InterruptHandler_0x54, IST0, TRAP_32BIT, RING0, true, GDT_KERNEL_CODE);
+ SetEntry(0x55, InterruptHandler_0x55, IST0, TRAP_32BIT, RING0, true, GDT_KERNEL_CODE);
+ SetEntry(0x56, InterruptHandler_0x56, IST0, TRAP_32BIT, RING0, true, GDT_KERNEL_CODE);
+ SetEntry(0x57, InterruptHandler_0x57, IST0, TRAP_32BIT, RING0, true, GDT_KERNEL_CODE);
+ SetEntry(0x58, InterruptHandler_0x58, IST0, TRAP_32BIT, RING0, true, GDT_KERNEL_CODE);
+ SetEntry(0x59, InterruptHandler_0x59, IST0, TRAP_32BIT, RING0, true, GDT_KERNEL_CODE);
+ SetEntry(0x5a, InterruptHandler_0x5a, IST0, TRAP_32BIT, RING0, true, GDT_KERNEL_CODE);
+ SetEntry(0x5b, InterruptHandler_0x5b, IST0, TRAP_32BIT, RING0, true, GDT_KERNEL_CODE);
+ SetEntry(0x5c, InterruptHandler_0x5c, IST0, TRAP_32BIT, RING0, true, GDT_KERNEL_CODE);
+ SetEntry(0x5d, InterruptHandler_0x5d, IST0, TRAP_32BIT, RING0, true, GDT_KERNEL_CODE);
+ SetEntry(0x5e, InterruptHandler_0x5e, IST0, TRAP_32BIT, RING0, true, GDT_KERNEL_CODE);
+ SetEntry(0x5f, InterruptHandler_0x5f, IST0, TRAP_32BIT, RING0, true, GDT_KERNEL_CODE);
+ SetEntry(0x60, InterruptHandler_0x60, IST0, TRAP_32BIT, RING0, true, GDT_KERNEL_CODE);
+ SetEntry(0x61, InterruptHandler_0x61, IST0, TRAP_32BIT, RING0, true, GDT_KERNEL_CODE);
+ SetEntry(0x62, InterruptHandler_0x62, IST0, TRAP_32BIT, RING0, true, GDT_KERNEL_CODE);
+ SetEntry(0x63, InterruptHandler_0x63, IST0, TRAP_32BIT, RING0, true, GDT_KERNEL_CODE);
+ SetEntry(0x64, InterruptHandler_0x64, IST0, TRAP_32BIT, RING0, true, GDT_KERNEL_CODE);
+ SetEntry(0x65, InterruptHandler_0x65, IST0, TRAP_32BIT, RING0, true, GDT_KERNEL_CODE);
+ SetEntry(0x66, InterruptHandler_0x66, IST0, TRAP_32BIT, RING0, true, GDT_KERNEL_CODE);
+ SetEntry(0x67, InterruptHandler_0x67, IST0, TRAP_32BIT, RING0, true, GDT_KERNEL_CODE);
+ SetEntry(0x68, InterruptHandler_0x68, IST0, TRAP_32BIT, RING0, true, GDT_KERNEL_CODE);
+ SetEntry(0x69, InterruptHandler_0x69, IST0, TRAP_32BIT, RING0, true, GDT_KERNEL_CODE);
+ SetEntry(0x6a, InterruptHandler_0x6a, IST0, TRAP_32BIT, RING0, true, GDT_KERNEL_CODE);
+ SetEntry(0x6b, InterruptHandler_0x6b, IST0, TRAP_32BIT, RING0, true, GDT_KERNEL_CODE);
+ SetEntry(0x6c, InterruptHandler_0x6c, IST0, TRAP_32BIT, RING0, true, GDT_KERNEL_CODE);
+ SetEntry(0x6d, InterruptHandler_0x6d, IST0, TRAP_32BIT, RING0, true, GDT_KERNEL_CODE);
+ SetEntry(0x6e, InterruptHandler_0x6e, IST0, TRAP_32BIT, RING0, true, GDT_KERNEL_CODE);
+ SetEntry(0x6f, InterruptHandler_0x6f, IST0, TRAP_32BIT, RING0, true, GDT_KERNEL_CODE);
+ SetEntry(0x70, InterruptHandler_0x70, IST0, TRAP_32BIT, RING0, true, GDT_KERNEL_CODE);
+ SetEntry(0x71, InterruptHandler_0x71, IST0, TRAP_32BIT, RING0, true, GDT_KERNEL_CODE);
+ SetEntry(0x72, InterruptHandler_0x72, IST0, TRAP_32BIT, RING0, true, GDT_KERNEL_CODE);
+ SetEntry(0x73, InterruptHandler_0x73, IST0, TRAP_32BIT, RING0, true, GDT_KERNEL_CODE);
+ SetEntry(0x74, InterruptHandler_0x74, IST0, TRAP_32BIT, RING0, true, GDT_KERNEL_CODE);
+ SetEntry(0x75, InterruptHandler_0x75, IST0, TRAP_32BIT, RING0, true, GDT_KERNEL_CODE);
+ SetEntry(0x76, InterruptHandler_0x76, IST0, TRAP_32BIT, RING0, true, GDT_KERNEL_CODE);
+ SetEntry(0x77, InterruptHandler_0x77, IST0, TRAP_32BIT, RING0, true, GDT_KERNEL_CODE);
+ SetEntry(0x78, InterruptHandler_0x78, IST0, TRAP_32BIT, RING0, true, GDT_KERNEL_CODE);
+ SetEntry(0x79, InterruptHandler_0x79, IST0, TRAP_32BIT, RING0, true, GDT_KERNEL_CODE);
+ SetEntry(0x7a, InterruptHandler_0x7a, IST0, TRAP_32BIT, RING0, true, GDT_KERNEL_CODE);
+ SetEntry(0x7b, InterruptHandler_0x7b, IST0, TRAP_32BIT, RING0, true, GDT_KERNEL_CODE);
+ SetEntry(0x7c, InterruptHandler_0x7c, IST0, TRAP_32BIT, RING0, true, GDT_KERNEL_CODE);
+ SetEntry(0x7d, InterruptHandler_0x7d, IST0, TRAP_32BIT, RING0, true, GDT_KERNEL_CODE);
+ SetEntry(0x7e, InterruptHandler_0x7e, IST0, TRAP_32BIT, RING0, true, GDT_KERNEL_CODE);
+ SetEntry(0x7f, InterruptHandler_0x7f, IST0, TRAP_32BIT, RING0, true, GDT_KERNEL_CODE);
+ SetEntry(0x80, InterruptHandler_0x80, IST0, TRAP_32BIT, RING0, true, GDT_KERNEL_CODE);
+ SetEntry(0x81, InterruptHandler_0x81, IST0, TRAP_32BIT, RING0, true, GDT_KERNEL_CODE);
+ SetEntry(0x82, InterruptHandler_0x82, IST0, TRAP_32BIT, RING0, true, GDT_KERNEL_CODE);
+ SetEntry(0x83, InterruptHandler_0x83, IST0, TRAP_32BIT, RING0, true, GDT_KERNEL_CODE);
+ SetEntry(0x84, InterruptHandler_0x84, IST0, TRAP_32BIT, RING0, true, GDT_KERNEL_CODE);
+ SetEntry(0x85, InterruptHandler_0x85, IST0, TRAP_32BIT, RING0, true, GDT_KERNEL_CODE);
+ SetEntry(0x86, InterruptHandler_0x86, IST0, TRAP_32BIT, RING0, true, GDT_KERNEL_CODE);
+ SetEntry(0x87, InterruptHandler_0x87, IST0, TRAP_32BIT, RING0, true, GDT_KERNEL_CODE);
+ SetEntry(0x88, InterruptHandler_0x88, IST0, TRAP_32BIT, RING0, true, GDT_KERNEL_CODE);
+ SetEntry(0x89, InterruptHandler_0x89, IST0, TRAP_32BIT, RING0, true, GDT_KERNEL_CODE);
+ SetEntry(0x8a, InterruptHandler_0x8a, IST0, TRAP_32BIT, RING0, true, GDT_KERNEL_CODE);
+ SetEntry(0x8b, InterruptHandler_0x8b, IST0, TRAP_32BIT, RING0, true, GDT_KERNEL_CODE);
+ SetEntry(0x8c, InterruptHandler_0x8c, IST0, TRAP_32BIT, RING0, true, GDT_KERNEL_CODE);
+ SetEntry(0x8d, InterruptHandler_0x8d, IST0, TRAP_32BIT, RING0, true, GDT_KERNEL_CODE);
+ SetEntry(0x8e, InterruptHandler_0x8e, IST0, TRAP_32BIT, RING0, true, GDT_KERNEL_CODE);
+ SetEntry(0x8f, InterruptHandler_0x8f, IST0, TRAP_32BIT, RING0, true, GDT_KERNEL_CODE);
+ SetEntry(0x90, InterruptHandler_0x90, IST0, TRAP_32BIT, RING0, true, GDT_KERNEL_CODE);
+ SetEntry(0x91, InterruptHandler_0x91, IST0, TRAP_32BIT, RING0, true, GDT_KERNEL_CODE);
+ SetEntry(0x92, InterruptHandler_0x92, IST0, TRAP_32BIT, RING0, true, GDT_KERNEL_CODE);
+ SetEntry(0x93, InterruptHandler_0x93, IST0, TRAP_32BIT, RING0, true, GDT_KERNEL_CODE);
+ SetEntry(0x94, InterruptHandler_0x94, IST0, TRAP_32BIT, RING0, true, GDT_KERNEL_CODE);
+ SetEntry(0x95, InterruptHandler_0x95, IST0, TRAP_32BIT, RING0, true, GDT_KERNEL_CODE);
+ SetEntry(0x96, InterruptHandler_0x96, IST0, TRAP_32BIT, RING0, true, GDT_KERNEL_CODE);
+ SetEntry(0x97, InterruptHandler_0x97, IST0, TRAP_32BIT, RING0, true, GDT_KERNEL_CODE);
+ SetEntry(0x98, InterruptHandler_0x98, IST0, TRAP_32BIT, RING0, true, GDT_KERNEL_CODE);
+ SetEntry(0x99, InterruptHandler_0x99, IST0, TRAP_32BIT, RING0, true, GDT_KERNEL_CODE);
+ SetEntry(0x9a, InterruptHandler_0x9a, IST0, TRAP_32BIT, RING0, true, GDT_KERNEL_CODE);
+ SetEntry(0x9b, InterruptHandler_0x9b, IST0, TRAP_32BIT, RING0, true, GDT_KERNEL_CODE);
+ SetEntry(0x9c, InterruptHandler_0x9c, IST0, TRAP_32BIT, RING0, true, GDT_KERNEL_CODE);
+ SetEntry(0x9d, InterruptHandler_0x9d, IST0, TRAP_32BIT, RING0, true, GDT_KERNEL_CODE);
+ SetEntry(0x9e, InterruptHandler_0x9e, IST0, TRAP_32BIT, RING0, true, GDT_KERNEL_CODE);
+ SetEntry(0x9f, InterruptHandler_0x9f, IST0, TRAP_32BIT, RING0, true, GDT_KERNEL_CODE);
+ SetEntry(0xa0, InterruptHandler_0xa0, IST0, TRAP_32BIT, RING0, true, GDT_KERNEL_CODE);
+ SetEntry(0xa1, InterruptHandler_0xa1, IST0, TRAP_32BIT, RING0, true, GDT_KERNEL_CODE);
+ SetEntry(0xa2, InterruptHandler_0xa2, IST0, TRAP_32BIT, RING0, true, GDT_KERNEL_CODE);
+ SetEntry(0xa3, InterruptHandler_0xa3, IST0, TRAP_32BIT, RING0, true, GDT_KERNEL_CODE);
+ SetEntry(0xa4, InterruptHandler_0xa4, IST0, TRAP_32BIT, RING0, true, GDT_KERNEL_CODE);
+ SetEntry(0xa5, InterruptHandler_0xa5, IST0, TRAP_32BIT, RING0, true, GDT_KERNEL_CODE);
+ SetEntry(0xa6, InterruptHandler_0xa6, IST0, TRAP_32BIT, RING0, true, GDT_KERNEL_CODE);
+ SetEntry(0xa7, InterruptHandler_0xa7, IST0, TRAP_32BIT, RING0, true, GDT_KERNEL_CODE);
+ SetEntry(0xa8, InterruptHandler_0xa8, IST0, TRAP_32BIT, RING0, true, GDT_KERNEL_CODE);
+ SetEntry(0xa9, InterruptHandler_0xa9, IST0, TRAP_32BIT, RING0, true, GDT_KERNEL_CODE);
+ SetEntry(0xaa, InterruptHandler_0xaa, IST0, TRAP_32BIT, RING0, true, GDT_KERNEL_CODE);
+ SetEntry(0xab, InterruptHandler_0xab, IST0, TRAP_32BIT, RING0, true, GDT_KERNEL_CODE);
+ SetEntry(0xac, InterruptHandler_0xac, IST0, TRAP_32BIT, RING0, true, GDT_KERNEL_CODE);
+ SetEntry(0xad, InterruptHandler_0xad, IST0, TRAP_32BIT, RING0, true, GDT_KERNEL_CODE);
+ SetEntry(0xae, InterruptHandler_0xae, IST0, TRAP_32BIT, RING0, true, GDT_KERNEL_CODE);
+ SetEntry(0xaf, InterruptHandler_0xaf, IST0, TRAP_32BIT, RING0, true, GDT_KERNEL_CODE);
+ SetEntry(0xb0, InterruptHandler_0xb0, IST0, TRAP_32BIT, RING0, true, GDT_KERNEL_CODE);
+ SetEntry(0xb1, InterruptHandler_0xb1, IST0, TRAP_32BIT, RING0, true, GDT_KERNEL_CODE);
+ SetEntry(0xb2, InterruptHandler_0xb2, IST0, TRAP_32BIT, RING0, true, GDT_KERNEL_CODE);
+ SetEntry(0xb3, InterruptHandler_0xb3, IST0, TRAP_32BIT, RING0, true, GDT_KERNEL_CODE);
+ SetEntry(0xb4, InterruptHandler_0xb4, IST0, TRAP_32BIT, RING0, true, GDT_KERNEL_CODE);
+ SetEntry(0xb5, InterruptHandler_0xb5, IST0, TRAP_32BIT, RING0, true, GDT_KERNEL_CODE);
+ SetEntry(0xb6, InterruptHandler_0xb6, IST0, TRAP_32BIT, RING0, true, GDT_KERNEL_CODE);
+ SetEntry(0xb7, InterruptHandler_0xb7, IST0, TRAP_32BIT, RING0, true, GDT_KERNEL_CODE);
+ SetEntry(0xb8, InterruptHandler_0xb8, IST0, TRAP_32BIT, RING0, true, GDT_KERNEL_CODE);
+ SetEntry(0xb9, InterruptHandler_0xb9, IST0, TRAP_32BIT, RING0, true, GDT_KERNEL_CODE);
+ SetEntry(0xba, InterruptHandler_0xba, IST0, TRAP_32BIT, RING0, true, GDT_KERNEL_CODE);
+ SetEntry(0xbb, InterruptHandler_0xbb, IST0, TRAP_32BIT, RING0, true, GDT_KERNEL_CODE);
+ SetEntry(0xbc, InterruptHandler_0xbc, IST0, TRAP_32BIT, RING0, true, GDT_KERNEL_CODE);
+ SetEntry(0xbd, InterruptHandler_0xbd, IST0, TRAP_32BIT, RING0, true, GDT_KERNEL_CODE);
+ SetEntry(0xbe, InterruptHandler_0xbe, IST0, TRAP_32BIT, RING0, true, GDT_KERNEL_CODE);
+ SetEntry(0xbf, InterruptHandler_0xbf, IST0, TRAP_32BIT, RING0, true, GDT_KERNEL_CODE);
+ SetEntry(0xc0, InterruptHandler_0xc0, IST0, TRAP_32BIT, RING0, true, GDT_KERNEL_CODE);
+ SetEntry(0xc1, InterruptHandler_0xc1, IST0, TRAP_32BIT, RING0, true, GDT_KERNEL_CODE);
+ SetEntry(0xc2, InterruptHandler_0xc2, IST0, TRAP_32BIT, RING0, true, GDT_KERNEL_CODE);
+ SetEntry(0xc3, InterruptHandler_0xc3, IST0, TRAP_32BIT, RING0, true, GDT_KERNEL_CODE);
+ SetEntry(0xc4, InterruptHandler_0xc4, IST0, TRAP_32BIT, RING0, true, GDT_KERNEL_CODE);
+ SetEntry(0xc5, InterruptHandler_0xc5, IST0, TRAP_32BIT, RING0, true, GDT_KERNEL_CODE);
+ SetEntry(0xc6, InterruptHandler_0xc6, IST0, TRAP_32BIT, RING0, true, GDT_KERNEL_CODE);
+ SetEntry(0xc7, InterruptHandler_0xc7, IST0, TRAP_32BIT, RING0, true, GDT_KERNEL_CODE);
+ SetEntry(0xc8, InterruptHandler_0xc8, IST0, TRAP_32BIT, RING0, true, GDT_KERNEL_CODE);
+ SetEntry(0xc9, InterruptHandler_0xc9, IST0, TRAP_32BIT, RING0, true, GDT_KERNEL_CODE);
+ SetEntry(0xca, InterruptHandler_0xca, IST0, TRAP_32BIT, RING0, true, GDT_KERNEL_CODE);
+ SetEntry(0xcb, InterruptHandler_0xcb, IST0, TRAP_32BIT, RING0, true, GDT_KERNEL_CODE);
+ SetEntry(0xcc, InterruptHandler_0xcc, IST0, TRAP_32BIT, RING0, true, GDT_KERNEL_CODE);
+ SetEntry(0xcd, InterruptHandler_0xcd, IST0, TRAP_32BIT, RING0, true, GDT_KERNEL_CODE);
+ SetEntry(0xce, InterruptHandler_0xce, IST0, TRAP_32BIT, RING0, true, GDT_KERNEL_CODE);
+ SetEntry(0xcf, InterruptHandler_0xcf, IST0, TRAP_32BIT, RING0, true, GDT_KERNEL_CODE);
+ SetEntry(0xd0, InterruptHandler_0xd0, IST0, TRAP_32BIT, RING0, true, GDT_KERNEL_CODE);
+ SetEntry(0xd1, InterruptHandler_0xd1, IST0, TRAP_32BIT, RING0, true, GDT_KERNEL_CODE);
+ SetEntry(0xd2, InterruptHandler_0xd2, IST0, TRAP_32BIT, RING0, true, GDT_KERNEL_CODE);
+ SetEntry(0xd3, InterruptHandler_0xd3, IST0, TRAP_32BIT, RING0, true, GDT_KERNEL_CODE);
+ SetEntry(0xd4, InterruptHandler_0xd4, IST0, TRAP_32BIT, RING0, true, GDT_KERNEL_CODE);
+ SetEntry(0xd5, InterruptHandler_0xd5, IST0, TRAP_32BIT, RING0, true, GDT_KERNEL_CODE);
+ SetEntry(0xd6, InterruptHandler_0xd6, IST0, TRAP_32BIT, RING0, true, GDT_KERNEL_CODE);
+ SetEntry(0xd7, InterruptHandler_0xd7, IST0, TRAP_32BIT, RING0, true, GDT_KERNEL_CODE);
+ SetEntry(0xd8, InterruptHandler_0xd8, IST0, TRAP_32BIT, RING0, true, GDT_KERNEL_CODE);
+ SetEntry(0xd9, InterruptHandler_0xd9, IST0, TRAP_32BIT, RING0, true, GDT_KERNEL_CODE);
+ SetEntry(0xda, InterruptHandler_0xda, IST0, TRAP_32BIT, RING0, true, GDT_KERNEL_CODE);
+ SetEntry(0xdb, InterruptHandler_0xdb, IST0, TRAP_32BIT, RING0, true, GDT_KERNEL_CODE);
+ SetEntry(0xdc, InterruptHandler_0xdc, IST0, TRAP_32BIT, RING0, true, GDT_KERNEL_CODE);
+ SetEntry(0xdd, InterruptHandler_0xdd, IST0, TRAP_32BIT, RING0, true, GDT_KERNEL_CODE);
+ SetEntry(0xde, InterruptHandler_0xde, IST0, TRAP_32BIT, RING0, true, GDT_KERNEL_CODE);
+ SetEntry(0xdf, InterruptHandler_0xdf, IST0, TRAP_32BIT, RING0, true, GDT_KERNEL_CODE);
+ SetEntry(0xe0, InterruptHandler_0xe0, IST0, TRAP_32BIT, RING0, true, GDT_KERNEL_CODE);
+ SetEntry(0xe1, InterruptHandler_0xe1, IST0, TRAP_32BIT, RING0, true, GDT_KERNEL_CODE);
+ SetEntry(0xe2, InterruptHandler_0xe2, IST0, TRAP_32BIT, RING0, true, GDT_KERNEL_CODE);
+ SetEntry(0xe3, InterruptHandler_0xe3, IST0, TRAP_32BIT, RING0, true, GDT_KERNEL_CODE);
+ SetEntry(0xe4, InterruptHandler_0xe4, IST0, TRAP_32BIT, RING0, true, GDT_KERNEL_CODE);
+ SetEntry(0xe5, InterruptHandler_0xe5, IST0, TRAP_32BIT, RING0, true, GDT_KERNEL_CODE);
+ SetEntry(0xe6, InterruptHandler_0xe6, IST0, TRAP_32BIT, RING0, true, GDT_KERNEL_CODE);
+ SetEntry(0xe7, InterruptHandler_0xe7, IST0, TRAP_32BIT, RING0, true, GDT_KERNEL_CODE);
+ SetEntry(0xe8, InterruptHandler_0xe8, IST0, TRAP_32BIT, RING0, true, GDT_KERNEL_CODE);
+ SetEntry(0xe9, InterruptHandler_0xe9, IST0, TRAP_32BIT, RING0, true, GDT_KERNEL_CODE);
+ SetEntry(0xea, InterruptHandler_0xea, IST0, TRAP_32BIT, RING0, true, GDT_KERNEL_CODE);
+ SetEntry(0xeb, InterruptHandler_0xeb, IST0, TRAP_32BIT, RING0, true, GDT_KERNEL_CODE);
+ SetEntry(0xec, InterruptHandler_0xec, IST0, TRAP_32BIT, RING0, true, GDT_KERNEL_CODE);
+ SetEntry(0xed, InterruptHandler_0xed, IST0, TRAP_32BIT, RING0, true, GDT_KERNEL_CODE);
+ SetEntry(0xee, InterruptHandler_0xee, IST0, TRAP_32BIT, RING0, true, GDT_KERNEL_CODE);
+ SetEntry(0xef, InterruptHandler_0xef, IST0, TRAP_32BIT, RING0, true, GDT_KERNEL_CODE);
+ SetEntry(0xf0, InterruptHandler_0xf0, IST0, TRAP_32BIT, RING0, true, GDT_KERNEL_CODE);
+ SetEntry(0xf1, InterruptHandler_0xf1, IST0, TRAP_32BIT, RING0, true, GDT_KERNEL_CODE);
+ SetEntry(0xf2, InterruptHandler_0xf2, IST0, TRAP_32BIT, RING0, true, GDT_KERNEL_CODE);
+ SetEntry(0xf3, InterruptHandler_0xf3, IST0, TRAP_32BIT, RING0, true, GDT_KERNEL_CODE);
+ SetEntry(0xf4, InterruptHandler_0xf4, IST0, TRAP_32BIT, RING0, true, GDT_KERNEL_CODE);
+ SetEntry(0xf5, InterruptHandler_0xf5, IST0, TRAP_32BIT, RING0, true, GDT_KERNEL_CODE);
+ SetEntry(0xf6, InterruptHandler_0xf6, IST0, TRAP_32BIT, RING0, true, GDT_KERNEL_CODE);
+ SetEntry(0xf7, InterruptHandler_0xf7, IST0, TRAP_32BIT, RING0, true, GDT_KERNEL_CODE);
+ SetEntry(0xf8, InterruptHandler_0xf8, IST0, TRAP_32BIT, RING0, true, GDT_KERNEL_CODE);
+ SetEntry(0xf9, InterruptHandler_0xf9, IST0, TRAP_32BIT, RING0, true, GDT_KERNEL_CODE);
+ SetEntry(0xfa, InterruptHandler_0xfa, IST0, TRAP_32BIT, RING0, true, GDT_KERNEL_CODE);
+ SetEntry(0xfb, InterruptHandler_0xfb, IST0, TRAP_32BIT, RING0, true, GDT_KERNEL_CODE);
+ SetEntry(0xfc, InterruptHandler_0xfc, IST0, TRAP_32BIT, RING0, true, GDT_KERNEL_CODE);
+ SetEntry(0xfd, InterruptHandler_0xfd, IST0, TRAP_32BIT, RING0, true, GDT_KERNEL_CODE);
+ SetEntry(0xfe, InterruptHandler_0xfe, IST0, TRAP_32BIT, RING0, true, GDT_KERNEL_CODE);
+ SetEntry(0xff, InterruptHandler_0xff, IST0, TRAP_32BIT, RING0, true, GDT_KERNEL_CODE);
+ CPU::x64::lidt(&idtd);
+ }
+}
diff --git a/Kernel/Architecture/amd64/cpu/SMPTrampoline.asm b/Kernel/Architecture/amd64/cpu/SMPTrampoline.asm
new file mode 100644
index 00000000..ca690e67
--- /dev/null
+++ b/Kernel/Architecture/amd64/cpu/SMPTrampoline.asm
@@ -0,0 +1,136 @@
+; 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/Kernel/Architecture/amd64/cpu/SymmetricMultiprocessing.cpp b/Kernel/Architecture/amd64/cpu/SymmetricMultiprocessing.cpp
new file mode 100644
index 00000000..fce30d26
--- /dev/null
+++ b/Kernel/Architecture/amd64/cpu/SymmetricMultiprocessing.cpp
@@ -0,0 +1,141 @@
+/*
+ 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 .
+*/
+
+#include
+
+#include
+#include
+#include
+#include
+#include
+
+#include "../../../kernel.h"
+#include "../acpi.hpp"
+#include "apic.hpp"
+
+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
+};
+
+std::atomic_bool CPUEnabled = false;
+
+#pragma GCC diagnostic ignored "-Wmissing-field-initializers"
+static __aligned(PAGE_SIZE) CPUData CPUs[MAX_CPU] = {0};
+
+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. */
+
+ 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];
+ }
+
+ 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::Enable);
+ KPrint("\e058C19CPU \e8888FF%d \e058C19is online", CoreID);
+ CPUEnabled.store(true, std::memory_order_release);
+ CPU::Halt(true);
+}
+
+namespace SMP
+{
+ int CPUCores = 0;
+
+ void Initialize(void *madt)
+ {
+ int Cores = ((ACPI::MADT *)madt)->CPUCores + 1;
+
+ 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;
+
+ CPUCores = 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);
+
+ 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;
+
+ 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;
+
+ ((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);
+
+ ((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);
+
+ 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);
+ }
+
+ 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/Kernel/Architecture/amd64/cpu/apic.hpp b/Kernel/Architecture/amd64/cpu/apic.hpp
new file mode 100644
index 00000000..e93c33a0
--- /dev/null
+++ b/Kernel/Architecture/amd64/cpu/apic.hpp
@@ -0,0 +1,354 @@
+/*
+ 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 .
+*/
+
+#ifndef __FENNIX_KERNEL_APIC_H__
+#define __FENNIX_KERNEL_APIC_H__
+
+#include
+
+#include
+#include
+
+namespace APIC
+{
+ enum APICRegisters
+ {
+ // source from: https://github.com/pdoane/osdev/blob/master/intr/local_apic.c
+ APIC_ID = 0x20, // Local APIC ID
+ APIC_VER = 0x30, // Local APIC Version
+ APIC_TPR = 0x80, // Task Priority
+ APIC_APR = 0x90, // Arbitration Priority
+ APIC_PPR = 0xA0, // Processor Priority
+ APIC_EOI = 0xB0, // EOI
+ APIC_RRD = 0xC0, // Remote Read
+ APIC_LDR = 0xD0, // Logical Destination
+ APIC_DFR = 0xE0, // Destination Format
+ APIC_SVR = 0xF0, // Spurious Interrupt Vector
+ APIC_ISR = 0x100, // In-Service (8 registers)
+ APIC_TMR = 0x180, // Trigger Mode (8 registers)
+ APIC_IRR = 0x200, // Interrupt Request (8 registers)
+ APIC_ESR = 0x280, // Error Status
+ APIC_ICRLO = 0x300, // Interrupt Command
+ APIC_ICRHI = 0x310, // Interrupt Command [63:32]
+ APIC_TIMER = 0x320, // LVT Timer
+ APIC_THERMAL = 0x330, // LVT Thermal Sensor
+ APIC_PERF = 0x340, // LVT Performance Counter
+ APIC_LINT0 = 0x350, // LVT LINT0
+ APIC_LINT1 = 0x360, // LVT LINT1
+ APIC_ERROR = 0x370, // LVT Error
+ APIC_TICR = 0x380, // Initial Count (for Timer)
+ APIC_TCCR = 0x390, // Current Count (for Timer)
+ APIC_TDCR = 0x3E0, // Divide Configuration (for Timer)
+ };
+
+ enum IOAPICRegisters
+ {
+ GetIOAPICVersion = 0x1
+ };
+
+ enum IOAPICFlags
+ {
+ ActiveHighLow = 2,
+ EdgeLevel = 8
+ };
+
+ enum APICDeliveryMode
+ {
+ Fixed = 0b000,
+ LowestPriority = 0b001, /* Reserved */
+ SMI = 0b010,
+ APIC_DELIVERY_MODE_RESERVED0 = 0b011, /* Reserved */
+ NMI = 0b100,
+ INIT = 0b101,
+ Startup = 0b110,
+ ExtINT = 0b111 /* Reserved */
+ };
+
+ enum APICDestinationMode
+ {
+ Physical = 0b0,
+ Logical = 0b1
+ };
+
+ enum APICDeliveryStatus
+ {
+ Idle = 0b0,
+ SendPending = 0b1
+ };
+
+ enum APICLevel
+ {
+ DeAssert = 0b0,
+ Assert = 0b1
+ };
+
+ enum APICTriggerMode
+ {
+ Edge = 0b0,
+ Level = 0b1
+ };
+
+ enum APICDestinationShorthand
+ {
+ NoShorthand = 0b00,
+ Self = 0b01,
+ AllIncludingSelf = 0b10,
+ AllExcludingSelf = 0b11
+ };
+
+ enum LVTTimerDivide
+ {
+ DivideBy2 = 0b000,
+ DivideBy4 = 0b001,
+ DivideBy8 = 0b010,
+ DivideBy16 = 0b011,
+ DivideBy32 = 0b100,
+ DivideBy64 = 0b101,
+ DivideBy128 = 0b110,
+ DivideBy1 = 0b111
+ };
+
+ enum LVTTimerMask
+ {
+ Unmasked = 0b0,
+ Masked = 0b1
+ };
+
+ enum LVTTimerMode
+ {
+ OneShot = 0b00,
+ Periodic = 0b01,
+ TSCDeadline = 0b10
+ };
+
+ typedef union
+ {
+ struct
+ {
+ /** @brief Interrupt Vector */
+ uint64_t Vector : 8;
+ /** @brief Reserved */
+ uint64_t Reserved0 : 4;
+ /**
+ * @brief Delivery Status
+ *
+ * 0: Idle
+ * 1: Send Pending
+ */
+ uint64_t DeliveryStatus : 1;
+ /** @brief Reserved */
+ uint64_t Reserved1 : 3;
+ /**
+ * @brief Mask
+ *
+ * 0: Not masked
+ * 1: Masked
+ */
+ uint64_t Mask : 1;
+ /** @brief Timer Mode
+ *
+ * 0: One-shot
+ * 1: Periodic
+ * 2: TSC-Deadline
+ */
+ uint64_t TimerMode : 1;
+ /** @brief Reserved */
+ uint64_t Reserved2 : 14;
+ };
+ uint64_t raw;
+ } __packed LVTTimer;
+
+ typedef union
+ {
+ struct
+ {
+ /** @brief Spurious Vector */
+ uint64_t Vector : 8;
+ /** @brief Enable or disable APIC software */
+ uint64_t Software : 1;
+ /** @brief Focus Processor Checking */
+ uint64_t FocusProcessorChecking : 1;
+ /** @brief Reserved */
+ uint64_t Reserved : 2;
+ /** @brief Disable EOI Broadcast */
+ uint64_t DisableEOIBroadcast : 1;
+ /** @brief Reserved */
+ uint64_t Reserved1 : 19;
+ };
+ uint64_t raw;
+ } __packed Spurious;
+
+ typedef union
+ {
+ struct
+ {
+ /** @brief Interrupt Vector */
+ uint64_t Vector : 8;
+ /** @brief Delivery Mode */
+ uint64_t DeliveryMode : 3;
+ /** @brief Destination Mode
+ *
+ * 0: Physical
+ * 1: Logical
+ */
+ uint64_t DestinationMode : 1;
+ /** @brief Delivery Status
+ *
+ * @note Reserved when in x2APIC mode
+ */
+ uint64_t DeliveryStatus : 1;
+ /** @brief Reserved */
+ uint64_t Reserved0 : 1;
+ /** @brief Level
+ *
+ * 0: Deassert
+ * 1: Assert
+ */
+ uint64_t Level : 1;
+ /** @brief Trigger Mode
+ *
+ * 0: Edge
+ * 1: Level
+ */
+ uint64_t TriggerMode : 1;
+ /** @brief Reserved */
+ uint64_t Reserved1 : 2;
+ /** @brief Destination Shorthand
+ *
+ * 0: No shorthand
+ * 1: Self
+ * 2: All including self
+ * 3: All excluding self
+ */
+ uint64_t DestinationShorthand : 2;
+ /** @brief Reserved */
+ uint64_t Reserved2 : 12;
+ };
+ uint64_t raw;
+ } __packed InterruptCommandRegisterLow;
+
+ typedef union
+ {
+ struct
+ {
+ /** @brief Reserved */
+ uint64_t Reserved0 : 24;
+ /** @brief Destination */
+ uint64_t Destination : 8;
+ };
+ uint64_t raw;
+ } __packed InterruptCommandRegisterHigh;
+
+ typedef union
+ {
+ struct
+ {
+ /** @brief Interrupt Vector */
+ uint64_t Vector : 8;
+ /** @brief Delivery Mode */
+ uint64_t DeliveryMode : 3;
+ /** @brief Destination Mode
+ *
+ * 0: Physical
+ * 1: Logical
+ */
+ uint64_t DestinationMode : 1;
+ /** @brief Delivery Status */
+ uint64_t DeliveryStatus : 1;
+ /** @brief Interrupt Input Pin Polarity
+ *
+ * 0: Active High
+ * 1: Active Low
+ */
+ uint64_t Polarity : 1;
+ /** @brief Remote IRR */
+ uint64_t RemoteIRR : 1;
+ /** @brief Trigger Mode
+ *
+ * 0: Edge
+ * 1: Level
+ */
+ uint64_t TriggerMode : 1;
+ /** @brief Mask */
+ uint64_t Mask : 1;
+ /** @brief Reserved */
+ uint64_t Reserved0 : 15;
+ /** @brief Reserved */
+ uint64_t Reserved1 : 24;
+ /** @brief Destination */
+ uint64_t DestinationID : 8;
+ };
+ struct
+ {
+ uint64_t Low;
+ uint64_t High;
+ } split;
+ uint64_t raw;
+ } __packed IOAPICRedirectEntry;
+
+ typedef union
+ {
+ struct
+ {
+ uint64_t Version : 8;
+ uint64_t Reserved : 8;
+ uint64_t MaximumRedirectionEntry : 8;
+ uint64_t Reserved2 : 8;
+ };
+ uint64_t raw;
+ } __packed IOAPICVersion;
+
+ class APIC
+ {
+ private:
+ bool x2APICSupported = false;
+ uint64_t APICBaseAddress = 0;
+
+ public:
+ uint32_t Read(uint32_t Register);
+ void Write(uint32_t Register, uint32_t Value);
+ void IOWrite(uint64_t Base, uint32_t Register, uint32_t Value);
+ uint32_t IORead(uint64_t Base, uint32_t Register);
+ void EOI();
+ void RedirectIRQs(int CPU = 0);
+ void WaitForIPI();
+ void IPI(int CPU, InterruptCommandRegisterLow icr);
+ void SendInitIPI(int CPU);
+ void SendStartupIPI(int CPU, uint64_t StartupAddress);
+ uint32_t IOGetMaxRedirect(uint32_t APICID);
+ void RawRedirectIRQ(uint16_t Vector, uint32_t GSI, uint16_t Flags, int CPU, int Status);
+ void RedirectIRQ(int CPU, uint16_t IRQ, int Status);
+ APIC(int Core);
+ ~APIC();
+ };
+
+ class Timer : public Interrupts::Handler
+ {
+ private:
+ APIC *lapic;
+ uint64_t Ticks = 0;
+ void OnInterruptReceived(CPU::x64::TrapFrame *Frame);
+
+ public:
+ uint64_t GetTicks() { return Ticks; }
+ void OneShot(uint32_t Vector, uint64_t Miliseconds);
+ Timer(APIC *apic);
+ ~Timer();
+ };
+}
+
+#endif // !__FENNIX_KERNEL_APIC_H__
diff --git a/Kernel/Architecture/amd64/cpu/gdt.hpp b/Kernel/Architecture/amd64/cpu/gdt.hpp
new file mode 100644
index 00000000..7eec05d6
--- /dev/null
+++ b/Kernel/Architecture/amd64/cpu/gdt.hpp
@@ -0,0 +1,164 @@
+/*
+ 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 .
+*/
+
+#ifndef __FENNIX_KERNEL_GDT_H__
+#define __FENNIX_KERNEL_GDT_H__
+
+#include
+
+namespace GlobalDescriptorTable
+{
+ /** @brief The GDT Access Table
+ * @details For more information, see https://wiki.osdev.org/Global_Descriptor_Table
+ */
+ union GlobalDescriptorTableAccess
+ {
+ struct
+ {
+ /** @brief Access bit.
+ * @note The CPU sets this bit to 1 when the segment is accessed.
+ */
+ uint64_t A : 1;
+
+ /** @brief Readable bit for code segments, writable bit for data segments.
+ * @details For code segments, this bit must be 1 for the segment to be readable.
+ * @details For data segments, this bit must be 1 for the segment to be writable.
+ */
+ uint64_t RW : 1;
+
+ /** @brief Direction bit for data segments, conforming bit for code segments.
+ * @details For data segments, this bit must be 1 for the segment to grow up (higher addresses).
+ * @details For code segments, this bit must be 1 for code in the segment to be able to be executed from an equal or lower privilege level.
+ */
+ uint64_t DC : 1;
+
+ /** @brief Executable bit.
+ * @details This bit must be 1 for code-segment descriptors.
+ * @details This bit must be 0 for data-segment and system descriptors.
+ */
+ uint64_t E : 1;
+
+ /** @brief Descriptor type.
+ * @details This bit must be 0 for system descriptors.
+ * @details This bit must be 1 for code or data segment descriptor.
+ */
+ uint64_t S : 1;
+
+ /** @brief Descriptor privilege level.
+ * @details This field determines the privilege level of the segment.
+ * @details 0 = kernel mode, 3 = user mode.
+ */
+ uint64_t DPL : 2;
+
+ /** @brief Present bit.
+ * @details This bit must be 1 for all valid descriptors.
+ */
+ uint64_t P : 1;
+ } __packed;
+ uint8_t Raw;
+ };
+
+ union GlobalDescriptorTableFlags
+ {
+ // TODO: Add more flags.
+ struct
+ {
+ /** @brief Unknown. */
+ uint64_t Unknown : 5;
+
+ /** @brief Long mode.
+ * @details If the long mode bit is clear, the segment is in 32-bit protected mode.
+ * @details If the long mode bit is set, the segment is in 64-bit long mode.
+ */
+ uint64_t L : 1;
+ } __packed;
+ uint8_t Raw;
+ };
+
+ typedef struct _TaskStateSegmentEntry
+ {
+ /* LOW */
+ uint16_t Length;
+ uint16_t BaseLow;
+ uint8_t BaseMiddle;
+ GlobalDescriptorTableAccess Flags;
+ uint8_t Granularity;
+ uint8_t BaseHigh;
+ /* HIGH */
+ uint32_t BaseUpper;
+ uint32_t Reserved;
+ } __packed TaskStateSegmentEntry;
+
+ typedef struct _TaskStateSegment
+ {
+ uint32_t Reserved0 __aligned(16);
+ uint64_t StackPointer[3];
+ uint64_t Reserved1;
+ uint64_t InterruptStackTable[7];
+ uint64_t Reserved2;
+ uint16_t Reserved3;
+ uint16_t IOMapBaseAddressOffset;
+ } __packed TaskStateSegment;
+
+ typedef struct _GlobalDescriptorTableEntry
+ {
+ /** @brief Length */
+ uint16_t Length;
+ /** @brief Low Base */
+ uint16_t BaseLow;
+ /** @brief Middle Base */
+ uint8_t BaseMiddle;
+ /** @brief Access */
+ GlobalDescriptorTableAccess Access;
+ /** @brief Flags */
+ GlobalDescriptorTableFlags Flags;
+ /** @brief High Base */
+ uint8_t BaseHigh;
+ } __packed GlobalDescriptorTableEntry;
+
+ typedef struct _GlobalDescriptorTableEntries
+ {
+ GlobalDescriptorTableEntry Null;
+ GlobalDescriptorTableEntry Code;
+ GlobalDescriptorTableEntry Data;
+ GlobalDescriptorTableEntry UserData;
+ GlobalDescriptorTableEntry UserCode;
+ TaskStateSegmentEntry TaskStateSegment;
+ } __packed GlobalDescriptorTableEntries;
+
+ typedef struct _GlobalDescriptorTableDescriptor
+ {
+ /** @brief GDT entries length */
+ uint16_t Length;
+ /** @brief GDT entries address */
+ GlobalDescriptorTableEntries *Entries;
+ } __packed GlobalDescriptorTableDescriptor;
+
+ extern void *CPUStackPointer[];
+ extern TaskStateSegment tss[];
+ void Init(int Core);
+ void SetKernelStack(void *Stack);
+ void *GetKernelStack();
+}
+
+#define GDT_KERNEL_CODE offsetof(GlobalDescriptorTable::GlobalDescriptorTableEntries, Code)
+#define GDT_KERNEL_DATA offsetof(GlobalDescriptorTable::GlobalDescriptorTableEntries, Data)
+#define GDT_USER_CODE (offsetof(GlobalDescriptorTable::GlobalDescriptorTableEntries, UserCode) | 3)
+#define GDT_USER_DATA (offsetof(GlobalDescriptorTable::GlobalDescriptorTableEntries, UserData) | 3)
+#define GDT_TSS (offsetof(GlobalDescriptorTable::GlobalDescriptorTableEntries, TaskStateSegment) | 3)
+
+#endif // !__FENNIX_KERNEL_GDT_H__
diff --git a/Kernel/Architecture/amd64/cpu/idt.hpp b/Kernel/Architecture/amd64/cpu/idt.hpp
new file mode 100644
index 00000000..ccc1da87
--- /dev/null
+++ b/Kernel/Architecture/amd64/cpu/idt.hpp
@@ -0,0 +1,84 @@
+/*
+ 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 .
+*/
+
+#ifndef __FENNIX_KERNEL_IDT_H__
+#define __FENNIX_KERNEL_IDT_H__
+
+#include
+
+namespace InterruptDescriptorTable
+{
+ typedef enum _InterruptGateType
+ {
+ TASK = 0b101,
+ INT_16BIT = 0b110,
+ TRAP_16BIT = 0b111,
+ INT_32BIT = 0b1110,
+ TRAP_32BIT = 0b1111,
+ } InterruptGateType;
+
+ typedef enum _InterruptRingType
+ {
+ RING0 = 0b0,
+ RING1 = 0b1,
+ RING2 = 0b10,
+ RING3 = 0b11,
+ } InterruptRingType;
+
+ typedef enum _InterruptStackTableType
+ {
+ IST0 = 0b0,
+ IST1 = 0b1,
+ IST2 = 0b10,
+ IST3 = 0b11,
+ IST4 = 0b100,
+ IST5 = 0b101,
+ IST6 = 0b110,
+ } InterruptStackTableType;
+
+ typedef struct _InterruptDescriptorTableEntry
+ {
+ uint64_t BaseLow : 16;
+ uint64_t SegmentSelector : 16;
+ uint64_t InterruptStackTable : 3;
+ uint64_t Reserved1 : 5;
+ uint64_t Flags : 4;
+ uint64_t Reserved2 : 1;
+ uint64_t Ring : 2;
+ uint64_t Present : 1;
+ uint64_t BaseHigh : 48;
+ uint64_t Reserved3 : 32;
+ } __packed InterruptDescriptorTableEntry;
+
+ typedef struct _InterruptDescriptorTableDescriptor
+ {
+ uint16_t Length;
+ InterruptDescriptorTableEntry *Entries;
+ } __packed InterruptDescriptorTableDescriptor;
+
+ void SetEntry(uint8_t Index,
+ void (*Base)(),
+ InterruptStackTableType InterruptStackTable,
+ InterruptGateType Gate,
+ InterruptRingType Ring,
+ bool Present,
+ uint16_t SegmentSelector);
+
+ void Init(int Core);
+}
+
+#endif // !__FENNIX_KERNEL_IDT_H__
diff --git a/Kernel/Architecture/amd64/linker.ld b/Kernel/Architecture/amd64/linker.ld
new file mode 100644
index 00000000..47dbe0e5
--- /dev/null
+++ b/Kernel/Architecture/amd64/linker.ld
@@ -0,0 +1,92 @@
+/*
+ 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 .
+*/
+
+OUTPUT_FORMAT(elf64-x86-64)
+OUTPUT_ARCH(i386:x86-64)
+
+KERNEL_VMA = 0xFFFFFFFF80000000;
+
+ENTRY(_start)
+
+SECTIONS
+{
+ . = 0x100000;
+
+ _bootstrap_start = .;
+ .bootstrap :
+ {
+ *(.multiboot)
+ *(.multiboot2)
+ *(.bootstrap .bootstrap.*)
+ }
+ . += CONSTANT(MAXPAGESIZE);
+ _bootstrap_end = ALIGN(CONSTANT(MAXPAGESIZE));
+
+ . += KERNEL_VMA;
+ . += CONSTANT(MAXPAGESIZE);
+ _kernel_start = ALIGN(CONSTANT(MAXPAGESIZE));
+ .text : AT(ADDR(.text) - KERNEL_VMA)
+ {
+ *(.text .text.*)
+ }
+ _kernel_text_end = ALIGN(CONSTANT(MAXPAGESIZE));
+ . += CONSTANT(MAXPAGESIZE);
+
+ .data : AT(ADDR(.data) - KERNEL_VMA)
+ {
+ *(.data .data.*)
+ }
+ _kernel_data_end = ALIGN(CONSTANT(MAXPAGESIZE));
+ . += CONSTANT(MAXPAGESIZE);
+
+ .rodata : AT(ADDR(.rodata) - KERNEL_VMA)
+ {
+ *(.rodata .rodata.*)
+ }
+
+ .init_array : AT(ADDR(.init_array) - KERNEL_VMA)
+ {
+ PROVIDE_HIDDEN(__init_array_start = .);
+ KEEP(*(.init_array .ctors))
+ KEEP(*(SORT_BY_INIT_PRIORITY(.init_array.*) SORT_BY_INIT_PRIORITY(.ctors.*)))
+ PROVIDE_HIDDEN (__init_array_end = .);
+ }
+
+ .fini_array : AT(ADDR(.fini_array) - KERNEL_VMA)
+ {
+ PROVIDE_HIDDEN(__fini_array_start = .);
+ KEEP(*(SORT_BY_INIT_PRIORITY(.fini_array.*) SORT_BY_INIT_PRIORITY(.dtors.*)))
+ KEEP(*(.fini_array .dtors))
+ PROVIDE_HIDDEN (__fini_array_end = .);
+ }
+ _kernel_rodata_end = ALIGN(CONSTANT(MAXPAGESIZE));
+ . += CONSTANT(MAXPAGESIZE);
+
+ .bss : AT(ADDR(.bss) - KERNEL_VMA)
+ {
+ *(COMMON)
+ *(.bss .bss.*)
+ }
+ . += CONSTANT(MAXPAGESIZE);
+ _kernel_end = ALIGN(CONSTANT(MAXPAGESIZE));
+
+ /DISCARD/ :
+ {
+ *(.comment*)
+ *(.note*)
+ }
+}
diff --git a/Kernel/Architecture/amd64/runtime/crt0.c b/Kernel/Architecture/amd64/runtime/crt0.c
new file mode 100644
index 00000000..35cf1abd
--- /dev/null
+++ b/Kernel/Architecture/amd64/runtime/crt0.c
@@ -0,0 +1,15 @@
+// #include
+
+// #include
+
+// int Entry(void *Info);
+
+// void _start(void *Raw)
+// {
+// error("Todo");
+// while (1)
+// asmv("hlt");
+// Entry(NULL);
+// return;
+// }
+// C stuff
\ No newline at end of file
diff --git a/Kernel/Architecture/amd64/runtime/crt1.c b/Kernel/Architecture/amd64/runtime/crt1.c
new file mode 100644
index 00000000..1369bfeb
--- /dev/null
+++ b/Kernel/Architecture/amd64/runtime/crt1.c
@@ -0,0 +1,15 @@
+#include
+
+#include
+
+int Entry(void *Info);
+
+// void _start(void *Raw)
+// {
+// UNUSED(Raw);
+// error("ERROR! INVALID BOOT PROTOCOL!");
+// while (1)
+// asmv("hlt");
+// Entry(NULL);
+// return;
+// }
diff --git a/Kernel/Architecture/amd64/runtime/crtbegin.c b/Kernel/Architecture/amd64/runtime/crtbegin.c
new file mode 100644
index 00000000..507125b3
--- /dev/null
+++ b/Kernel/Architecture/amd64/runtime/crtbegin.c
@@ -0,0 +1 @@
+// C++ constructor/destructor stuff
\ No newline at end of file
diff --git a/Kernel/Architecture/amd64/runtime/crtend.c b/Kernel/Architecture/amd64/runtime/crtend.c
new file mode 100644
index 00000000..507125b3
--- /dev/null
+++ b/Kernel/Architecture/amd64/runtime/crtend.c
@@ -0,0 +1 @@
+// C++ constructor/destructor stuff
\ No newline at end of file
diff --git a/Kernel/Architecture/amd64/runtime/crti.S b/Kernel/Architecture/amd64/runtime/crti.S
new file mode 100644
index 00000000..93855715
--- /dev/null
+++ b/Kernel/Architecture/amd64/runtime/crti.S
@@ -0,0 +1,13 @@
+.section .init
+.global _init
+.type _init, @function
+_init:
+ push %rbp
+ movq %rsp, %rbp
+
+.section .fini
+.global _fini
+.type _fini, @function
+_fini:
+ push %rbp
+ movq %rsp, %rbp
diff --git a/Kernel/Architecture/amd64/runtime/crtn.S b/Kernel/Architecture/amd64/runtime/crtn.S
new file mode 100644
index 00000000..2fe55b4d
--- /dev/null
+++ b/Kernel/Architecture/amd64/runtime/crtn.S
@@ -0,0 +1,7 @@
+.section .init
+ popq %rbp
+ ret
+
+.section .fini
+ popq %rbp
+ ret
diff --git a/Kernel/Architecture/amd64/rust-target.json b/Kernel/Architecture/amd64/rust-target.json
new file mode 100644
index 00000000..f3697f10
--- /dev/null
+++ b/Kernel/Architecture/amd64/rust-target.json
@@ -0,0 +1,21 @@
+{
+ "llvm-target": "x86_64-unknown-none",
+ "data-layout": "e-m:e-i64:64-f80:128-n8:16:32:64-S128",
+ "cpu": "x86-64",
+ "arch": "x86_64",
+ "features": "-mmx,-sse,+soft-float",
+ "target-endian": "little",
+ "target-pointer-width": "64",
+ "target-c-int-width": "32",
+ "os": "none",
+ "linker-flavor": "ld",
+ "pre-link-args": {
+ "ld": [
+ "-m64"
+ ]
+ },
+ "no-compiler-rt": true,
+ "disable-redzone": true,
+ "eliminate-frame-pointer": false,
+ "morestack": false
+}
\ No newline at end of file
diff --git a/Kernel/Architecture/i386/ArithmeticOperations.c b/Kernel/Architecture/i386/ArithmeticOperations.c
new file mode 100644
index 00000000..91a9db63
--- /dev/null
+++ b/Kernel/Architecture/i386/ArithmeticOperations.c
@@ -0,0 +1,327 @@
+/* Source: https://github.com/glitchub/arith64 */
+#define arith64_u64 unsigned long long int
+#define arith64_s64 signed long long int
+#define arith64_u32 unsigned int
+#define arith64_s32 int
+
+typedef union
+{
+ arith64_u64 u64;
+ arith64_s64 s64;
+ struct
+ {
+#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
+ arith64_u32 hi;
+ arith64_u32 lo;
+#else
+ arith64_u32 lo;
+ arith64_u32 hi;
+#endif
+ } u32;
+ struct
+ {
+#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
+ arith64_s32 hi;
+ arith64_s32 lo;
+#else
+ arith64_s32 lo;
+ arith64_s32 hi;
+#endif
+ } s32;
+} arith64_word;
+
+#define arith64_hi(n) (arith64_word){.u64 = n}.u32.hi
+#define arith64_lo(n) (arith64_word){.u64 = n}.u32.lo
+#define arith64_neg(a, b) (((a) ^ ((((arith64_s64)(b)) >= 0) - 1)) + (((arith64_s64)(b)) < 0))
+#define arith64_abs(a) arith64_neg(a, a)
+
+arith64_s64 __absvdi2(arith64_s64 a)
+{
+ return arith64_abs(a);
+}
+
+arith64_s64 __ashldi3(arith64_s64 a, int b)
+{
+ arith64_word w = {.s64 = a};
+
+ b &= 63;
+
+ if (b >= 32)
+ {
+ w.u32.hi = w.u32.lo << (b - 32);
+ w.u32.lo = 0;
+ }
+ else if (b)
+ {
+ w.u32.hi = (w.u32.lo >> (32 - b)) | (w.u32.hi << b);
+ w.u32.lo <<= b;
+ }
+ return w.s64;
+}
+
+arith64_s64 __ashrdi3(arith64_s64 a, int b)
+{
+ arith64_word w = {.s64 = a};
+
+ b &= 63;
+
+ if (b >= 32)
+ {
+ w.s32.lo = w.s32.hi >> (b - 32);
+ w.s32.hi >>= 31; // 0xFFFFFFFF or 0
+ }
+ else if (b)
+ {
+ w.u32.lo = (w.u32.hi << (32 - b)) | (w.u32.lo >> b);
+ w.s32.hi >>= b;
+ }
+ return w.s64;
+}
+
+int __clzsi2(arith64_u32 a)
+{
+ int b, n = 0;
+ b = !(a & 0xffff0000) << 4;
+ n += b;
+ a <<= b;
+ b = !(a & 0xff000000) << 3;
+ n += b;
+ a <<= b;
+ b = !(a & 0xf0000000) << 2;
+ n += b;
+ a <<= b;
+ b = !(a & 0xc0000000) << 1;
+ n += b;
+ a <<= b;
+ return n + !(a & 0x80000000);
+}
+
+int __clzdi2(arith64_u64 a)
+{
+ int b, n = 0;
+ b = !(a & 0xffffffff00000000ULL) << 5;
+ n += b;
+ a <<= b;
+ b = !(a & 0xffff000000000000ULL) << 4;
+ n += b;
+ a <<= b;
+ b = !(a & 0xff00000000000000ULL) << 3;
+ n += b;
+ a <<= b;
+ b = !(a & 0xf000000000000000ULL) << 2;
+ n += b;
+ a <<= b;
+ b = !(a & 0xc000000000000000ULL) << 1;
+ n += b;
+ a <<= b;
+ return n + !(a & 0x8000000000000000ULL);
+}
+
+int __ctzsi2(arith64_u32 a)
+{
+ int b, n = 0;
+ b = !(a & 0x0000ffff) << 4;
+ n += b;
+ a >>= b;
+ b = !(a & 0x000000ff) << 3;
+ n += b;
+ a >>= b;
+ b = !(a & 0x0000000f) << 2;
+ n += b;
+ a >>= b;
+ b = !(a & 0x00000003) << 1;
+ n += b;
+ a >>= b;
+ return n + !(a & 0x00000001);
+}
+
+int __ctzdi2(arith64_u64 a)
+{
+ int b, n = 0;
+ b = !(a & 0x00000000ffffffffULL) << 5;
+ n += b;
+ a >>= b;
+ b = !(a & 0x000000000000ffffULL) << 4;
+ n += b;
+ a >>= b;
+ b = !(a & 0x00000000000000ffULL) << 3;
+ n += b;
+ a >>= b;
+ b = !(a & 0x000000000000000fULL) << 2;
+ n += b;
+ a >>= b;
+ b = !(a & 0x0000000000000003ULL) << 1;
+ n += b;
+ a >>= b;
+ return n + !(a & 0x0000000000000001ULL);
+}
+
+arith64_u64 __divmoddi4(arith64_u64 a, arith64_u64 b, arith64_u64 *c)
+{
+ if (b > a)
+ {
+ if (c)
+ *c = a;
+ return 0;
+ }
+ if (!arith64_hi(b))
+ {
+ if (b == 0)
+ {
+ volatile char x = 0;
+ x = 1 / x;
+ }
+ if (b == 1)
+ {
+ if (c)
+ *c = 0;
+ return a;
+ }
+ if (!arith64_hi(a))
+ {
+ if (c)
+ *c = arith64_lo(a) % arith64_lo(b);
+ return arith64_lo(a) / arith64_lo(b);
+ }
+ }
+
+ char bits = __clzdi2(b) - __clzdi2(a) + 1;
+ arith64_u64 rem = a >> bits;
+ a <<= 64 - bits;
+ arith64_u64 wrap = 0;
+ while (bits-- > 0)
+ {
+ rem = (rem << 1) | (a >> 63);
+ a = (a << 1) | (wrap & 1);
+ wrap = ((arith64_s64)(b - rem - 1) >> 63);
+ rem -= b & wrap;
+ }
+ if (c)
+ *c = rem;
+ return (a << 1) | (wrap & 1);
+}
+
+arith64_s64 __divdi3(arith64_s64 a, arith64_s64 b)
+{
+ arith64_u64 q = __divmoddi4(arith64_abs(a), arith64_abs(b), (void *)0);
+ return arith64_neg(q, a ^ b);
+}
+
+int __ffsdi2(arith64_u64 a) { return a ? __ctzdi2(a) + 1 : 0; }
+
+arith64_u64 __lshrdi3(arith64_u64 a, int b)
+{
+ arith64_word w = {.u64 = a};
+
+ b &= 63;
+
+ if (b >= 32)
+ {
+ w.u32.lo = w.u32.hi >> (b - 32);
+ w.u32.hi = 0;
+ }
+ else if (b)
+ {
+ w.u32.lo = (w.u32.hi << (32 - b)) | (w.u32.lo >> b);
+ w.u32.hi >>= b;
+ }
+ return w.u64;
+}
+
+arith64_s64 __moddi3(arith64_s64 a, arith64_s64 b)
+{
+ arith64_u64 r;
+ __divmoddi4(arith64_abs(a), arith64_abs(b), &r);
+ return arith64_neg(r, a);
+}
+
+int __popcountsi2(arith64_u32 a)
+{
+
+ a = a - ((a >> 1) & 0x55555555);
+ a = ((a >> 2) & 0x33333333) + (a & 0x33333333);
+ a = (a + (a >> 4)) & 0x0F0F0F0F;
+ a = (a + (a >> 16));
+
+ return (a + (a >> 8)) & 63;
+}
+
+int __popcountdi2(arith64_u64 a)
+{
+
+ a = a - ((a >> 1) & 0x5555555555555555ULL);
+ a = ((a >> 2) & 0x3333333333333333ULL) + (a & 0x3333333333333333ULL);
+ a = (a + (a >> 4)) & 0x0F0F0F0F0F0F0F0FULL;
+ a = (a + (a >> 32));
+ a = (a + (a >> 16));
+
+ return (a + (a >> 8)) & 127;
+}
+
+arith64_u64 __udivdi3(arith64_u64 a, arith64_u64 b) { return __divmoddi4(a, b, (void *)0); }
+
+arith64_u64 __umoddi3(arith64_u64 a, arith64_u64 b)
+{
+ arith64_u64 r;
+ __divmoddi4(a, b, &r);
+ return r;
+}
+
+/* Good documentation: https://splichal.eu/scripts/sphinx/gccint/_build/html/the-gcc-low-level-runtime-library/routines-for-floating-point-emulation.html */
+
+double __adddf3(double a, double b) { return a + b; }
+double __muldf3(double a, double b) { return a * b; }
+double __floatsidf(int i) { return (double)i; }
+int __ltdf2(double a, double b) { return a < b; }
+int __gtdf2(double a, double b) { return a > b; }
+int __nedf2(double a, double b) { return a != b; }
+int __eqdf2(double a, double b) { return a == b; }
+double __floatdidf(long i) { return (double)i; }
+double __divdf3(double a, double b) { return a / b; }
+double __subdf3(double a, double b) { return a - b; }
+int __gedf2(double a, double b) { return a >= b; }
+int __fixdfsi(double a) { return (int)a; }
+long __fixdfdi(double a) { return (long)a; }
+int __ledf2(double a, double b) { return a <= b; }
+
+/* FIXME: Check if these functions are implemented correctly */
+
+typedef long long int64_t;
+typedef unsigned long long uint64_t;
+typedef unsigned int uint32_t;
+typedef struct
+{
+ uint64_t value;
+} atomic_uint64_t;
+
+uint64_t __atomic_load_8(const atomic_uint64_t *p)
+{
+ uint64_t value;
+ __asm__ volatile("lock cmpxchg8b %1"
+ : "=A"(value)
+ : "m"(*p)
+ : "memory");
+ return value;
+}
+
+void __atomic_store_8(atomic_uint64_t *p, uint64_t value)
+{
+ __asm__ volatile("lock cmpxchg8b %0"
+ : "=m"(p->value)
+ : "a"((uint32_t)value), "d"((uint32_t)(value >> 32)), "m"(*p)
+ : "memory");
+}
+
+/* FIXME: __fixsfsi is not implemented correctly(?) */
+int __fixsfsi(float a) { return (int)a; }
+
+int __ltsf2(float a, float b) { return a < b; }
+int __eqsf2(float a, float b) { return a == b; }
+float __divsf3(float a, float b) { return a / b; }
+double __extendsfdf2(float a) { return (double)a; }
+float __truncdfsf2(double a) { return (float)a; }
+float __subsf3(float a, float b) { return a - b; }
+float __floatsisf(int a) { return (float)a; }
+int __fixunssfsi(float a) { return (int)a; }
+float __mulsf3(float a, float b) { return a * b; }
+float __addsf3(float a, float b) { return a + b; }
diff --git a/Kernel/Architecture/i386/Bootstrap/Header_Multiboot.asm b/Kernel/Architecture/i386/Bootstrap/Header_Multiboot.asm
new file mode 100644
index 00000000..71a6efe8
--- /dev/null
+++ b/Kernel/Architecture/i386/Bootstrap/Header_Multiboot.asm
@@ -0,0 +1,5 @@
+section .multiboot
+align 4
+ dd 0x1BADB002
+ dd 1 << 0 | 1 << 1
+ dd -(0x1BADB002 + (1 << 0 | 1 << 1))
diff --git a/Kernel/Architecture/i386/Bootstrap/Header_Multiboot2.asm b/Kernel/Architecture/i386/Bootstrap/Header_Multiboot2.asm
new file mode 100644
index 00000000..a0a9a71e
--- /dev/null
+++ b/Kernel/Architecture/i386/Bootstrap/Header_Multiboot2.asm
@@ -0,0 +1,41 @@
+section .multiboot2
+align 4096
+HEADER_START:
+ dd 0xE85250D6
+ dd 0
+ dd (HEADER_END - HEADER_START)
+ dd 0x100000000 - (HEADER_END - HEADER_START) - 0 - 0xE85250D6
+align 8
+MB2_INFO_REQUEST_TAG_START:
+ dw 1
+ dw 0
+ dd MB2_INFO_REQUEST_TAG_END - MB2_INFO_REQUEST_TAG_START
+ dd 1 ; Command Line
+ dd 2 ; Boot Loader Name
+ dd 3 ; Module
+ dd 4 ; Basic Memory Information
+ dd 5 ; BIOS Boot Device
+ dd 6 ; Memory Map
+ dd 7 ; VBE
+ dd 8 ; Framebuffer
+ dd 9 ; ELF Sections
+ dd 10 ; APM Table
+ dd 11 ; EFI 32-bit System Table Pointer
+ dd 12 ; EFI 64-bit System Table Pointer
+ ; dd 13 ; SMBIOS
+ dd 14 ; ACPI Old
+ dd 15 ; ACPI New
+ dd 16 ; Network
+ dd 17 ; EFI Memory Map
+ dd 18 ; EFI Boot Services Notifier
+ dd 19 ; EFI 32-bit Image Handle Pointer
+ dd 20 ; EFI 64-bit Image Handle Pointer
+ dd 21 ; Load Base Address
+MB2_INFO_REQUEST_TAG_END:
+align 8
+MB2_TAG_START:
+ dw 0
+ dw 0
+ dd MB2_TAG_END - MB2_TAG_START
+MB2_TAG_END:
+HEADER_END:
diff --git a/Kernel/Architecture/i386/Bootstrap/Multiboot.cpp b/Kernel/Architecture/i386/Bootstrap/Multiboot.cpp
new file mode 100644
index 00000000..a048bdf9
--- /dev/null
+++ b/Kernel/Architecture/i386/Bootstrap/Multiboot.cpp
@@ -0,0 +1,286 @@
+#include
+
+#include
+#include
+#include
+
+#include "../../../kernel.h"
+
+EXTERNC void multiboot_main(uint32_t Magic, uint32_t Info)
+{
+ if (Info == NULL || Magic == NULL)
+ {
+ if (Magic == NULL)
+ error("Multiboot magic is NULL");
+ if (Info == NULL)
+ error("Multiboot info is NULL");
+ CPU::Stop();
+ }
+ else if (Magic != MULTIBOOT2_BOOTLOADER_MAGIC)
+ {
+ error("Multiboot magic is invalid (%#x != %#x)", Magic, MULTIBOOT2_BOOTLOADER_MAGIC);
+ CPU::Stop();
+ }
+
+ uint64_t div = 1193180 / 1000;
+ outb(0x43, 0xB6);
+ outb(0x42, (uint8_t)div);
+ outb(0x42, (uint8_t)(div >> 8));
+ uint8_t tmp = inb(0x61);
+ if (tmp != (tmp | 3))
+ outb(0x61, tmp | 3);
+
+ BootInfo mb2binfo;
+ int pos = 0;
+ auto InfoAddress = Info;
+ for (auto Tag = (struct multiboot_tag *)((uint8_t *)InfoAddress + 8);
+ ;
+ Tag = (struct multiboot_tag *)((multiboot_uint8_t *)Tag + ((Tag->size + 7) & ~7)))
+ {
+ if (Tag->type == MULTIBOOT_TAG_TYPE_END)
+ {
+ debug("End of multiboot2 tags");
+ break;
+ }
+
+ switch (Tag->type)
+ {
+ case MULTIBOOT_TAG_TYPE_CMDLINE:
+ {
+ strncpy(mb2binfo.Kernel.CommandLine,
+ ((multiboot_tag_string *)Tag)->string,
+ strlen(((multiboot_tag_string *)Tag)->string));
+ debug("Kernel command line: %s", mb2binfo.Kernel.CommandLine);
+ break;
+ }
+ case MULTIBOOT_TAG_TYPE_BOOT_LOADER_NAME:
+ {
+ strncpy(mb2binfo.Bootloader.Name,
+ ((multiboot_tag_string *)Tag)->string,
+ strlen(((multiboot_tag_string *)Tag)->string));
+ debug("Bootloader name: %s", mb2binfo.Bootloader.Name);
+ break;
+ }
+ case MULTIBOOT_TAG_TYPE_MODULE:
+ {
+ multiboot_tag_module *module = (multiboot_tag_module *)Tag;
+ static int module_count = 0;
+ mb2binfo.Modules[module_count++].Address = (void *)(uint64_t)module->mod_start;
+ mb2binfo.Modules[module_count++].Size = module->size;
+ strncpy(mb2binfo.Modules[module_count++].Path, "(null)", 6);
+ strncpy(mb2binfo.Modules[module_count++].CommandLine, module->cmdline,
+ strlen(module->cmdline));
+ debug("Module: %s", mb2binfo.Modules[module_count++].Path);
+ break;
+ }
+ case MULTIBOOT_TAG_TYPE_BASIC_MEMINFO:
+ {
+ multiboot_tag_basic_meminfo *meminfo = (multiboot_tag_basic_meminfo *)Tag;
+ fixme("basic_meminfo->[mem_lower: %#x, mem_upper: %#x]",
+ meminfo->mem_lower, meminfo->mem_upper);
+ break;
+ }
+ case MULTIBOOT_TAG_TYPE_BOOTDEV:
+ {
+ multiboot_tag_bootdev *bootdev = (multiboot_tag_bootdev *)Tag;
+ fixme("bootdev->[biosdev: %#x, slice: %#x, part: %#x]",
+ bootdev->biosdev, bootdev->slice, bootdev->part);
+ break;
+ }
+ case MULTIBOOT_TAG_TYPE_MMAP:
+ {
+ multiboot_tag_mmap *mmap = (multiboot_tag_mmap *)Tag;
+ uint32_t EntryCount = mmap->size / sizeof(multiboot_mmap_entry);
+ mb2binfo.Memory.Entries = EntryCount;
+ for (uint32_t i = 0; i < EntryCount; i++)
+ {
+ if (EntryCount > MAX_MEMORY_ENTRIES)
+ {
+ warn("Too many memory entries, skipping the rest...");
+ break;
+ }
+ multiboot_mmap_entry entry = mmap->entries[i];
+ mb2binfo.Memory.Size += entry.len;
+ switch (entry.type)
+ {
+ case MULTIBOOT_MEMORY_AVAILABLE:
+ mb2binfo.Memory.Entry[i].BaseAddress = (void *)entry.addr;
+ mb2binfo.Memory.Entry[i].Length = entry.len;
+ mb2binfo.Memory.Entry[i].Type = Usable;
+ break;
+ case MULTIBOOT_MEMORY_RESERVED:
+ mb2binfo.Memory.Entry[i].BaseAddress = (void *)entry.addr;
+ mb2binfo.Memory.Entry[i].Length = entry.len;
+ mb2binfo.Memory.Entry[i].Type = Reserved;
+ break;
+ case MULTIBOOT_MEMORY_ACPI_RECLAIMABLE:
+ mb2binfo.Memory.Entry[i].BaseAddress = (void *)entry.addr;
+ mb2binfo.Memory.Entry[i].Length = entry.len;
+ mb2binfo.Memory.Entry[i].Type = ACPIReclaimable;
+ break;
+ case MULTIBOOT_MEMORY_NVS:
+ mb2binfo.Memory.Entry[i].BaseAddress = (void *)entry.addr;
+ mb2binfo.Memory.Entry[i].Length = entry.len;
+ mb2binfo.Memory.Entry[i].Type = ACPINVS;
+ break;
+ case MULTIBOOT_MEMORY_BADRAM:
+ mb2binfo.Memory.Entry[i].BaseAddress = (void *)entry.addr;
+ mb2binfo.Memory.Entry[i].Length = entry.len;
+ mb2binfo.Memory.Entry[i].Type = BadMemory;
+ break;
+ default:
+ mb2binfo.Memory.Entry[i].BaseAddress = (void *)entry.addr;
+ mb2binfo.Memory.Entry[i].Length = entry.len;
+ mb2binfo.Memory.Entry[i].Type = Unknown;
+ break;
+ }
+ debug("Memory entry: [BaseAddress: %#x, Length: %#x, Type: %d]",
+ mb2binfo.Memory.Entry[i].BaseAddress,
+ mb2binfo.Memory.Entry[i].Length,
+ mb2binfo.Memory.Entry[i].Type);
+ }
+ break;
+ }
+ case MULTIBOOT_TAG_TYPE_VBE:
+ {
+ multiboot_tag_vbe *vbe = (multiboot_tag_vbe *)Tag;
+ fixme("vbe->[vbe_mode: %#x, vbe_interface_seg: %#x, vbe_interface_off: %#x, vbe_interface_len: %#x]",
+ vbe->vbe_mode, vbe->vbe_interface_seg, vbe->vbe_interface_off, vbe->vbe_interface_len);
+ break;
+ }
+ case MULTIBOOT_TAG_TYPE_FRAMEBUFFER:
+ {
+ multiboot_tag_framebuffer *fb = (multiboot_tag_framebuffer *)Tag;
+ static int fb_count = 0;
+ mb2binfo.Framebuffer[fb_count].BaseAddress = (void *)fb->common.framebuffer_addr;
+ mb2binfo.Framebuffer[fb_count].Width = fb->common.framebuffer_width;
+ mb2binfo.Framebuffer[fb_count].Height = fb->common.framebuffer_height;
+ mb2binfo.Framebuffer[fb_count].Pitch = fb->common.framebuffer_pitch;
+ mb2binfo.Framebuffer[fb_count].BitsPerPixel = fb->common.framebuffer_bpp;
+ switch (fb->common.framebuffer_type)
+ {
+ case MULTIBOOT_FRAMEBUFFER_TYPE_INDEXED:
+ {
+ mb2binfo.Framebuffer[fb_count].Type = Indexed;
+ break;
+ }
+ case MULTIBOOT_FRAMEBUFFER_TYPE_RGB:
+ {
+ mb2binfo.Framebuffer[fb_count].Type = RGB;
+ mb2binfo.Framebuffer[fb_count].RedMaskSize = fb->framebuffer_red_mask_size;
+ mb2binfo.Framebuffer[fb_count].RedMaskShift = fb->framebuffer_red_field_position;
+ mb2binfo.Framebuffer[fb_count].GreenMaskSize = fb->framebuffer_green_mask_size;
+ mb2binfo.Framebuffer[fb_count].GreenMaskShift = fb->framebuffer_green_field_position;
+ mb2binfo.Framebuffer[fb_count].BlueMaskSize = fb->framebuffer_blue_mask_size;
+ mb2binfo.Framebuffer[fb_count].BlueMaskShift = fb->framebuffer_blue_field_position;
+ break;
+ }
+ case MULTIBOOT_FRAMEBUFFER_TYPE_EGA_TEXT:
+ {
+ mb2binfo.Framebuffer[fb_count].Type = EGA;
+ break;
+ }
+ }
+ debug("Framebuffer %d: %dx%d %d bpp", fb_count, fb->common.framebuffer_width, fb->common.framebuffer_height, fb->common.framebuffer_bpp);
+ debug("More info:\nAddress: %p\nPitch: %lld\nMemoryModel: %d\nRedMaskSize: %d\nRedMaskShift: %d\nGreenMaskSize: %d\nGreenMaskShift: %d\nBlueMaskSize: %d\nBlueMaskShift: %d",
+ fb->common.framebuffer_addr, fb->common.framebuffer_pitch, fb->common.framebuffer_type,
+ fb->framebuffer_red_mask_size, fb->framebuffer_red_field_position, fb->framebuffer_green_mask_size,
+ fb->framebuffer_green_field_position, fb->framebuffer_blue_mask_size, fb->framebuffer_blue_field_position);
+ fb_count++;
+ break;
+ }
+ case MULTIBOOT_TAG_TYPE_ELF_SECTIONS:
+ {
+ multiboot_tag_elf_sections *elf = (multiboot_tag_elf_sections *)Tag;
+ fixme("elf_sections->[num=%d, size=%d, entsize=%d, shndx=%d]",
+ elf->num, elf->size, elf->entsize, elf->shndx);
+ break;
+ }
+ case MULTIBOOT_TAG_TYPE_APM:
+ {
+ multiboot_tag_apm *apm = (multiboot_tag_apm *)Tag;
+ fixme("apm->[version: %d, cseg: %d, offset: %d, cseg_16: %d, dseg: %d, flags: %d, cseg_len: %d, cseg_16_len: %d, dseg_len: %d]",
+ apm->version, apm->cseg, apm->offset, apm->cseg_16, apm->dseg, apm->flags, apm->cseg_len, apm->cseg_16_len, apm->dseg_len);
+ break;
+ }
+ case MULTIBOOT_TAG_TYPE_EFI32:
+ {
+ multiboot_tag_efi32 *efi32 = (multiboot_tag_efi32 *)Tag;
+ fixme("efi32->[pointer: %p, size: %d]", efi32->pointer, efi32->size);
+ break;
+ }
+ case MULTIBOOT_TAG_TYPE_EFI64:
+ {
+ multiboot_tag_efi64 *efi64 = (multiboot_tag_efi64 *)Tag;
+ fixme("efi64->[pointer: %p, size: %d]", efi64->pointer, efi64->size);
+ break;
+ }
+ case MULTIBOOT_TAG_TYPE_SMBIOS:
+ {
+ multiboot_tag_smbios *smbios = (multiboot_tag_smbios *)Tag;
+ fixme("smbios->[major: %d, minor: %d]", smbios->major, smbios->minor);
+ break;
+ }
+ case MULTIBOOT_TAG_TYPE_ACPI_OLD:
+ {
+ mb2binfo.RSDP = (BootInfo::RSDPInfo *)((multiboot_tag_old_acpi *)Tag)->rsdp;
+ debug("OLD ACPI RSDP: %p", mb2binfo.RSDP);
+ break;
+ }
+ case MULTIBOOT_TAG_TYPE_ACPI_NEW:
+ {
+ mb2binfo.RSDP = (BootInfo::RSDPInfo *)((multiboot_tag_new_acpi *)Tag)->rsdp;
+ debug("NEW ACPI RSDP: %p", mb2binfo.RSDP);
+ break;
+ }
+ case MULTIBOOT_TAG_TYPE_NETWORK:
+ {
+ multiboot_tag_network *net = (multiboot_tag_network *)Tag;
+ fixme("network->[dhcpack: %p]", net->dhcpack);
+ break;
+ }
+ case MULTIBOOT_TAG_TYPE_EFI_MMAP:
+ {
+ multiboot_tag_efi_mmap *efi_mmap = (multiboot_tag_efi_mmap *)Tag;
+ fixme("efi_mmap->[descr_size: %d, descr_vers: %d, efi_mmap: %p]",
+ efi_mmap->descr_size, efi_mmap->descr_vers, efi_mmap->efi_mmap);
+ break;
+ }
+ case MULTIBOOT_TAG_TYPE_EFI_BS:
+ {
+ fixme("efi_bs->[%p] (unknown structure)", Tag);
+ break;
+ }
+ case MULTIBOOT_TAG_TYPE_EFI32_IH:
+ {
+ multiboot_tag_efi32_ih *efi32_ih = (multiboot_tag_efi32_ih *)Tag;
+ fixme("efi32_ih->[pointer: %p]", efi32_ih->pointer);
+ break;
+ }
+ case MULTIBOOT_TAG_TYPE_EFI64_IH:
+ {
+ multiboot_tag_efi64_ih *efi64_ih = (multiboot_tag_efi64_ih *)Tag;
+ fixme("efi64_ih->[pointer: %p]", efi64_ih->pointer);
+ break;
+ }
+ case MULTIBOOT_TAG_TYPE_LOAD_BASE_ADDR:
+ {
+ multiboot_tag_load_base_addr *load_base_addr = (multiboot_tag_load_base_addr *)Tag;
+ mb2binfo.Kernel.PhysicalBase = (void *)(uint64_t)load_base_addr->load_base_addr;
+ mb2binfo.Kernel.VirtualBase = (void *)(uint64_t)(load_base_addr->load_base_addr + 0xFFFFFFFF80000000);
+ debug("Kernel base: %p (physical) %p (virtual)", mb2binfo.Kernel.PhysicalBase, mb2binfo.Kernel.VirtualBase);
+ break;
+ }
+ default:
+ {
+ error("Unknown multiboot2 tag type: %d", Tag->type);
+ break;
+ }
+ }
+ }
+
+ tmp = inb(0x61) & 0xFC;
+ outb(0x61, tmp);
+
+ Entry(&mb2binfo);
+}
diff --git a/Kernel/Architecture/i386/Bootstrap/Multiboot_Init.asm b/Kernel/Architecture/i386/Bootstrap/Multiboot_Init.asm
new file mode 100644
index 00000000..c8212a96
--- /dev/null
+++ b/Kernel/Architecture/i386/Bootstrap/Multiboot_Init.asm
@@ -0,0 +1,50 @@
+[bits 32]
+KERNEL_VIRTUAL_BASE equ 0xC0000000 ; 3GB
+KERNEL_STACK_SIZE equ 0x4000 ; 16KB
+
+extern multiboot_main
+extern BootPageTable
+global _start
+
+section .text
+
+MB_HeaderMagic:
+ dq 0
+
+MB_HeaderInfo:
+ dq 0
+
+_start:
+ cli
+ mov ecx, (BootPageTable - KERNEL_VIRTUAL_BASE)
+ mov cr3, ecx
+
+ mov ecx, cr4
+ or ecx, 0x00000010 ; Set PSE in CR4
+ mov cr4, ecx
+
+ mov ecx, cr0
+ or ecx, 0x80000000 ; Set PG in CR0
+ mov cr0, ecx
+
+ lea ecx, [HigherHalfStart]
+ jmp ecx
+
+HigherHalfStart:
+ mov [MB_HeaderMagic], eax
+ mov [MB_HeaderInfo], ebx
+ mov esp, KernelStack + KERNEL_STACK_SIZE
+ mov eax, [MB_HeaderMagic]
+ mov ebx, [MB_HeaderInfo]
+ push ebx ; Multiboot2 Header
+ add ebx, KERNEL_VIRTUAL_BASE
+ push eax ; Multiboot2 Magic
+ call multiboot_main
+.Hang:
+ hlt
+ jmp .Hang
+
+section .bss
+align 16
+KernelStack:
+ resb KERNEL_STACK_SIZE
diff --git a/Kernel/Architecture/i386/Bootstrap/Multiboot_PageTable.asm b/Kernel/Architecture/i386/Bootstrap/Multiboot_PageTable.asm
new file mode 100644
index 00000000..9df80899
--- /dev/null
+++ b/Kernel/Architecture/i386/Bootstrap/Multiboot_PageTable.asm
@@ -0,0 +1,10 @@
+KERNEL_PAGE_NUMBER equ 768 ; 0xC0000000
+
+section .data
+global BootPageTable
+align 0x1000
+BootPageTable:
+ dd 0x00000083
+ times (KERNEL_PAGE_NUMBER - 1) dd 0
+ dd 0x00000083
+ times (1024 - KERNEL_PAGE_NUMBER - 1) dd 0
diff --git a/Kernel/Architecture/i386/Interrupts/8259PIC.cpp b/Kernel/Architecture/i386/Interrupts/8259PIC.cpp
new file mode 100644
index 00000000..1be69a88
--- /dev/null
+++ b/Kernel/Architecture/i386/Interrupts/8259PIC.cpp
@@ -0,0 +1,140 @@
+/*
+ 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 .
+*/
+
+#include "pic.hpp"
+
+#include
+
+namespace PIC
+{
+ PIC::PIC(uint8_t MasterCommandPort, uint8_t MasterDataPort, uint8_t SlaveCommandPort, uint8_t SlaveDataPort, uint8_t MasterOffset, uint8_t SlaveOffset)
+ {
+ this->MasterCommandPort = MasterCommandPort;
+ this->MasterDataPort = MasterDataPort;
+ this->SlaveCommandPort = SlaveCommandPort;
+ this->SlaveDataPort = SlaveDataPort;
+ this->MasterOffset = MasterOffset;
+ this->SlaveOffset = SlaveOffset;
+
+ MasterMask = 0xFF;
+ SlaveMask = 0xFF;
+
+ // ICW1
+ outb(MasterCommandPort, 0x11);
+ outb(SlaveCommandPort, 0x11);
+
+ // ICW2
+ outb(MasterDataPort, MasterOffset);
+ outb(SlaveDataPort, SlaveOffset);
+
+ // ICW3
+ outb(MasterDataPort, 0x04);
+ outb(SlaveDataPort, 0x02);
+
+ // ICW4
+ outb(MasterDataPort, 0x01);
+ outb(SlaveDataPort, 0x01);
+
+ // OCW1
+ outb(MasterDataPort, MasterMask);
+ outb(SlaveDataPort, SlaveMask);
+ }
+
+ PIC::~PIC()
+ {
+ outb(MasterDataPort, 0xFF);
+ outb(SlaveDataPort, 0xFF);
+ }
+
+ void PIC::Mask(uint8_t IRQ)
+ {
+ uint16_t Port;
+ uint8_t Value;
+
+ if (IRQ < 8)
+ {
+ Port = MasterDataPort;
+ Value = MasterMask & ~(1 << IRQ);
+ MasterMask = Value;
+ }
+ else
+ {
+ Port = SlaveDataPort;
+ Value = SlaveMask & ~(1 << (IRQ - 8));
+ SlaveMask = Value;
+ }
+
+ outb(Port, Value);
+ }
+
+ void PIC::Unmask(uint8_t IRQ)
+ {
+ uint16_t Port;
+ uint8_t Value;
+
+ if (IRQ < 8)
+ {
+ Port = MasterDataPort;
+ Value = MasterMask | (1 << IRQ);
+ MasterMask = Value;
+ }
+ else
+ {
+ Port = SlaveDataPort;
+ Value = SlaveMask | (1 << (IRQ - 8));
+ SlaveMask = Value;
+ }
+
+ outb(Port, Value);
+ }
+
+ void PIC::SendEOI(uint8_t IRQ)
+ {
+ if (IRQ >= 8)
+ outb(SlaveCommandPort, 0x20);
+
+ outb(MasterCommandPort, 0x20);
+ }
+
+ PIT::PIT(uint16_t Port, uint16_t Frequency)
+ {
+ this->Port = Port;
+ this->Frequency = Frequency;
+ }
+
+ PIT::~PIT()
+ {
+ }
+
+ void PIT::PrepareSleep(uint32_t Milliseconds)
+ {
+ uint16_t Divisor = 1193182 / Frequency;
+ uint8_t Low = (uint8_t)(Divisor & 0xFF);
+ uint8_t High = (uint8_t)((Divisor >> 8) & 0xFF);
+
+ outb(Port + 3, 0x36);
+ outb(Port + 0, Low);
+ outb(Port + 1, High);
+ }
+
+ void PIT::PerformSleep()
+ {
+ uint8_t Value = inb(Port + 0);
+ while (Value != 0)
+ Value = inb(Port + 0);
+ }
+}
diff --git a/Kernel/Architecture/i386/Interrupts/pic.hpp b/Kernel/Architecture/i386/Interrupts/pic.hpp
new file mode 100644
index 00000000..fb0e5f1a
--- /dev/null
+++ b/Kernel/Architecture/i386/Interrupts/pic.hpp
@@ -0,0 +1,59 @@
+/*
+ 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 .
+*/
+
+#ifndef __FENNIX_KERNEL_8259PIC_H__
+#define __FENNIX_KERNEL_8259PIC_H__
+
+#include
+
+namespace PIC
+{
+ class PIC
+ {
+ private:
+ uint8_t MasterCommandPort;
+ uint8_t MasterDataPort;
+ uint8_t SlaveCommandPort;
+ uint8_t SlaveDataPort;
+ uint8_t MasterOffset;
+ uint8_t SlaveOffset;
+ uint8_t MasterMask;
+ uint8_t SlaveMask;
+
+ public:
+ PIC(uint8_t MasterCommandPort, uint8_t MasterDataPort, uint8_t SlaveCommandPort, uint8_t SlaveDataPort, uint8_t MasterOffset, uint8_t SlaveOffset);
+ ~PIC();
+ void Mask(uint8_t IRQ);
+ void Unmask(uint8_t IRQ);
+ void SendEOI(uint8_t IRQ);
+ };
+
+ class PIT
+ {
+ private:
+ uint16_t Port;
+ uint16_t Frequency;
+
+ public:
+ PIT(uint16_t Port, uint16_t Frequency);
+ ~PIT();
+ void PrepareSleep(uint32_t Milliseconds);
+ void PerformSleep();
+ };
+}
+
+#endif // !__FENNIX_KERNEL_8259PIC_H__
diff --git a/Kernel/Architecture/i386/SystemCalls.cpp b/Kernel/Architecture/i386/SystemCalls.cpp
new file mode 100644
index 00000000..cc9c5007
--- /dev/null
+++ b/Kernel/Architecture/i386/SystemCalls.cpp
@@ -0,0 +1,30 @@
+/*
+ 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 .
+*/
+
+#include
+
+#include
+
+#include "cpu/gdt.hpp"
+
+using namespace CPU::x32;
+
+extern "C" uint32_t SystemCallsHandler(SyscallsFrame *regs);
+
+void InitializeSystemCalls()
+{
+}
diff --git a/Kernel/Architecture/i386/acpi.hpp b/Kernel/Architecture/i386/acpi.hpp
new file mode 100644
index 00000000..1a71f712
--- /dev/null
+++ b/Kernel/Architecture/i386/acpi.hpp
@@ -0,0 +1,294 @@
+/*
+ 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 .
+*/
+
+#ifndef __FENNIX_KERNEL_ACPI_H__
+#define __FENNIX_KERNEL_ACPI_H__
+
+#include
+
+#include
+#include
+#include
+#include
+
+namespace ACPI
+{
+ class ACPI
+ {
+ public:
+ struct ACPIHeader
+ {
+ unsigned char Signature[4];
+ uint32_t Length;
+ uint8_t Revision;
+ uint8_t Checksum;
+ uint8_t OEMID[6];
+ uint8_t OEMTableID[8];
+ uint32_t OEMRevision;
+ uint32_t CreatorID;
+ uint32_t CreatorRevision;
+ } __packed;
+
+ struct GenericAddressStructure
+ {
+ uint8_t AddressSpace;
+ uint8_t BitWidth;
+ uint8_t BitOffset;
+ uint8_t AccessSize;
+ uint64_t Address;
+ } __packed;
+
+ struct MCFGHeader
+ {
+ struct ACPIHeader Header;
+ uint64_t Reserved;
+ } __packed;
+
+ struct HPETHeader
+ {
+ ACPIHeader Header;
+ uint8_t HardwareRevID;
+ uint8_t ComparatorCount : 5;
+ uint8_t CounterSize : 1;
+ uint8_t Reserved : 1;
+ uint8_t LegacyReplacement : 1;
+ uint16_t PCIVendorID;
+ struct GenericAddressStructure Address;
+ uint8_t HPETNumber;
+ uint16_t MinimumTick;
+ uint8_t PageProtection;
+ } __packed;
+
+ struct FADTHeader
+ {
+ ACPIHeader Header;
+ uint32_t FirmwareCtrl;
+ uint32_t Dsdt;
+ uint8_t Reserved;
+ uint8_t PreferredPowerManagementProfile;
+ uint16_t SCI_Interrupt;
+ uint32_t SMI_CommandPort;
+ uint8_t AcpiEnable;
+ uint8_t AcpiDisable;
+ uint8_t S4BIOS_REQ;
+ uint8_t PSTATE_Control;
+ uint32_t PM1aEventBlock;
+ uint32_t PM1bEventBlock;
+ uint32_t PM1aControlBlock;
+ uint32_t PM1bControlBlock;
+ uint32_t PM2ControlBlock;
+ uint32_t PMTimerBlock;
+ uint32_t GPE0Block;
+ uint32_t GPE1Block;
+ uint8_t PM1EventLength;
+ uint8_t PM1ControlLength;
+ uint8_t PM2ControlLength;
+ uint8_t PMTimerLength;
+ uint8_t GPE0Length;
+ uint8_t GPE1Length;
+ uint8_t GPE1Base;
+ uint8_t CStateControl;
+ uint16_t WorstC2Latency;
+ uint16_t WorstC3Latency;
+ uint16_t FlushSize;
+ uint16_t FlushStride;
+ uint8_t DutyOffset;
+ uint8_t DutyWidth;
+ uint8_t DayAlarm;
+ uint8_t MonthAlarm;
+ uint8_t Century;
+ uint16_t BootArchitectureFlags;
+ uint8_t Reserved2;
+ uint32_t Flags;
+ struct GenericAddressStructure ResetReg;
+ uint8_t ResetValue;
+ uint8_t Reserved3[3];
+ uint64_t X_FirmwareControl;
+ uint64_t X_Dsdt;
+ struct GenericAddressStructure X_PM1aEventBlock;
+ struct GenericAddressStructure X_PM1bEventBlock;
+ struct GenericAddressStructure X_PM1aControlBlock;
+ struct GenericAddressStructure X_PM1bControlBlock;
+ struct GenericAddressStructure X_PM2ControlBlock;
+ struct GenericAddressStructure X_PMTimerBlock;
+ struct GenericAddressStructure X_GPE0Block;
+ struct GenericAddressStructure X_GPE1Block;
+ } __packed;
+
+ struct BGRTHeader
+ {
+ ACPIHeader Header;
+ uint16_t Version;
+ uint8_t Status;
+ uint8_t ImageType;
+ uint64_t ImageAddress;
+ uint32_t ImageOffsetX;
+ uint32_t ImageOffsetY;
+ };
+
+ struct SRATHeader
+ {
+ ACPIHeader Header;
+ uint32_t TableRevision; // Must be value 1
+ uint64_t Reserved; // Reserved, must be zero
+ };
+
+ struct TPM2Header
+ {
+ ACPIHeader Header;
+ uint32_t Flags;
+ uint64_t ControlAddress;
+ uint32_t StartMethod;
+ };
+
+ struct TCPAHeader
+ {
+ ACPIHeader Header;
+ uint16_t Reserved;
+ uint32_t MaxLogLength;
+ uint64_t LogAddress;
+ };
+
+ struct WAETHeader
+ {
+ ACPIHeader Header;
+ uint32_t Flags;
+ };
+
+ struct HESTHeader
+ {
+ ACPIHeader Header;
+ uint32_t ErrorSourceCount;
+ };
+
+ struct MADTHeader
+ {
+ ACPIHeader Header;
+ uint32_t LocalControllerAddress;
+ uint32_t Flags;
+ char Entries[];
+ } __packed;
+
+ ACPIHeader *XSDT = nullptr;
+ MCFGHeader *MCFG = nullptr;
+ HPETHeader *HPET = nullptr;
+ FADTHeader *FADT = nullptr;
+ BGRTHeader *BGRT = nullptr;
+ SRATHeader *SRAT = nullptr;
+ TPM2Header *TPM2 = nullptr;
+ TCPAHeader *TCPA = nullptr;
+ WAETHeader *WAET = nullptr;
+ MADTHeader *MADT = nullptr;
+ HESTHeader *HEST = nullptr;
+ bool XSDTSupported = false;
+
+ void *FindTable(ACPIHeader *ACPIHeader, char *Signature);
+ void SearchTables(ACPIHeader *Header);
+ ACPI();
+ ~ACPI();
+ };
+
+ class MADT
+ {
+ public:
+ struct APICHeader
+ {
+ uint8_t Type;
+ uint8_t Length;
+ } __packed;
+
+ struct MADTIOApic
+ {
+ struct APICHeader Header;
+ uint8_t APICID;
+ uint8_t reserved;
+ uint32_t Address;
+ uint32_t GSIBase;
+ } __packed;
+
+ struct MADTIso
+ {
+ struct APICHeader Header;
+ uint8_t BuSSource;
+ uint8_t IRQSource;
+ uint32_t GSI;
+ uint16_t Flags;
+ } __packed;
+
+ struct MADTNmi
+ {
+ struct APICHeader Header;
+ uint8_t processor;
+ uint16_t flags;
+ uint8_t lint;
+ } __packed;
+
+ struct LocalAPIC
+ {
+ struct APICHeader Header;
+ uint8_t ACPIProcessorId;
+ uint8_t APICId;
+ uint32_t Flags;
+ } __packed;
+
+ struct LAPIC
+ {
+ uint8_t id;
+ uintptr_t PhysicalAddress;
+ void *VirtualAddress;
+ };
+
+ std::vector ioapic;
+ std::vector iso;
+ std::vector nmi;
+ std::vector lapic;
+ struct LAPIC *LAPICAddress;
+ uint16_t CPUCores;
+
+ MADT(ACPI::MADTHeader *madt);
+ ~MADT();
+ };
+
+ class DSDT : public Interrupts::Handler
+ {
+ private:
+ uint32_t SMI_CMD = 0;
+ uint8_t ACPI_ENABLE = 0;
+ uint8_t ACPI_DISABLE = 0;
+ uint32_t PM1a_CNT = 0;
+ uint32_t PM1b_CNT = 0;
+ uint16_t SLP_TYPa = 0;
+ uint16_t SLP_TYPb = 0;
+ uint16_t SLP_EN = 0;
+ uint16_t SCI_EN = 0;
+ uint8_t PM1_CNT_LEN = 0;
+
+ ACPI *acpi;
+ void OnInterruptReceived(CPU::x64::TrapFrame *Frame);
+
+ public:
+ bool ACPIShutdownSupported = false;
+
+ void Reboot();
+ void Shutdown();
+
+ DSDT(ACPI *acpi);
+ ~DSDT();
+ };
+}
+
+#endif // !__FENNIX_KERNEL_ACPI_H__
diff --git a/Kernel/Architecture/i386/cpu/GlobalDescriptorTable.cpp b/Kernel/Architecture/i386/cpu/GlobalDescriptorTable.cpp
new file mode 100644
index 00000000..d7cb3d0d
--- /dev/null
+++ b/Kernel/Architecture/i386/cpu/GlobalDescriptorTable.cpp
@@ -0,0 +1,116 @@
+/*
+ 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 .
+*/
+
+#include "gdt.hpp"
+
+#include
+#include
+#include
+#include
+
+namespace GlobalDescriptorTable
+{
+ static GlobalDescriptorTableEntries GDTEntriesTemplate = {
+ // null
+ {.Length = 0x0,
+ .BaseLow = 0x0,
+ .BaseMiddle = 0x0,
+ .Access = {.Raw = 0x0},
+ .Flags = {.Raw = 0x0},
+ .BaseHigh = 0x0},
+
+ // kernel code
+ {.Length = 0x0,
+ .BaseLow = 0x0,
+ .BaseMiddle = 0x0,
+ .Access = {.A = 0,
+ .RW = 1,
+ .DC = 0,
+ .E = 1,
+ .S = 1,
+ .DPL = 0,
+ .P = 1},
+ .Flags = {.Unknown = 0x0, .L = 1},
+ .BaseHigh = 0x0},
+
+ // kernel data
+ {.Length = 0x0,
+ .BaseLow = 0x0,
+ .BaseMiddle = 0x0,
+ .Access = {.A = 0,
+ .RW = 1,
+ .DC = 0,
+ .E = 0,
+ .S = 1,
+ .DPL = 0,
+ .P = 1},
+ .Flags = {.Raw = 0x0},
+ .BaseHigh = 0x0},
+
+ // user data
+ {.Length = 0x0,
+ .BaseLow = 0x0,
+ .BaseMiddle = 0x0,
+ .Access = {.A = 0,
+ .RW = 1,
+ .DC = 0,
+ .E = 0,
+ .S = 1,
+ .DPL = 3,
+ .P = 1},
+ .Flags = {.Raw = 0x0},
+ .BaseHigh = 0x0},
+
+ // user code
+ {.Length = 0x0,
+ .BaseLow = 0x0,
+ .BaseMiddle = 0x0,
+ .Access = {.A = 0,
+ .RW = 1,
+ .DC = 0,
+ .E = 1,
+ .S = 1,
+ .DPL = 3,
+ .P = 1},
+ .Flags = {.Unknown = 0x0, .L = 1},
+ .BaseHigh = 0x0},
+
+ // tss
+ {}};
+
+ GlobalDescriptorTableEntries GDTEntries[MAX_CPU];
+ GlobalDescriptorTableDescriptor gdt[MAX_CPU];
+
+ TaskStateSegment tss[MAX_CPU] = {
+ 0,
+ {0, 0, 0},
+ 0,
+ {0, 0, 0, 0, 0, 0, 0},
+ 0,
+ 0,
+ };
+
+ void *CPUStackPointer[MAX_CPU];
+
+ SafeFunction void Init(int Core)
+ {
+ }
+
+ SafeFunction void SetKernelStack(void *Stack)
+ {
+ }
+}
diff --git a/Kernel/Architecture/i386/cpu/SymmetricMultiprocessing.cpp b/Kernel/Architecture/i386/cpu/SymmetricMultiprocessing.cpp
new file mode 100644
index 00000000..eff12718
--- /dev/null
+++ b/Kernel/Architecture/i386/cpu/SymmetricMultiprocessing.cpp
@@ -0,0 +1,54 @@
+/*
+ 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 .
+*/
+
+#include
+
+#include
+#include
+#include
+#include
+
+#include "../../../kernel.h"
+
+volatile bool CPUEnabled = false;
+
+#pragma GCC diagnostic ignored "-Wmissing-field-initializers"
+static __aligned(0x1000) CPUData CPUs[MAX_CPU] = {0};
+
+CPUData *GetCPU(uint64_t id) { return &CPUs[id]; }
+
+CPUData *GetCurrentCPU()
+{
+ uint64_t ret = 0;
+ if (!(&CPUs[ret])->IsActive)
+ {
+ // error("CPU %d is not active!", ret);
+ return &CPUs[0];
+ }
+ assert((&CPUs[ret])->Checksum == CPU_DATA_CHECKSUM);
+ return &CPUs[ret];
+}
+
+namespace SMP
+{
+ int CPUCores = 0;
+
+ void Initialize(void *madt)
+ {
+ fixme("SMP::Initialize() is not implemented!");
+ }
+}
diff --git a/Kernel/Architecture/i386/cpu/apic.hpp b/Kernel/Architecture/i386/cpu/apic.hpp
new file mode 100644
index 00000000..24887b48
--- /dev/null
+++ b/Kernel/Architecture/i386/cpu/apic.hpp
@@ -0,0 +1,354 @@
+/*
+ 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 .
+*/
+
+#ifndef __FENNIX_KERNEL_APIC_H__
+#define __FENNIX_KERNEL_APIC_H__
+
+#include
+
+#include
+#include
+
+namespace APIC
+{
+ enum APICRegisters
+ {
+ // source from: https://github.com/pdoane/osdev/blob/master/intr/local_apic.c
+ APIC_ID = 0x20, // Local APIC ID
+ APIC_VER = 0x30, // Local APIC Version
+ APIC_TPR = 0x80, // Task Priority
+ APIC_APR = 0x90, // Arbitration Priority
+ APIC_PPR = 0xA0, // Processor Priority
+ APIC_EOI = 0xB0, // EOI
+ APIC_RRD = 0xC0, // Remote Read
+ APIC_LDR = 0xD0, // Logical Destination
+ APIC_DFR = 0xE0, // Destination Format
+ APIC_SVR = 0xF0, // Spurious Interrupt Vector
+ APIC_ISR = 0x100, // In-Service (8 registers)
+ APIC_TMR = 0x180, // Trigger Mode (8 registers)
+ APIC_IRR = 0x200, // Interrupt Request (8 registers)
+ APIC_ESR = 0x280, // Error Status
+ APIC_ICRLO = 0x300, // Interrupt Command
+ APIC_ICRHI = 0x310, // Interrupt Command [63:32]
+ APIC_TIMER = 0x320, // LVT Timer
+ APIC_THERMAL = 0x330, // LVT Thermal Sensor
+ APIC_PERF = 0x340, // LVT Performance Counter
+ APIC_LINT0 = 0x350, // LVT LINT0
+ APIC_LINT1 = 0x360, // LVT LINT1
+ APIC_ERROR = 0x370, // LVT Error
+ APIC_TICR = 0x380, // Initial Count (for Timer)
+ APIC_TCCR = 0x390, // Current Count (for Timer)
+ APIC_TDCR = 0x3E0, // Divide Configuration (for Timer)
+ };
+
+ enum IOAPICRegisters
+ {
+ GetIOAPICVersion = 0x1
+ };
+
+ enum IOAPICFlags
+ {
+ ActiveHighLow = 2,
+ EdgeLevel = 8
+ };
+
+ enum APICDeliveryMode
+ {
+ Fixed = 0b000,
+ LowestPriority = 0b001, /* Reserved */
+ SMI = 0b010,
+ APIC_DELIVERY_MODE_RESERVED0 = 0b011, /* Reserved */
+ NMI = 0b100,
+ INIT = 0b101,
+ Startup = 0b110,
+ ExtINT = 0b111 /* Reserved */
+ };
+
+ enum APICDestinationMode
+ {
+ Physical = 0b0,
+ Logical = 0b1
+ };
+
+ enum APICDeliveryStatus
+ {
+ Idle = 0b0,
+ SendPending = 0b1
+ };
+
+ enum APICLevel
+ {
+ DeAssert = 0b0,
+ Assert = 0b1
+ };
+
+ enum APICTriggerMode
+ {
+ Edge = 0b0,
+ Level = 0b1
+ };
+
+ enum APICDestinationShorthand
+ {
+ NoShorthand = 0b00,
+ Self = 0b01,
+ AllIncludingSelf = 0b10,
+ AllExcludingSelf = 0b11
+ };
+
+ enum LVTTimerDivide
+ {
+ DivideBy2 = 0b000,
+ DivideBy4 = 0b001,
+ DivideBy8 = 0b010,
+ DivideBy16 = 0b011,
+ DivideBy32 = 0b100,
+ DivideBy64 = 0b101,
+ DivideBy128 = 0b110,
+ DivideBy1 = 0b111
+ };
+
+ enum LVTTimerMask
+ {
+ Unmasked = 0b0,
+ Masked = 0b1
+ };
+
+ enum LVTTimerMode
+ {
+ OneShot = 0b00,
+ Periodic = 0b01,
+ TSCDeadline = 0b10
+ };
+
+ typedef union
+ {
+ struct
+ {
+ /** @brief Interrupt Vector */
+ uint64_t Vector : 8;
+ /** @brief Reserved */
+ uint64_t Reserved0 : 4;
+ /**
+ * @brief Delivery Status
+ *
+ * 0: Idle
+ * 1: Send Pending
+ */
+ uint64_t DeliveryStatus : 1;
+ /** @brief Reserved */
+ uint64_t Reserved1 : 3;
+ /**
+ * @brief Mask
+ *
+ * 0: Not masked
+ * 1: Masked
+ */
+ uint64_t Mask : 1;
+ /** @brief Timer Mode
+ *
+ * 0: One-shot
+ * 1: Periodic
+ * 2: TSC-Deadline
+ */
+ uint64_t TimerMode : 1;
+ /** @brief Reserved */
+ uint64_t Reserved2 : 14;
+ };
+ uint64_t raw;
+ } __packed LVTTimer;
+
+ typedef union
+ {
+ struct
+ {
+ /** @brief Spurious Vector */
+ uint64_t Vector : 8;
+ /** @brief Enable or disable APIC software */
+ uint64_t Software : 1;
+ /** @brief Focus Processor Checking */
+ uint64_t FocusProcessorChecking : 1;
+ /** @brief Reserved */
+ uint64_t Reserved : 2;
+ /** @brief Disable EOI Broadcast */
+ uint64_t DisableEOIBroadcast : 1;
+ /** @brief Reserved */
+ uint64_t Reserved1 : 19;
+ };
+ uint64_t raw;
+ } __packed Spurious;
+
+ typedef union
+ {
+ struct
+ {
+ /** @brief Interrupt Vector */
+ uint64_t Vector : 8;
+ /** @brief Delivery Mode */
+ uint64_t DeliveryMode : 3;
+ /** @brief Destination Mode
+ *
+ * 0: Physical
+ * 1: Logical
+ */
+ uint64_t DestinationMode : 1;
+ /** @brief Delivery Status
+ *
+ * @note Reserved when in x2APIC mode
+ */
+ uint64_t DeliveryStatus : 1;
+ /** @brief Reserved */
+ uint64_t Reserved0 : 1;
+ /** @brief Level
+ *
+ * 0: Deassert
+ * 1: Assert
+ */
+ uint64_t Level : 1;
+ /** @brief Trigger Mode
+ *
+ * 0: Edge
+ * 1: Level
+ */
+ uint64_t TriggerMode : 1;
+ /** @brief Reserved */
+ uint64_t Reserved1 : 2;
+ /** @brief Destination Shorthand
+ *
+ * 0: No shorthand
+ * 1: Self
+ * 2: All including self
+ * 3: All excluding self
+ */
+ uint64_t DestinationShorthand : 2;
+ /** @brief Reserved */
+ uint64_t Reserved2 : 12;
+ };
+ uint64_t raw;
+ } __packed InterruptCommandRegisterLow;
+
+ typedef union
+ {
+ struct
+ {
+ /** @brief Reserved */
+ uint64_t Reserved0 : 24;
+ /** @brief Destination */
+ uint64_t Destination : 8;
+ };
+ uint64_t raw;
+ } __packed InterruptCommandRegisterHigh;
+
+ typedef union
+ {
+ struct
+ {
+ /** @brief Interrupt Vector */
+ uint64_t Vector : 8;
+ /** @brief Delivery Mode */
+ uint64_t DeliveryMode : 3;
+ /** @brief Destination Mode
+ *
+ * 0: Physical
+ * 1: Logical
+ */
+ uint64_t DestinationMode : 1;
+ /** @brief Delivery Status */
+ uint64_t DeliveryStatus : 1;
+ /** @brief Interrupt Input Pin Polarity
+ *
+ * 0: Active High
+ * 1: Active Low
+ */
+ uint64_t Polarity : 1;
+ /** @brief Remote IRR */
+ uint64_t RemoteIRR : 1;
+ /** @brief Trigger Mode
+ *
+ * 0: Edge
+ * 1: Level
+ */
+ uint64_t TriggerMode : 1;
+ /** @brief Mask */
+ uint64_t Mask : 1;
+ /** @brief Reserved */
+ uint64_t Reserved0 : 15;
+ /** @brief Reserved */
+ uint64_t Reserved1 : 24;
+ /** @brief Destination */
+ uint64_t DestinationID : 8;
+ };
+ struct
+ {
+ uint64_t Low;
+ uint64_t High;
+ } split;
+ uint64_t raw;
+ } __packed IOAPICRedirectEntry;
+
+ typedef union
+ {
+ struct
+ {
+ uint64_t Version : 8;
+ uint64_t Reserved : 8;
+ uint64_t MaximumRedirectionEntry : 8;
+ uint64_t Reserved2 : 8;
+ };
+ uint64_t raw;
+ } __packed IOAPICVersion;
+
+ class APIC
+ {
+ private:
+ bool x2APICSupported = false;
+ uint64_t APICBaseAddress = 0;
+
+ public:
+ uint32_t Read(uint32_t Register);
+ void Write(uint32_t Register, uint32_t Value);
+ void IOWrite(uint64_t Base, uint32_t Register, uint32_t Value);
+ uint32_t IORead(uint64_t Base, uint32_t Register);
+ void EOI();
+ void RedirectIRQs(int CPU = 0);
+ void WaitForIPI();
+ void IPI(uint8_t CPU, InterruptCommandRegisterLow icr);
+ void SendInitIPI(uint8_t CPU);
+ void SendStartupIPI(uint8_t CPU, uint64_t StartupAddress);
+ uint32_t IOGetMaxRedirect(uint32_t APICID);
+ void RawRedirectIRQ(uint8_t Vector, uint32_t GSI, uint16_t Flags, int CPU, int Status);
+ void RedirectIRQ(int CPU, uint16_t IRQ, int Status);
+ APIC(int Core);
+ ~APIC();
+ };
+
+ class Timer : public Interrupts::Handler
+ {
+ private:
+ APIC *lapic;
+ uint64_t Ticks = 0;
+ void OnInterruptReceived(CPU::x32::TrapFrame *Frame);
+
+ public:
+ uint64_t GetTicks() { return Ticks; }
+ void OneShot(uint32_t Vector, uint64_t Miliseconds);
+ Timer(APIC *apic);
+ ~Timer();
+ };
+}
+
+#endif // !__FENNIX_KERNEL_APIC_H__
diff --git a/Kernel/Architecture/i386/cpu/gdt.hpp b/Kernel/Architecture/i386/cpu/gdt.hpp
new file mode 100644
index 00000000..92e43015
--- /dev/null
+++ b/Kernel/Architecture/i386/cpu/gdt.hpp
@@ -0,0 +1,162 @@
+/*
+ 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 .
+*/
+
+#ifndef __FENNIX_KERNEL_GDT_H__
+#define __FENNIX_KERNEL_GDT_H__
+
+#include
+
+namespace GlobalDescriptorTable
+{
+ /** @brief The GDT Access Table
+ * @details For more information, see https://wiki.osdev.org/Global_Descriptor_Table
+ */
+ union GlobalDescriptorTableAccess
+ {
+ struct
+ {
+ /** @brief Access bit.
+ * @note The CPU sets this bit to 1 when the segment is accessed.
+ */
+ uint8_t A : 1;
+
+ /** @brief Readable bit for code segments, writable bit for data segments.
+ * @details For code segments, this bit must be 1 for the segment to be readable.
+ * @details For data segments, this bit must be 1 for the segment to be writable.
+ */
+ uint8_t RW : 1;
+
+ /** @brief Direction bit for data segments, conforming bit for code segments.
+ * @details For data segments, this bit must be 1 for the segment to grow up (higher addresses).
+ * @details For code segments, this bit must be 1 for code in the segment to be able to be executed from an equal or lower privilege level.
+ */
+ uint8_t DC : 1;
+
+ /** @brief Executable bit.
+ * @details This bit must be 1 for code-segment descriptors.
+ * @details This bit must be 0 for data-segment and system descriptors.
+ */
+ uint8_t E : 1;
+
+ /** @brief Descriptor type.
+ * @details This bit must be 0 for system descriptors.
+ * @details This bit must be 1 for code or data segment descriptor.
+ */
+ uint8_t S : 1;
+
+ /** @brief Descriptor privilege level.
+ * @details This field determines the privilege level of the segment.
+ * @details 0 = kernel mode, 3 = user mode.
+ */
+ uint8_t DPL : 2;
+
+ /** @brief Present bit.
+ * @details This bit must be 1 for all valid descriptors.
+ */
+ uint8_t P : 1;
+ } __packed;
+ uint8_t Raw;
+ };
+
+ union GlobalDescriptorTableFlags
+ {
+ // TODO: Add more flags.
+ struct
+ {
+ /** @brief Unknown. */
+ uint8_t Unknown : 5;
+
+ /** @brief Long mode.
+ * @details If the long mode bit is clear, the segment is in 32-bit protected mode.
+ * @details If the long mode bit is set, the segment is in 64-bit long mode.
+ */
+ uint8_t L : 1;
+ } __packed;
+ uint8_t Raw;
+ };
+
+ typedef struct _TaskStateSegmentEntry
+ {
+ /* LOW */
+ uint16_t Length;
+ uint16_t BaseLow;
+ uint8_t BaseMiddle;
+ GlobalDescriptorTableAccess Flags;
+ uint8_t Granularity;
+ uint8_t BaseHigh;
+ /* HIGH */
+ uint32_t BaseUpper;
+ uint32_t Reserved;
+ } __packed TaskStateSegmentEntry;
+
+ typedef struct _TaskStateSegment
+ {
+ uint32_t Reserved0 __aligned(16);
+ uint64_t StackPointer[3];
+ uint64_t Reserved1;
+ uint64_t InterruptStackTable[7];
+ uint16_t Reserved2;
+ uint16_t IOMapBaseAddressOffset;
+ } __packed TaskStateSegment;
+
+ typedef struct _GlobalDescriptorTableEntry
+ {
+ /** @brief Length */
+ uint16_t Length;
+ /** @brief Low Base */
+ uint16_t BaseLow;
+ /** @brief Middle Base */
+ uint8_t BaseMiddle;
+ /** @brief Access */
+ GlobalDescriptorTableAccess Access;
+ /** @brief Flags */
+ GlobalDescriptorTableFlags Flags;
+ /** @brief High Base */
+ uint8_t BaseHigh;
+ } __packed GlobalDescriptorTableEntry;
+
+ typedef struct _GlobalDescriptorTableEntries
+ {
+ GlobalDescriptorTableEntry Null;
+ GlobalDescriptorTableEntry Code;
+ GlobalDescriptorTableEntry Data;
+ GlobalDescriptorTableEntry UserData;
+ GlobalDescriptorTableEntry UserCode;
+ TaskStateSegmentEntry TaskStateSegment;
+ } __packed GlobalDescriptorTableEntries;
+
+ typedef struct _GlobalDescriptorTableDescriptor
+ {
+ /** @brief GDT entries length */
+ uint16_t Length;
+ /** @brief GDT entries address */
+ GlobalDescriptorTableEntries *Entries;
+ } __packed GlobalDescriptorTableDescriptor;
+
+ extern void *CPUStackPointer[];
+ extern TaskStateSegment tss[];
+ void Init(int Core);
+ void SetKernelStack(void *Stack);
+}
+
+#define GDT_KERNEL_CODE offsetof(GlobalDescriptorTable::GlobalDescriptorTableEntries, Code)
+#define GDT_KERNEL_DATA offsetof(GlobalDescriptorTable::GlobalDescriptorTableEntries, Data)
+#define GDT_USER_CODE (offsetof(GlobalDescriptorTable::GlobalDescriptorTableEntries, UserCode) | 3)
+#define GDT_USER_DATA (offsetof(GlobalDescriptorTable::GlobalDescriptorTableEntries, UserData) | 3)
+#define GDT_TSS (offsetof(GlobalDescriptorTable::GlobalDescriptorTableEntries, TaskStateSegment) | 3)
+
+#endif // !__FENNIX_KERNEL_GDT_H__
diff --git a/Kernel/Architecture/i386/cpu/idt.hpp b/Kernel/Architecture/i386/cpu/idt.hpp
new file mode 100644
index 00000000..204072aa
--- /dev/null
+++ b/Kernel/Architecture/i386/cpu/idt.hpp
@@ -0,0 +1,28 @@
+/*
+ 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 .
+*/
+
+#ifndef __FENNIX_KERNEL_IDT_H__
+#define __FENNIX_KERNEL_IDT_H__
+
+#include
+
+namespace InterruptDescriptorTable
+{
+ void Init(int Core);
+}
+
+#endif // !__FENNIX_KERNEL_IDT_H__
diff --git a/Kernel/Architecture/i386/linker.ld b/Kernel/Architecture/i386/linker.ld
new file mode 100644
index 00000000..2e427dd4
--- /dev/null
+++ b/Kernel/Architecture/i386/linker.ld
@@ -0,0 +1,93 @@
+/*
+ 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 .
+*/
+
+OUTPUT_FORMAT(elf32-i386)
+OUTPUT_ARCH(i386)
+
+KERNEL_VMA = 0xC0000000;
+
+ENTRY(_start)
+
+SECTIONS
+{
+ . = 0x100000;
+
+ _bootstrap_start = .;
+ .bootstrap :
+ {
+ *(.multiboot)
+ *(.multiboot2)
+ *(.bootstrap .bootstrap.*)
+ }
+ . += CONSTANT(MAXPAGESIZE);
+ _bootstrap_end = ALIGN(CONSTANT(MAXPAGESIZE));
+
+ . += KERNEL_VMA;
+ . += CONSTANT(MAXPAGESIZE);
+ _kernel_start = ALIGN(CONSTANT(MAXPAGESIZE));
+ .text : AT(ADDR(.text) - KERNEL_VMA)
+ {
+ *(.text .text.*)
+ }
+ _kernel_text_end = ALIGN(CONSTANT(MAXPAGESIZE));
+ . += CONSTANT(MAXPAGESIZE);
+
+ .data : AT(ADDR(.data) - KERNEL_VMA)
+ {
+ *(.data .data.*)
+ }
+ _kernel_data_end = ALIGN(CONSTANT(MAXPAGESIZE));
+ . += CONSTANT(MAXPAGESIZE);
+
+ .rodata : AT(ADDR(.rodata) - KERNEL_VMA)
+ {
+ *(.rodata .rodata.*)
+ }
+ _kernel_rodata_end = ALIGN(CONSTANT(MAXPAGESIZE));
+ . += CONSTANT(MAXPAGESIZE);
+
+ .init_array : AT(ADDR(.init_array) - KERNEL_VMA)
+ {
+ PROVIDE_HIDDEN(__init_array_start = .);
+ KEEP(*(.init_array .ctors))
+ KEEP(*(SORT_BY_INIT_PRIORITY(.init_array.*) SORT_BY_INIT_PRIORITY(.ctors.*)))
+ PROVIDE_HIDDEN (__init_array_end = .);
+ }
+
+ .fini_array : AT(ADDR(.fini_array) - KERNEL_VMA)
+ {
+ PROVIDE_HIDDEN(__fini_array_start = .);
+ KEEP(*(SORT_BY_INIT_PRIORITY(.fini_array.*) SORT_BY_INIT_PRIORITY(.dtors.*)))
+ KEEP(*(.fini_array .dtors))
+ PROVIDE_HIDDEN (__fini_array_end = .);
+ }
+ . += CONSTANT(MAXPAGESIZE);
+
+ .bss : AT(ADDR(.bss) - KERNEL_VMA)
+ {
+ *(COMMON)
+ *(.bss .bss.*)
+ }
+ . += CONSTANT(MAXPAGESIZE);
+ _kernel_end = ALIGN(CONSTANT(MAXPAGESIZE));
+
+ /DISCARD/ :
+ {
+ *(.comment*)
+ *(.note*)
+ }
+}
diff --git a/Kernel/Architecture/i386/runtime/crt0.c b/Kernel/Architecture/i386/runtime/crt0.c
new file mode 100644
index 00000000..35cf1abd
--- /dev/null
+++ b/Kernel/Architecture/i386/runtime/crt0.c
@@ -0,0 +1,15 @@
+// #include
+
+// #include
+
+// int Entry(void *Info);
+
+// void _start(void *Raw)
+// {
+// error("Todo");
+// while (1)
+// asmv("hlt");
+// Entry(NULL);
+// return;
+// }
+// C stuff
\ No newline at end of file
diff --git a/Kernel/Architecture/i386/runtime/crt1.c b/Kernel/Architecture/i386/runtime/crt1.c
new file mode 100644
index 00000000..1369bfeb
--- /dev/null
+++ b/Kernel/Architecture/i386/runtime/crt1.c
@@ -0,0 +1,15 @@
+#include
+
+#include
+
+int Entry(void *Info);
+
+// void _start(void *Raw)
+// {
+// UNUSED(Raw);
+// error("ERROR! INVALID BOOT PROTOCOL!");
+// while (1)
+// asmv("hlt");
+// Entry(NULL);
+// return;
+// }
diff --git a/Kernel/Architecture/i386/runtime/crtbegin.c b/Kernel/Architecture/i386/runtime/crtbegin.c
new file mode 100644
index 00000000..507125b3
--- /dev/null
+++ b/Kernel/Architecture/i386/runtime/crtbegin.c
@@ -0,0 +1 @@
+// C++ constructor/destructor stuff
\ No newline at end of file
diff --git a/Kernel/Architecture/i386/runtime/crtend.c b/Kernel/Architecture/i386/runtime/crtend.c
new file mode 100644
index 00000000..507125b3
--- /dev/null
+++ b/Kernel/Architecture/i386/runtime/crtend.c
@@ -0,0 +1 @@
+// C++ constructor/destructor stuff
\ No newline at end of file
diff --git a/Kernel/Architecture/i386/runtime/crti.S b/Kernel/Architecture/i386/runtime/crti.S
new file mode 100644
index 00000000..7f9924ad
--- /dev/null
+++ b/Kernel/Architecture/i386/runtime/crti.S
@@ -0,0 +1,13 @@
+.section .init
+.global _init
+.type _init, @function
+_init:
+ push %ebp
+ mov %esp, %ebp
+
+.section .fini
+.global _fini
+.type _fini, @function
+_fini:
+ push %ebp
+ mov %esp, %ebp
diff --git a/Kernel/Architecture/i386/runtime/crtn.S b/Kernel/Architecture/i386/runtime/crtn.S
new file mode 100644
index 00000000..aa67ce13
--- /dev/null
+++ b/Kernel/Architecture/i386/runtime/crtn.S
@@ -0,0 +1,7 @@
+.section .init
+ pop %ebp
+ ret
+
+.section .fini
+ pop %ebp
+ ret
diff --git a/Kernel/Core/CPU.cpp b/Kernel/Core/CPU.cpp
new file mode 100644
index 00000000..8c5d5547
--- /dev/null
+++ b/Kernel/Core/CPU.cpp
@@ -0,0 +1,492 @@
+/*
+ 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 .
+*/
+
+#include
+
+#include
+#include
+#include
+#include
+
+#include "../kernel.h"
+
+namespace CPU
+{
+ static bool SSEEnabled = false;
+
+ char *Vendor()
+ {
+ static char Vendor[13] = {0};
+ if (Vendor[0] != 0)
+ return Vendor;
+#if defined(a64)
+ uint32_t eax, ebx, ecx, edx;
+ x64::cpuid(0x0, &eax, &ebx, &ecx, &edx);
+ memcpy(Vendor + 0, &ebx, 4);
+ memcpy(Vendor + 4, &edx, 4);
+ memcpy(Vendor + 8, &ecx, 4);
+#elif defined(a32)
+ uint32_t eax, ebx, ecx, edx;
+ x32::cpuid(0x0, &eax, &ebx, &ecx, &edx);
+ memcpy(Vendor + 0, &ebx, 4);
+ memcpy(Vendor + 4, &edx, 4);
+ memcpy(Vendor + 8, &ecx, 4);
+#elif defined(aa64)
+ asmv("mrs %0, MIDR_EL1"
+ : "=r"(Vendor[0]));
+#endif
+ return Vendor;
+ }
+
+ char *Name()
+ {
+ static char Name[49] = {0};
+ if (Name[0] != 0)
+ return Name;
+#if defined(a64)
+ uint32_t eax, ebx, ecx, edx;
+ x64::cpuid(0x80000002, &eax, &ebx, &ecx, &edx);
+ memcpy(Name + 0, &eax, 4);
+ memcpy(Name + 4, &ebx, 4);
+ memcpy(Name + 8, &ecx, 4);
+ memcpy(Name + 12, &edx, 4);
+ x64::cpuid(0x80000003, &eax, &ebx, &ecx, &edx);
+ memcpy(Name + 16, &eax, 4);
+ memcpy(Name + 20, &ebx, 4);
+ memcpy(Name + 24, &ecx, 4);
+ memcpy(Name + 28, &edx, 4);
+ x64::cpuid(0x80000004, &eax, &ebx, &ecx, &edx);
+ memcpy(Name + 32, &eax, 4);
+ memcpy(Name + 36, &ebx, 4);
+ memcpy(Name + 40, &ecx, 4);
+ memcpy(Name + 44, &edx, 4);
+#elif defined(a32)
+ uint32_t eax, ebx, ecx, edx;
+ x32::cpuid(0x80000002, &eax, &ebx, &ecx, &edx);
+ memcpy(Name + 0, &eax, 4);
+ memcpy(Name + 4, &ebx, 4);
+ memcpy(Name + 8, &ecx, 4);
+ memcpy(Name + 12, &edx, 4);
+ x32::cpuid(0x80000003, &eax, &ebx, &ecx, &edx);
+ memcpy(Name + 16, &eax, 4);
+ memcpy(Name + 20, &ebx, 4);
+ memcpy(Name + 24, &ecx, 4);
+ memcpy(Name + 28, &edx, 4);
+ x32::cpuid(0x80000004, &eax, &ebx, &ecx, &edx);
+ memcpy(Name + 32, &eax, 4);
+ memcpy(Name + 36, &ebx, 4);
+ memcpy(Name + 40, &ecx, 4);
+ memcpy(Name + 44, &edx, 4);
+#elif defined(aa64)
+ asmv("mrs %0, MIDR_EL1"
+ : "=r"(Name[0]));
+#endif
+ return Name;
+ }
+
+ char *Hypervisor()
+ {
+ static char Hypervisor[13] = {0};
+ if (Hypervisor[0] != 0)
+ return Hypervisor;
+#if defined(a64)
+ uint32_t eax, ebx, ecx, edx;
+ x64::cpuid(0x40000000, &eax, &ebx, &ecx, &edx);
+ memcpy(Hypervisor + 0, &ebx, 4);
+ memcpy(Hypervisor + 4, &ecx, 4);
+ memcpy(Hypervisor + 8, &edx, 4);
+#elif defined(a32)
+ uint32_t eax, ebx, ecx, edx;
+ x64::cpuid(0x40000000, &eax, &ebx, &ecx, &edx);
+ memcpy(Hypervisor + 0, &ebx, 4);
+ memcpy(Hypervisor + 4, &ecx, 4);
+ memcpy(Hypervisor + 8, &edx, 4);
+#elif defined(aa64)
+ asmv("mrs %0, MIDR_EL1"
+ : "=r"(Hypervisor[0]));
+#endif
+ return Hypervisor;
+ }
+
+ bool Interrupts(InterruptsType Type)
+ {
+ switch (Type)
+ {
+ case Check:
+ {
+ uintptr_t Flags;
+#if defined(a64)
+ asmv("pushfq");
+ asmv("popq %0"
+ : "=r"(Flags));
+ return Flags & (1 << 9);
+#elif defined(a32)
+ asmv("pushfl");
+ asmv("popl %0"
+ : "=r"(Flags));
+ return Flags & (1 << 9);
+#elif defined(aa64)
+ asmv("mrs %0, daif"
+ : "=r"(Flags));
+ return !(Flags & (1 << 2));
+#endif
+ }
+ case Enable:
+ {
+#if defined(a86)
+ asmv("sti");
+#elif defined(aa64)
+ asmv("msr daifclr, #2");
+#endif
+ return true;
+ }
+ case Disable:
+ {
+#if defined(a86)
+ asmv("cli");
+#elif defined(aa64)
+ asmv("msr daifset, #2");
+#endif
+ return true;
+ }
+ default:
+ break;
+ }
+ return false;
+ }
+
+ void *PageTable(void *PT)
+ {
+#if defined(a64)
+ if (PT)
+ asmv("movq %0, %%cr3"
+ :
+ : "r"(PT));
+ else
+ asmv("movq %%cr3, %0"
+ : "=r"(PT));
+#elif defined(a32)
+ if (PT)
+ asmv("movl %0, %%cr3"
+ :
+ : "r"(PT));
+ else
+ asmv("movl %%cr3, %0"
+ : "=r"(PT));
+#elif defined(aa64)
+ if (PT)
+ asmv("msr ttbr0_el1, %0"
+ :
+ : "r"(PT));
+ else
+ asmv("mrs %0, ttbr0_el1"
+ : "=r"(PT));
+#endif
+ return PT;
+ }
+
+ void InitializeFeatures(long Core)
+ {
+#if defined(a64)
+ bool PGESupport = false;
+ bool SSESupport = false;
+ bool UMIPSupport = false;
+ bool SMEPSupport = false;
+ bool SMAPSupport = false;
+
+ static int BSP = 0;
+ x64::CR0 cr0 = x64::readcr0();
+ x64::CR4 cr4 = x64::readcr4();
+
+ if (strcmp(CPU::Vendor(), x86_CPUID_VENDOR_AMD) == 0)
+ {
+ CPU::x86::AMD::CPUID0x00000001 cpuid1;
+ CPU::x86::AMD::CPUID0x00000007 cpuid7;
+ cpuid1.Get();
+ cpuid7.Get();
+
+ PGESupport = cpuid1.EDX.PGE;
+ SSESupport = cpuid1.EDX.SSE;
+ SMEPSupport = cpuid7.EBX.SMEP;
+ SMAPSupport = cpuid7.EBX.SMAP;
+ UMIPSupport = cpuid7.ECX.UMIP;
+ }
+ else if (strcmp(CPU::Vendor(), x86_CPUID_VENDOR_INTEL) == 0)
+ {
+ CPU::x86::Intel::CPUID0x00000001 cpuid1;
+ CPU::x86::Intel::CPUID0x00000007_0 cpuid7_0;
+ cpuid1.Get();
+ cpuid7_0.Get();
+ PGESupport = cpuid1.EDX.PGE;
+ SSESupport = cpuid1.EDX.SSE;
+ SMEPSupport = cpuid7_0.EBX.SMEP;
+ SMAPSupport = cpuid7_0.EBX.SMAP;
+ UMIPSupport = cpuid7_0.ECX.UMIP;
+ }
+
+ if (Config.SIMD == false)
+ {
+ debug("Disabling SSE support...");
+ SSESupport = false;
+ }
+
+ if (PGESupport)
+ {
+ debug("Enabling global pages support...");
+ if (!BSP)
+ KPrint("Global Pages is supported.");
+ cr4.PGE = 1;
+ }
+
+ bool SSEEnableAfter = false;
+
+ /* Not sure if my code is not working properly or something else is the issue. */
+ if ((strcmp(Hypervisor(), x86_CPUID_VENDOR_TCG) != 0 &&
+ strcmp(Hypervisor(), x86_CPUID_VENDOR_VIRTUALBOX) != 0) &&
+ SSESupport)
+ {
+ debug("Enabling SSE support...");
+ if (!BSP)
+ KPrint("SSE is supported.");
+ cr0.EM = 0;
+ cr0.MP = 1;
+ cr4.OSFXSR = 1;
+ cr4.OSXMMEXCPT = 1;
+
+ CPUData *CoreData = GetCPU(Core);
+ CoreData->Data.FPU = (CPU::x64::FXState *)KernelAllocator.RequestPages(TO_PAGES(sizeof(CPU::x64::FXState) + 1));
+ memset(CoreData->Data.FPU, 0, FROM_PAGES(TO_PAGES(sizeof(CPU::x64::FXState))));
+ CoreData->Data.FPU->mxcsr = 0b0001111110000000;
+ CoreData->Data.FPU->mxcsrmask = 0b1111111110111111;
+ CoreData->Data.FPU->fcw = 0b0000001100111111;
+ CPU::x64::fxrstor(CoreData->Data.FPU);
+
+ SSEEnableAfter = true;
+ }
+
+ cr0.NW = 0;
+ cr0.CD = 0;
+ cr0.WP = 1;
+
+ x64::writecr0(cr0);
+
+ if (strcmp(Hypervisor(), x86_CPUID_VENDOR_VIRTUALBOX) != 0 &&
+ strcmp(Hypervisor(), x86_CPUID_VENDOR_TCG) != 0)
+ {
+ // FIXME: I don't think this is reporting correctly. This has to be fixed asap.
+ debug("Enabling UMIP, SMEP & SMAP support...");
+ if (UMIPSupport)
+ {
+ if (!BSP)
+ KPrint("UMIP is supported.");
+ debug("UMIP is supported.");
+ // cr4.UMIP = 1;
+ }
+
+ if (SMEPSupport)
+ {
+ if (!BSP)
+ KPrint("SMEP is supported.");
+ debug("SMEP is supported.");
+ // cr4.SMEP = 1;
+ }
+
+ if (SMAPSupport)
+ {
+ if (!BSP)
+ KPrint("SMAP is supported.");
+ debug("SMAP is supported.");
+ // cr4.SMAP = 1;
+ }
+ }
+ else
+ {
+ if (!BSP)
+ {
+ if (strcmp(Hypervisor(), x86_CPUID_VENDOR_VIRTUALBOX) == 0)
+ KPrint("VirtualBox detected. Not using UMIP, SMEP & SMAP");
+ else if (strcmp(Hypervisor(), x86_CPUID_VENDOR_TCG) == 0)
+ KPrint("QEMU (TCG) detected. Not using UMIP, SMEP & SMAP");
+ }
+ }
+
+ debug("Writing CR4...");
+ x64::writecr4(cr4);
+ debug("Wrote CR4.");
+
+ debug("Enabling PAT support...");
+ x64::wrmsr(x64::MSR_CR_PAT, 0x6 | (0x0 << 8) | (0x1 << 16));
+ if (!BSP++)
+ trace("Features for BSP initialized.");
+ if (SSEEnableAfter)
+ SSEEnabled = true;
+#elif defined(a32)
+#elif defined(aa64)
+#endif
+ }
+
+ uintptr_t Counter()
+ {
+ // TODO: Get the counter from the x2APIC or any other timer that is available. (TSC is not available on all CPUs)
+ uintptr_t Counter;
+#if defined(a64)
+ asmv("rdtsc"
+ : "=A"(Counter));
+#elif defined(a32)
+ asmv("rdtsc"
+ : "=A"(Counter));
+#elif defined(aa64)
+ asmv("mrs %0, cntvct_el0"
+ : "=r"(Counter));
+#endif
+ return Counter;
+ }
+
+ uint64_t CheckSIMD()
+ {
+#if defined(a32)
+ return SIMD_NONE; /* TODO: Support x86 SIMD on x32 */
+#endif
+
+ if (unlikely(!SSEEnabled))
+ return SIMD_NONE;
+
+ // return SIMD_SSE;
+
+#if defined(a86)
+ static uint64_t SIMDType = SIMD_NONE;
+
+ if (likely(SIMDType != SIMD_NONE))
+ return SIMDType;
+
+ if (strcmp(CPU::Vendor(), x86_CPUID_VENDOR_AMD) == 0)
+ {
+ CPU::x86::AMD::CPUID0x00000001 cpuid;
+ asmv("cpuid"
+ : "=a"(cpuid.EAX.raw), "=b"(cpuid.EBX.raw), "=c"(cpuid.ECX.raw), "=d"(cpuid.EDX.raw)
+ : "a"(0x1));
+
+ if (cpuid.ECX.SSE42)
+ SIMDType |= SIMD_SSE42;
+ else if (cpuid.ECX.SSE41)
+ SIMDType |= SIMD_SSE41;
+ else if (cpuid.ECX.SSE3)
+ SIMDType |= SIMD_SSE3;
+ else if (cpuid.EDX.SSE2)
+ SIMDType |= SIMD_SSE2;
+ else if (cpuid.EDX.SSE)
+ SIMDType |= SIMD_SSE;
+
+#ifdef DEBUG
+ if (cpuid.ECX.SSE42)
+ debug("SSE4.2 is supported.");
+ if (cpuid.ECX.SSE41)
+ debug("SSE4.1 is supported.");
+ if (cpuid.ECX.SSE3)
+ debug("SSE3 is supported.");
+ if (cpuid.EDX.SSE2)
+ debug("SSE2 is supported.");
+ if (cpuid.EDX.SSE)
+ debug("SSE is supported.");
+#endif
+
+ return SIMDType;
+ }
+ else if (strcmp(CPU::Vendor(), x86_CPUID_VENDOR_INTEL) == 0)
+ {
+ CPU::x86::Intel::CPUID0x00000001 cpuid;
+ asmv("cpuid"
+ : "=a"(cpuid.EAX.raw), "=b"(cpuid.EBX.raw), "=c"(cpuid.ECX.raw), "=d"(cpuid.EDX.raw)
+ : "a"(0x1));
+
+ if (cpuid.ECX.SSE4_2)
+ SIMDType |= SIMD_SSE42;
+ else if (cpuid.ECX.SSE4_1)
+ SIMDType |= SIMD_SSE41;
+ else if (cpuid.ECX.SSE3)
+ SIMDType |= SIMD_SSE3;
+ else if (cpuid.EDX.SSE2)
+ SIMDType |= SIMD_SSE2;
+ else if (cpuid.EDX.SSE)
+ SIMDType |= SIMD_SSE;
+
+#ifdef DEBUG
+ if (cpuid.ECX.SSE4_2)
+ debug("SSE4.2 is supported.");
+ if (cpuid.ECX.SSE4_1)
+ debug("SSE4.1 is supported.");
+ if (cpuid.ECX.SSE3)
+ debug("SSE3 is supported.");
+ if (cpuid.EDX.SSE2)
+ debug("SSE2 is supported.");
+ if (cpuid.EDX.SSE)
+ debug("SSE is supported.");
+#endif
+ return SIMDType;
+ }
+
+ debug("No SIMD support.");
+#endif // a64 || a32
+ return SIMD_NONE;
+ }
+
+ bool CheckSIMD(x86SIMDType Type)
+ {
+ if (unlikely(!SSEEnabled))
+ return false;
+
+#if defined(a86)
+ if (strcmp(CPU::Vendor(), x86_CPUID_VENDOR_AMD) == 0)
+ {
+ CPU::x86::AMD::CPUID0x00000001 cpuid;
+ asmv("cpuid"
+ : "=a"(cpuid.EAX.raw), "=b"(cpuid.EBX.raw), "=c"(cpuid.ECX.raw), "=d"(cpuid.EDX.raw)
+ : "a"(0x1));
+
+ if (Type == SIMD_SSE42)
+ return cpuid.ECX.SSE42;
+ else if (Type == SIMD_SSE41)
+ return cpuid.ECX.SSE41;
+ else if (Type == SIMD_SSE3)
+ return cpuid.ECX.SSE3;
+ else if (Type == SIMD_SSE2)
+ return cpuid.EDX.SSE2;
+ else if (Type == SIMD_SSE)
+ return cpuid.EDX.SSE;
+ }
+ else if (strcmp(CPU::Vendor(), x86_CPUID_VENDOR_INTEL) == 0)
+ {
+ CPU::x86::Intel::CPUID0x00000001 cpuid;
+ asmv("cpuid"
+ : "=a"(cpuid.EAX.raw), "=b"(cpuid.EBX.raw), "=c"(cpuid.ECX.raw), "=d"(cpuid.EDX.raw)
+ : "a"(0x1));
+
+ if (Type == SIMD_SSE42)
+ return cpuid.ECX.SSE4_2;
+ else if (Type == SIMD_SSE41)
+ return cpuid.ECX.SSE4_1;
+ else if (Type == SIMD_SSE3)
+ return cpuid.ECX.SSE3;
+ else if (Type == SIMD_SSE2)
+ return cpuid.EDX.SSE2;
+ else if (Type == SIMD_SSE)
+ return cpuid.EDX.SSE;
+ }
+#endif // a64 || a32
+ return false;
+ }
+}
diff --git a/Kernel/Core/Crash/CrashDetails.cpp b/Kernel/Core/Crash/CrashDetails.cpp
new file mode 100644
index 00000000..bc1b85ec
--- /dev/null
+++ b/Kernel/Core/Crash/CrashDetails.cpp
@@ -0,0 +1,346 @@
+/*
+ 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 .
+*/
+
+#include "../crashhandler.hpp"
+#include "chfcts.hpp"
+
+#include
+#include
+#include
+#include
+#include
+
+#if defined(a64)
+#include "../../Architecture/amd64/cpu/gdt.hpp"
+#elif defined(a32)
+#elif defined(aa64)
+#endif
+
+#include "../../kernel.h"
+
+static const char *PageFaultDescriptions[8] = {
+ "Supervisory process tried to read a non-present page entry\n",
+ "Supervisory process tried to read a page and caused a protection fault\n",
+ "Supervisory process tried to write to a non-present page entry\n",
+ "Supervisory process tried to write a page and caused a protection fault\n",
+ "User process tried to read a non-present page entry\n",
+ "User process tried to read a page and caused a protection fault\n",
+ "User process tried to write to a non-present page entry\n",
+ "User process tried to write a page and caused a protection fault\n"};
+
+SafeFunction void DivideByZeroExceptionHandler(CHArchTrapFrame *Frame)
+{
+ fixme("Divide by zero exception\n");
+ UNUSED(Frame);
+}
+
+SafeFunction void DebugExceptionHandler(CHArchTrapFrame *Frame)
+{
+ CrashHandler::EHPrint("Kernel triggered debug exception.\n");
+ UNUSED(Frame);
+}
+
+SafeFunction void NonMaskableInterruptExceptionHandler(CHArchTrapFrame *Frame)
+{
+ fixme("NMI exception");
+ UNUSED(Frame);
+}
+
+SafeFunction void BreakpointExceptionHandler(CHArchTrapFrame *Frame)
+{
+ fixme("Breakpoint exception");
+ UNUSED(Frame);
+}
+
+SafeFunction void OverflowExceptionHandler(CHArchTrapFrame *Frame)
+{
+ fixme("Overflow exception");
+ UNUSED(Frame);
+}
+
+SafeFunction void BoundRangeExceptionHandler(CHArchTrapFrame *Frame)
+{
+ fixme("Bound range exception");
+ UNUSED(Frame);
+}
+
+SafeFunction void InvalidOpcodeExceptionHandler(CHArchTrapFrame *Frame)
+{
+ CrashHandler::EHPrint("Kernel tried to execute an invalid opcode.\n");
+ UNUSED(Frame);
+}
+
+SafeFunction void DeviceNotAvailableExceptionHandler(CHArchTrapFrame *Frame)
+{
+ fixme("Device not available exception");
+ UNUSED(Frame);
+}
+
+SafeFunction void DoubleFaultExceptionHandler(CHArchTrapFrame *Frame)
+{
+ fixme("Double fault exception");
+ UNUSED(Frame);
+}
+
+SafeFunction void CoprocessorSegmentOverrunExceptionHandler(CHArchTrapFrame *Frame)
+{
+ fixme("Coprocessor segment overrun exception");
+ UNUSED(Frame);
+}
+
+SafeFunction void InvalidTSSExceptionHandler(CHArchTrapFrame *Frame)
+{
+ fixme("Invalid TSS exception");
+ UNUSED(Frame);
+}
+
+SafeFunction void SegmentNotPresentExceptionHandler(CHArchTrapFrame *Frame)
+{
+ fixme("Segment not present exception");
+ UNUSED(Frame);
+}
+
+SafeFunction void StackFaultExceptionHandler(CHArchTrapFrame *Frame)
+{
+ CPU::x64::SelectorErrorCode SelCode = {.raw = Frame->ErrorCode};
+#if defined(a64)
+ CrashHandler::EHPrint("Stack segment fault at address %#lx\n", Frame->rip);
+#elif defined(a32)
+ CrashHandler::EHPrint("Stack segment fault at address %#lx\n", Frame->eip);
+#elif defined(aa64)
+#endif
+ CrashHandler::EHPrint("External: %d\n", SelCode.External);
+ CrashHandler::EHPrint("Table: %d\n", SelCode.Table);
+ CrashHandler::EHPrint("Index: %#x\n", SelCode.Idx);
+ CrashHandler::EHPrint("Error code: %#lx\n", Frame->ErrorCode);
+}
+
+SafeFunction void GeneralProtectionExceptionHandler(CHArchTrapFrame *Frame)
+{
+ CPU::x64::SelectorErrorCode SelCode = {.raw = Frame->ErrorCode};
+ // switch (SelCode.Table)
+ // {
+ // case CPU::x64::0b00:
+ // memcpy(desc_tmp, "GDT", 3);
+ // break;
+ // case CPU::x64::0b01:
+ // memcpy(desc_tmp, "IDT", 3);
+ // break;
+ // case CPU::x64::0b10:
+ // memcpy(desc_tmp, "LDT", 3);
+ // break;
+ // case CPU::x64::0b11:
+ // memcpy(desc_tmp, "IDT", 3);
+ // break;
+ // default:
+ // memcpy(desc_tmp, "Unknown", 7);
+ // break;
+ // }
+ CrashHandler::EHPrint("Kernel performed an illegal operation.\n");
+ CrashHandler::EHPrint("External: %d\n", SelCode.External);
+ CrashHandler::EHPrint("Table: %d\n", SelCode.Table);
+ CrashHandler::EHPrint("Index: %#x\n", SelCode.Idx);
+}
+
+SafeFunction void PageFaultExceptionHandler(CHArchTrapFrame *Frame)
+{
+ CPU::x64::PageFaultErrorCode params = {.raw = (uint32_t)Frame->ErrorCode};
+#if defined(a64)
+ CrashHandler::EHPrint("\eAFAFAFAn exception occurred at %#lx by %#lx\n", CrashHandler::PageFaultAddress, Frame->rip);
+#elif defined(a32)
+ CrashHandler::EHPrint("\eAFAFAFAn exception occurred at %#lx by %#lx\n", CrashHandler::PageFaultAddress, Frame->eip);
+#elif defined(aa64)
+#endif
+ CrashHandler::EHPrint("Page: %s\n", params.P ? "Present" : "Not Present");
+ CrashHandler::EHPrint("Write Operation: %s\n", params.W ? "Read-Only" : "Read-Write");
+ CrashHandler::EHPrint("Processor Mode: %s\n", params.U ? "User-Mode" : "Kernel-Mode");
+ CrashHandler::EHPrint("CPU Reserved Bits: %s\n", params.R ? "Reserved" : "Unreserved");
+ CrashHandler::EHPrint("Caused By An Instruction Fetch: %s\n", params.I ? "Yes" : "No");
+ CrashHandler::EHPrint("Caused By A Protection-Key Violation: %s\n", params.PK ? "Yes" : "No");
+ CrashHandler::EHPrint("Caused By A Shadow Stack Access: %s\n", params.SS ? "Yes" : "No");
+ CrashHandler::EHPrint("Caused By An SGX Violation: %s\n", params.SGX ? "Yes" : "No");
+ if (Frame->ErrorCode & 0x00000008)
+ CrashHandler::EHPrint("One or more page directory entries contain reserved bits which are set to 1.\n");
+ else
+ CrashHandler::EHPrint(PageFaultDescriptions[Frame->ErrorCode & 0b111]);
+
+#ifdef DEBUG
+ uintptr_t CheckPageFaultAddress = 0;
+ CheckPageFaultAddress = CrashHandler::PageFaultAddress;
+ if (CheckPageFaultAddress == 0)
+#ifdef a64
+ CheckPageFaultAddress = Frame->rip;
+#elif defined(a32)
+ CheckPageFaultAddress = Frame->eip;
+#elif defined(aa64)
+ CheckPageFaultAddress = 0;
+#endif
+
+#if defined(a64)
+ Memory::Virtual vma = Memory::Virtual(((Memory::PageTable4 *)CPU::x64::readcr3().raw));
+#elif defined(a32)
+ Memory::Virtual vma = Memory::Virtual(((Memory::PageTable4 *)CPU::x32::readcr3().raw));
+#elif defined(aa64)
+ Memory::Virtual vma = Memory::Virtual();
+#warning "TODO: aa64"
+#endif
+
+ bool PageAvailable = vma.Check((void *)CheckPageFaultAddress);
+ debug("Page available (Check(...)): %s. %s",
+ PageAvailable ? "Yes" : "No",
+ (params.P && !PageAvailable) ? "CR2 == Present; Check() != Present??????" : "CR2 confirms Check() result.");
+
+ if (PageAvailable)
+ {
+ bool Present = vma.Check((void *)CheckPageFaultAddress);
+ bool ReadWrite = vma.Check((void *)CheckPageFaultAddress, Memory::PTFlag::RW);
+ bool User = vma.Check((void *)CheckPageFaultAddress, Memory::PTFlag::US);
+ bool WriteThrough = vma.Check((void *)CheckPageFaultAddress, Memory::PTFlag::PWT);
+ bool CacheDisabled = vma.Check((void *)CheckPageFaultAddress, Memory::PTFlag::PCD);
+ bool Accessed = vma.Check((void *)CheckPageFaultAddress, Memory::PTFlag::A);
+ bool Dirty = vma.Check((void *)CheckPageFaultAddress, Memory::PTFlag::D);
+ bool Global = vma.Check((void *)CheckPageFaultAddress, Memory::PTFlag::G);
+ /* ... */
+
+ debug("Page available: %s", Present ? "Yes" : "No");
+ debug("Page read/write: %s", ReadWrite ? "Yes" : "No");
+ debug("Page user/kernel: %s", User ? "User" : "Kernel");
+ debug("Page write-through: %s", WriteThrough ? "Yes" : "No");
+ debug("Page cache disabled: %s", CacheDisabled ? "Yes" : "No");
+ debug("Page accessed: %s", Accessed ? "Yes" : "No");
+ debug("Page dirty: %s", Dirty ? "Yes" : "No");
+ debug("Page global: %s", Global ? "Yes" : "No");
+
+ if (Present)
+ {
+ uintptr_t CheckPageFaultLinearAddress = (uintptr_t)CheckPageFaultAddress;
+ CheckPageFaultLinearAddress &= 0xFFFFFFFFFFFFF000;
+ debug("%#lx -> %#lx", CheckPageFaultAddress, CheckPageFaultLinearAddress);
+
+ Memory::Virtual::PageMapIndexer Index = Memory::Virtual::PageMapIndexer((uintptr_t)CheckPageFaultLinearAddress);
+ debug("Index for %#lx is PML:%d PDPTE:%d PDE:%d PTE:%d",
+ CheckPageFaultLinearAddress,
+ Index.PMLIndex,
+ Index.PDPTEIndex,
+ Index.PDEIndex,
+ Index.PTEIndex);
+#if defined(a64)
+ Memory::PageMapLevel4 PML4 = ((Memory::PageTable4 *)CPU::x64::readcr3().raw)->Entries[Index.PMLIndex];
+#elif defined(a32)
+ Memory::PageMapLevel4 PML4 = ((Memory::PageTable4 *)CPU::x32::readcr3().raw)->Entries[Index.PMLIndex];
+#elif defined(aa64)
+ Memory::PageMapLevel4 PML4 = {.raw = 0};
+#warning "TODO: aa64"
+#endif
+
+ Memory::PageDirectoryPointerTableEntryPtr *PDPTE = (Memory::PageDirectoryPointerTableEntryPtr *)((uintptr_t)PML4.GetAddress() << 12);
+ Memory::PageDirectoryEntryPtr *PDE = (Memory::PageDirectoryEntryPtr *)((uintptr_t)PDPTE->Entries[Index.PDPTEIndex].GetAddress() << 12);
+ Memory::PageTableEntryPtr *PTE = (Memory::PageTableEntryPtr *)((uintptr_t)PDE->Entries[Index.PDEIndex].GetAddress() << 12);
+
+ debug("# %03d-%03d-%03d-%03d: P:%s RW:%s US:%s PWT:%s PCB:%s A:%s NX:%s Address:%#lx",
+ Index.PMLIndex, 0, 0, 0,
+ PML4.Present ? "1" : "0",
+ PML4.ReadWrite ? "1" : "0",
+ PML4.UserSupervisor ? "1" : "0",
+ PML4.WriteThrough ? "1" : "0",
+ PML4.CacheDisable ? "1" : "0",
+ PML4.Accessed ? "1" : "0",
+ PML4.ExecuteDisable ? "1" : "0",
+ PML4.GetAddress() << 12);
+
+ debug("# %03d-%03d-%03d-%03d: P:%s RW:%s US:%s PWT:%s PCB:%s A:%s NX:%s Address:%#lx",
+ Index.PMLIndex, Index.PDPTEIndex, 0, 0,
+ PDPTE->Entries[Index.PDPTEIndex].Present ? "1" : "0",
+ PDPTE->Entries[Index.PDPTEIndex].ReadWrite ? "1" : "0",
+ PDPTE->Entries[Index.PDPTEIndex].UserSupervisor ? "1" : "0",
+ PDPTE->Entries[Index.PDPTEIndex].WriteThrough ? "1" : "0",
+ PDPTE->Entries[Index.PDPTEIndex].CacheDisable ? "1" : "0",
+ PDPTE->Entries[Index.PDPTEIndex].Accessed ? "1" : "0",
+ PDPTE->Entries[Index.PDPTEIndex].ExecuteDisable ? "1" : "0",
+ PDPTE->Entries[Index.PDPTEIndex].GetAddress() << 12);
+
+ debug("# %03d-%03d-%03d-%03d: P:%s RW:%s US:%s PWT:%s PCB:%s A:%s NX:%s Address:%#lx",
+ Index.PMLIndex, Index.PDPTEIndex, Index.PDEIndex, 0,
+ PDE->Entries[Index.PDEIndex].Present ? "1" : "0",
+ PDE->Entries[Index.PDEIndex].ReadWrite ? "1" : "0",
+ PDE->Entries[Index.PDEIndex].UserSupervisor ? "1" : "0",
+ PDE->Entries[Index.PDEIndex].WriteThrough ? "1" : "0",
+ PDE->Entries[Index.PDEIndex].CacheDisable ? "1" : "0",
+ PDE->Entries[Index.PDEIndex].Accessed ? "1" : "0",
+ PDE->Entries[Index.PDEIndex].ExecuteDisable ? "1" : "0",
+ PDE->Entries[Index.PDEIndex].GetAddress() << 12);
+
+ debug("# %03d-%03d-%03d-%03d: P:%s RW:%s US:%s PWT:%s PCB:%s A:%s D:%s PAT:%s G:%s PK:%d NX:%s Address:%#lx",
+ Index.PMLIndex, Index.PDPTEIndex, Index.PDEIndex, Index.PTEIndex,
+ PTE->Entries[Index.PTEIndex].Present ? "1" : "0",
+ PTE->Entries[Index.PTEIndex].ReadWrite ? "1" : "0",
+ PTE->Entries[Index.PTEIndex].UserSupervisor ? "1" : "0",
+ PTE->Entries[Index.PTEIndex].WriteThrough ? "1" : "0",
+ PTE->Entries[Index.PTEIndex].CacheDisable ? "1" : "0",
+ PTE->Entries[Index.PTEIndex].Accessed ? "1" : "0",
+ PTE->Entries[Index.PTEIndex].Dirty ? "1" : "0",
+ PTE->Entries[Index.PTEIndex].PageAttributeTable ? "1" : "0",
+ PTE->Entries[Index.PTEIndex].Global ? "1" : "0",
+ PTE->Entries[Index.PTEIndex].ProtectionKey,
+ PTE->Entries[Index.PTEIndex].ExecuteDisable ? "1" : "0",
+ PTE->Entries[Index.PTEIndex].GetAddress() << 12);
+ }
+ }
+#endif
+}
+
+SafeFunction void x87FloatingPointExceptionHandler(CHArchTrapFrame *Frame)
+{
+ fixme("x87 floating point exception");
+ UNUSED(Frame);
+}
+
+SafeFunction void AlignmentCheckExceptionHandler(CHArchTrapFrame *Frame)
+{
+ fixme("Alignment check exception");
+ UNUSED(Frame);
+}
+
+SafeFunction void MachineCheckExceptionHandler(CHArchTrapFrame *Frame)
+{
+ fixme("Machine check exception");
+ UNUSED(Frame);
+}
+
+SafeFunction void SIMDFloatingPointExceptionHandler(CHArchTrapFrame *Frame)
+{
+ fixme("SIMD floating point exception");
+ UNUSED(Frame);
+}
+
+SafeFunction void VirtualizationExceptionHandler(CHArchTrapFrame *Frame)
+{
+ fixme("Virtualization exception");
+ UNUSED(Frame);
+}
+
+SafeFunction void SecurityExceptionHandler(CHArchTrapFrame *Frame)
+{
+ fixme("Security exception");
+ UNUSED(Frame);
+}
+
+SafeFunction void UnknownExceptionHandler(CHArchTrapFrame *Frame)
+{
+ fixme("Unknown exception");
+ UNUSED(Frame);
+}
diff --git a/Kernel/Core/Crash/CrashHandler.cpp b/Kernel/Core/Crash/CrashHandler.cpp
new file mode 100644
index 00000000..6eabd5b0
--- /dev/null
+++ b/Kernel/Core/Crash/CrashHandler.cpp
@@ -0,0 +1,1122 @@
+/*
+ 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 .
+*/
+
+#include "../crashhandler.hpp"
+#include "chfcts.hpp"
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#if defined(a64)
+#include "../../Architecture/amd64/cpu/gdt.hpp"
+#include "../Architecture/amd64/cpu/apic.hpp"
+#elif defined(a32)
+#include "../../Architecture/i386/cpu/gdt.hpp"
+#include "../Architecture/i386/cpu/apic.hpp"
+#elif defined(aa64)
+#endif
+
+#include "../../kernel.h"
+#include "../../DAPI.hpp"
+
+NewLock(UserInputLock);
+
+namespace CrashHandler
+{
+ uintptr_t PageFaultAddress = 0;
+ void *EHIntFrames[INT_FRAMES_MAX];
+ static bool ExceptionOccurred = false;
+ int SBIdx = 255;
+
+ SafeFunction void printfWrapper(char c, void *unused)
+ {
+ Display->Print(c, SBIdx, true);
+ UNUSED(unused);
+ }
+
+ SafeFunction void EHPrint(const char *Format, ...)
+ {
+ va_list args;
+ va_start(args, Format);
+ vfctprintf(printfWrapper, NULL, Format, args);
+ va_end(args);
+ }
+
+ SafeFunction void EHDumpData(void *Address, unsigned long Length)
+ {
+ EHPrint("-------------------------------------------------------------------------\n");
+ Display->SetBuffer(SBIdx);
+ unsigned char *AddressChar = (unsigned char *)Address;
+ unsigned char Buffer[17];
+ unsigned long Iterate;
+ for (Iterate = 0; Iterate < Length; Iterate++)
+ {
+ if ((Iterate % 16) == 0)
+ {
+ if (Iterate != 0)
+ EHPrint(" \e8A78FF%s\eAABBCC\n", Buffer);
+ EHPrint(" \e9E9E9E%04x\eAABBCC ", Iterate);
+ Display->SetBuffer(SBIdx);
+ }
+ EHPrint(" \e4287f5%02x\eAABBCC", AddressChar[Iterate]);
+ if ((AddressChar[Iterate] < 0x20) || (AddressChar[Iterate] > 0x7e))
+ Buffer[Iterate % 16] = '.';
+ else
+ Buffer[Iterate % 16] = AddressChar[Iterate];
+ Buffer[(Iterate % 16) + 1] = '\0';
+ }
+
+ while ((Iterate % 16) != 0)
+ {
+ EHPrint(" ");
+ Display->SetBuffer(SBIdx);
+ Iterate++;
+ }
+
+ EHPrint(" \e8A78FF%s\eAABBCC\n", Buffer);
+ EHPrint("-------------------------------------------------------------------------\n\n.");
+ Display->SetBuffer(SBIdx);
+ }
+
+ SafeFunction char *TrimWhiteSpace(char *str)
+ {
+ char *end;
+ while (*str == ' ')
+ str++;
+ if (*str == 0)
+ return str;
+ end = str + strlen(str) - 1;
+ while (end > str && *end == ' ')
+ end--;
+ *(end + 1) = 0;
+ return str;
+ }
+
+ CRData crashdata = {};
+
+ SafeFunction void DisplayTopOverlay()
+ {
+ Video::ScreenBuffer *sb = Display->GetBuffer(SBIdx);
+ Video::Font *f = Display->GetCurrentFont();
+ Video::FontInfo fi = f->GetInfo();
+
+ for (uint32_t i = 0; i < sb->Width; i++)
+ for (uint32_t j = 0; j < fi.Height + 8; j++)
+ Display->SetPixel(i, j, 0x282828, SBIdx);
+
+ Display->SetBufferCursor(SBIdx, 8, (fi.Height + 8) / 6);
+ switch (SBIdx)
+ {
+ case 255:
+ {
+ EHPrint("\eAAAAAAMAIN \e606060DETAILS \e606060FRAMES \e606060TASKS \e606060CONSOLE");
+ break;
+ }
+ case 254:
+ {
+ EHPrint("\e606060MAIN \eAAAAAADETAILS \e606060FRAMES \e606060TASKS \e606060CONSOLE");
+ break;
+ }
+ case 253:
+ {
+ EHPrint("\e606060MAIN \e606060DETAILS \eAAAAAAFRAMES \e606060TASKS \e606060CONSOLE");
+ break;
+ }
+ case 252:
+ {
+ EHPrint("\e606060MAIN \e606060DETAILS \e606060FRAMES \eAAAAAATASKS \e606060CONSOLE");
+ break;
+ }
+ case 251:
+ {
+ EHPrint("\e606060MAIN \e606060DETAILS \e606060FRAMES \e606060TASKS \eAAAAAACONSOLE");
+ break;
+ }
+ default:
+ {
+ EHPrint("\e606060MAIN \e606060DETAILS \e606060FRAMES \e606060TASKS \e606060CONSOLE");
+ break;
+ }
+ }
+ EHPrint(" \e00AAFF%ldMB / %ldMB (%ldMB Reserved)",
+ TO_MB(KernelAllocator.GetUsedMemory()),
+ TO_MB(KernelAllocator.GetTotalMemory()),
+ TO_MB(KernelAllocator.GetReservedMemory()));
+ EHPrint(" \eAA0F0F%s", CPU::Hypervisor());
+ EHPrint(" \eAAF00F%s", CPU::Vendor());
+ EHPrint(" \eAA00FF%s", CPU::Name());
+ Display->SetBufferCursor(SBIdx, 0, fi.Height + 10);
+
+ /* https://imgflip.com/i/77slbl */
+ if ((Random::rand32() % 100) >= 98)
+ {
+ debug("Easter egg activated!");
+ int BaseXOffset = sb->Width - 14;
+ int BaseYOffset = 8;
+ Display->SetPixel(BaseXOffset + 3, BaseYOffset + 0, 0x21852E, SBIdx);
+ Display->SetPixel(BaseXOffset + 4, BaseYOffset + 0, 0x21852E, SBIdx);
+ Display->SetPixel(BaseXOffset + 6, BaseYOffset + 0, 0x21852E, SBIdx);
+ Display->SetPixel(BaseXOffset + 7, BaseYOffset + 0, 0x21852E, SBIdx);
+
+ Display->SetPixel(BaseXOffset + 2, BaseYOffset + 1, 0x21852E, SBIdx);
+ Display->SetPixel(BaseXOffset + 3, BaseYOffset + 1, 0x21852E, SBIdx);
+ Display->SetPixel(BaseXOffset + 4, BaseYOffset + 1, 0x21852E, SBIdx);
+ Display->SetPixel(BaseXOffset + 5, BaseYOffset + 1, 0x21852E, SBIdx);
+ Display->SetPixel(BaseXOffset + 6, BaseYOffset + 1, 0x21852E, SBIdx);
+ Display->SetPixel(BaseXOffset + 7, BaseYOffset + 1, 0x21852E, SBIdx);
+ Display->SetPixel(BaseXOffset + 8, BaseYOffset + 1, 0x21852E, SBIdx);
+
+ Display->SetPixel(BaseXOffset + 1, BaseYOffset + 2, 0x21852E, SBIdx);
+ Display->SetPixel(BaseXOffset + 2, BaseYOffset + 2, 0x21852E, SBIdx);
+ Display->SetPixel(BaseXOffset + 3, BaseYOffset + 2, 0xFFFFFF, SBIdx);
+ Display->SetPixel(BaseXOffset + 4, BaseYOffset + 2, 0x000000, SBIdx);
+ Display->SetPixel(BaseXOffset + 5, BaseYOffset + 2, 0x21852E, SBIdx);
+ Display->SetPixel(BaseXOffset + 6, BaseYOffset + 2, 0xFFFFFF, SBIdx);
+ Display->SetPixel(BaseXOffset + 7, BaseYOffset + 2, 0x000000, SBIdx);
+ Display->SetPixel(BaseXOffset + 8, BaseYOffset + 2, 0x21852E, SBIdx);
+
+ Display->SetPixel(BaseXOffset + 1, BaseYOffset + 3, 0x21852E, SBIdx);
+ Display->SetPixel(BaseXOffset + 2, BaseYOffset + 3, 0x21852E, SBIdx);
+ Display->SetPixel(BaseXOffset + 3, BaseYOffset + 3, 0x21852E, SBIdx);
+ Display->SetPixel(BaseXOffset + 4, BaseYOffset + 3, 0x21852E, SBIdx);
+ Display->SetPixel(BaseXOffset + 5, BaseYOffset + 3, 0x21852E, SBIdx);
+ Display->SetPixel(BaseXOffset + 6, BaseYOffset + 3, 0x21852E, SBIdx);
+ Display->SetPixel(BaseXOffset + 7, BaseYOffset + 3, 0x21852E, SBIdx);
+
+ Display->SetPixel(BaseXOffset + 0, BaseYOffset + 4, 0x21852E, SBIdx);
+ Display->SetPixel(BaseXOffset + 1, BaseYOffset + 4, 0x21852E, SBIdx);
+ Display->SetPixel(BaseXOffset + 2, BaseYOffset + 4, 0x21852E, SBIdx);
+ Display->SetPixel(BaseXOffset + 3, BaseYOffset + 4, 0x21852E, SBIdx);
+ Display->SetPixel(BaseXOffset + 4, BaseYOffset + 4, 0xA84832, SBIdx);
+ Display->SetPixel(BaseXOffset + 5, BaseYOffset + 4, 0xA84832, SBIdx);
+ Display->SetPixel(BaseXOffset + 6, BaseYOffset + 4, 0xA84832, SBIdx);
+ Display->SetPixel(BaseXOffset + 7, BaseYOffset + 4, 0xA84832, SBIdx);
+
+ Display->SetPixel(BaseXOffset + 0, BaseYOffset + 5, 0x21852E, SBIdx);
+ Display->SetPixel(BaseXOffset + 1, BaseYOffset + 5, 0x21852E, SBIdx);
+ Display->SetPixel(BaseXOffset + 2, BaseYOffset + 5, 0x21852E, SBIdx);
+ Display->SetPixel(BaseXOffset + 3, BaseYOffset + 5, 0x21852E, SBIdx);
+ Display->SetPixel(BaseXOffset + 4, BaseYOffset + 5, 0x21852E, SBIdx);
+ Display->SetPixel(BaseXOffset + 5, BaseYOffset + 5, 0x21852E, SBIdx);
+ Display->SetPixel(BaseXOffset + 6, BaseYOffset + 5, 0x21852E, SBIdx);
+
+ Display->SetPixel(BaseXOffset + 0, BaseYOffset + 6, 0x1216FF, SBIdx);
+ Display->SetPixel(BaseXOffset + 1, BaseYOffset + 6, 0x1216FF, SBIdx);
+ Display->SetPixel(BaseXOffset + 2, BaseYOffset + 6, 0x1216FF, SBIdx);
+ Display->SetPixel(BaseXOffset + 3, BaseYOffset + 6, 0x1216FF, SBIdx);
+ Display->SetPixel(BaseXOffset + 4, BaseYOffset + 6, 0x1216FF, SBIdx);
+ Display->SetPixel(BaseXOffset + 5, BaseYOffset + 6, 0x1216FF, SBIdx);
+ Display->SetPixel(BaseXOffset + 6, BaseYOffset + 6, 0x1216FF, SBIdx);
+
+ Display->SetBuffer(SBIdx);
+ }
+ }
+
+ SafeFunction void DisplayBottomOverlay()
+ {
+ Video::ScreenBuffer *sb = Display->GetBuffer(SBIdx);
+ Video::Font *f = Display->GetCurrentFont();
+ Video::FontInfo fi = f->GetInfo();
+
+ for (uint32_t i = 0; i < sb->Width; i++)
+ for (uint32_t j = sb->Height - fi.Height - 8; j < sb->Height; j++)
+ Display->SetPixel(i, j, 0x282828, SBIdx);
+
+ Display->SetBufferCursor(SBIdx, 8, sb->Height - fi.Height - 4);
+ EHPrint("\eAAAAAA> \eFAFAFA");
+ }
+
+ SafeFunction void ArrowInput(uint8_t key)
+ {
+ switch (key)
+ {
+ case KEY_D_UP:
+ if (SBIdx < 255)
+ SBIdx++;
+ else
+ return;
+ break;
+ case KEY_D_LEFT:
+ if (SBIdx < 255)
+ SBIdx++;
+ else
+ return;
+ break;
+ case KEY_D_RIGHT:
+ if (SBIdx > 251)
+ SBIdx--;
+ else
+ return;
+ break;
+ case KEY_D_DOWN:
+ if (SBIdx > 251)
+ SBIdx--;
+ else
+ return;
+ break;
+ default:
+ break;
+ }
+ Display->ClearBuffer(SBIdx);
+ DisplayTopOverlay();
+ EHPrint("\eFAFAFA");
+
+ switch (SBIdx)
+ {
+ case 255:
+ {
+ DisplayMainScreen(crashdata);
+ break;
+ }
+ case 254:
+ {
+ DisplayDetailsScreen(crashdata);
+ break;
+ }
+ case 253:
+ {
+ DisplayStackFrameScreen(crashdata);
+ break;
+ }
+ case 252:
+ {
+ DisplayTasksScreen(crashdata);
+ break;
+ }
+ case 251:
+ {
+ DisplayConsoleScreen(crashdata);
+ break;
+ }
+ default:
+ {
+ break;
+ }
+ }
+ DisplayBottomOverlay();
+ Display->SetBuffer(SBIdx);
+ }
+
+ SafeFunction void UserInput(char *Input)
+ {
+ SmartCriticalSection(UserInputLock);
+ Display->ClearBuffer(SBIdx);
+ DisplayTopOverlay();
+ EHPrint("\eFAFAFA");
+
+ if (strcmp(Input, "help") == 0)
+ {
+ EHPrint("Available commands are:\n");
+ EHPrint("exit - Shutdown the OS.\n");
+ EHPrint("reboot - Reboot the OS.\n");
+ EHPrint("help - Display this help message.\n");
+ EHPrint("showbuf,sb - Display the contents of a screen buffer.\n");
+ EHPrint(" - A sleep timer will be enabled. This will cause the OS to sleep for an unknown amount of time.\n");
+ EHPrint(" - \eFF4400WARNING: This can crash the system if a wrong buffer is selected.\eFAFAFA\n");
+ EHPrint("ifr - Show interrupt frames.\n");
+ EHPrint("tlb - Print the page table entries\n");
+ EHPrint("bitmap - Print the memory bitmap\n");
+ EHPrint("mem - Print the memory allocation\n");
+ EHPrint("cr - Print the CPU control register\n");
+ EHPrint("tss - Print the CPU task state segment\n");
+ EHPrint("dump - Dump memory\n");
+ EHPrint(" - \eFF4400WARNING: This can crash the system if you try to read from an unmapped page.\eFAFAFA\n");
+ EHPrint("uartmemdmp - Dump the memory of a UART.\n");
+ EHPrint("main - Show the main screen.\n");
+ EHPrint("details - Show the details screen.\n");
+ EHPrint("frames - Show the stack frame screen.\n");
+ EHPrint("tasks - Show the tasks screen.\n");
+ EHPrint("console - Show the console screen.\n");
+ EHPrint("Also, you can use the arrow keys to navigate between the screens.\n");
+ EHPrint("=========================================================================\n");
+ EHPrint("Kernel Compiled at: %s %s with C++ Standard: %d\n", __DATE__, __TIME__, CPP_LANGUAGE_STANDARD);
+ EHPrint("C++ Language Version (__cplusplus): %ld\n", __cplusplus);
+ }
+ else if (strcmp(Input, "exit") == 0)
+ {
+ PowerManager->Shutdown();
+ EHPrint("\eFFFFFFNow it's safe to turn off your computer.");
+ Display->SetBuffer(SBIdx);
+ CPU::Stop();
+ }
+ else if (strcmp(Input, "reboot") == 0)
+ {
+ PowerManager->Reboot();
+ EHPrint("\eFFFFFFNow it's safe to reboot your computer.");
+ Display->SetBuffer(SBIdx);
+ CPU::Stop();
+ }
+ else if (strncmp(Input, "showbuf", 7) == 0 || strncmp(Input, "sb", 2) == 0)
+ {
+ char *arg = TrimWhiteSpace(Input + 7);
+ int tmpidx = SBIdx;
+ SBIdx = atoi(arg);
+ Display->SetBuffer(SBIdx);
+#if defined(a86)
+ for (int i = 0; i < 5000000; i++)
+ inb(0x80);
+#endif // a64 || a32
+ SBIdx = tmpidx;
+ Display->SetBuffer(SBIdx);
+ }
+ else if (strncmp(Input, "ifr", 3) == 0)
+ {
+ char *arg = TrimWhiteSpace(Input + 3);
+ int CountI = atoi(arg);
+ int TotalCount = sizeof(EHIntFrames) / sizeof(EHIntFrames[0]);
+
+ debug("Printing %ld interrupt frames.", CountI);
+
+ if (CountI > TotalCount)
+ {
+ EHPrint("\eFF4400Count too big! Maximum allowed is %ld\eFAFAFA\n", TotalCount);
+ Display->SetBuffer(SBIdx);
+ }
+ else
+ {
+ for (int i = 0; i < CountI; i++)
+ {
+ if (EHIntFrames[i])
+ {
+ if (!Memory::Virtual().Check(EHIntFrames[i]))
+ continue;
+ EHPrint("\n\e2565CC%p", EHIntFrames[i]);
+ EHPrint("\e7925CC-");
+#if defined(a64)
+ if ((uintptr_t)EHIntFrames[i] >= 0xFFFFFFFF80000000 && (uintptr_t)EHIntFrames[i] <= (uintptr_t)&_kernel_end)
+#elif defined(a32)
+ if ((uintptr_t)EHIntFrames[i] >= 0xC0000000 && (uintptr_t)EHIntFrames[i] <= (uintptr_t)&_kernel_end)
+#elif defined(aa64)
+ if ((uintptr_t)EHIntFrames[i] >= 0xFFFFFFFF80000000 && (uintptr_t)EHIntFrames[i] <= (uintptr_t)&_kernel_end)
+#endif
+ EHPrint("\e25CCC9%s", KernelSymbolTable->GetSymbolFromAddress((uintptr_t)EHIntFrames[i]));
+ else
+ EHPrint("\eFF4CA9Outside Kernel");
+#if defined(a86)
+ for (int i = 0; i < 20000; i++)
+ inb(0x80);
+#endif // a64 || a32
+ Display->SetBuffer(SBIdx);
+ }
+ }
+ }
+ }
+ else if (strncmp(Input, "tlb", 3) == 0)
+ {
+ char *arg = TrimWhiteSpace(Input + 3);
+ uintptr_t Address = NULL;
+ Address = strtol(arg, NULL, 16);
+ debug("Converted %s to %#lx", arg, Address);
+ Memory::PageTable4 *BasePageTable = (Memory::PageTable4 *)Address;
+ if (Memory::Virtual().Check(BasePageTable))
+ {
+ for (int PMLIndex = 0; PMLIndex < 512; PMLIndex++)
+ {
+ Memory::PageMapLevel4 PML4 = BasePageTable->Entries[PMLIndex];
+ EHPrint("\e888888# \eAABBCC%03d-%03d-%03d-%03d\e4500F5: P:%s RW:%s US:%s PWT:%s PCB:%s A:%s NX:%s Address:\e888888%#lx\n",
+ PMLIndex, 0, 0, 0,
+ PML4.Present ? "\e00FF001\e4500F5" : "\eFF00000\e4500F5",
+ PML4.ReadWrite ? "\e00FF001\e4500F5" : "\eFF00000\e4500F5",
+ PML4.UserSupervisor ? "\e00FF001\e4500F5" : "\eFF00000\e4500F5",
+ PML4.WriteThrough ? "\e00FF001\e4500F5" : "\eFF00000\e4500F5",
+ PML4.CacheDisable ? "\e00FF001\e4500F5" : "\eFF00000\e4500F5",
+ PML4.Accessed ? "\e00FF001\e4500F5" : "\eFF00000\e4500F5",
+ PML4.ExecuteDisable ? "\e00FF001\e4500F5" : "\eFF00000\e4500F5",
+ PML4.GetAddress() << 12);
+ Display->SetBuffer(SBIdx);
+ if (PML4.Present)
+ {
+ Memory::PageDirectoryPointerTableEntryPtr *PDPTE = (Memory::PageDirectoryPointerTableEntryPtr *)((uintptr_t)PML4.GetAddress() << 12);
+ if (PDPTE)
+ {
+ for (int PDPTEIndex = 0; PDPTEIndex < 512; PDPTEIndex++)
+ {
+ EHPrint("\e888888# \eAABBCC%03d-%03d-%03d-%03d\e4500F5: P:%s RW:%s US:%s PWT:%s PCB:%s A:%s NX:%s Address:\e888888%#lx\n",
+ PMLIndex, PDPTEIndex, 0, 0,
+ PDPTE->Entries[PDPTEIndex].Present ? "\e00FF001\e4500F5" : "\eFF00000\e4500F5",
+ PDPTE->Entries[PDPTEIndex].ReadWrite ? "\e00FF001\e4500F5" : "\eFF00000\e4500F5",
+ PDPTE->Entries[PDPTEIndex].UserSupervisor ? "\e00FF001\e4500F5" : "\eFF00000\e4500F5",
+ PDPTE->Entries[PDPTEIndex].WriteThrough ? "\e00FF001\e4500F5" : "\eFF00000\e4500F5",
+ PDPTE->Entries[PDPTEIndex].CacheDisable ? "\e00FF001\e4500F5" : "\eFF00000\e4500F5",
+ PDPTE->Entries[PDPTEIndex].Accessed ? "\e00FF001\e4500F5" : "\eFF00000\e4500F5",
+ PDPTE->Entries[PDPTEIndex].ExecuteDisable ? "\e00FF001\e4500F5" : "\eFF00000\e4500F5",
+ PDPTE->Entries[PDPTEIndex].GetAddress() << 12);
+ Display->SetBuffer(SBIdx);
+ if ((PDPTE->Entries[PDPTEIndex].Present))
+ {
+ Memory::PageDirectoryEntryPtr *PDE = (Memory::PageDirectoryEntryPtr *)((uintptr_t)PDPTE->Entries[PDPTEIndex].GetAddress() << 12);
+ if (PDE)
+ {
+ for (int PDEIndex = 0; PDEIndex < 512; PDEIndex++)
+ {
+ EHPrint("\e888888# \eAABBCC%03d-%03d-%03d-%03d\e4500F5: P:%s RW:%s US:%s PWT:%s PCB:%s A:%s NX:%s Address:\e888888%#lx\n",
+ PMLIndex, PDPTEIndex, PDEIndex, 0,
+ PDE->Entries[PDEIndex].Present ? "\e00FF001\e4500F5" : "\eFF00000\e4500F5",
+ PDE->Entries[PDEIndex].ReadWrite ? "\e00FF001\e4500F5" : "\eFF00000\e4500F5",
+ PDE->Entries[PDEIndex].UserSupervisor ? "\e00FF001\e4500F5" : "\eFF00000\e4500F5",
+ PDE->Entries[PDEIndex].WriteThrough ? "\e00FF001\e4500F5" : "\eFF00000\e4500F5",
+ PDE->Entries[PDEIndex].CacheDisable ? "\e00FF001\e4500F5" : "\eFF00000\e4500F5",
+ PDE->Entries[PDEIndex].Accessed ? "\e00FF001\e4500F5" : "\eFF00000\e4500F5",
+ PDE->Entries[PDEIndex].ExecuteDisable ? "\e00FF001\e4500F5" : "\eFF00000\e4500F5",
+ PDE->Entries[PDEIndex].GetAddress() << 12);
+ Display->SetBuffer(SBIdx);
+ if ((PDE->Entries[PDEIndex].Present))
+ {
+ Memory::PageTableEntryPtr *PTE = (Memory::PageTableEntryPtr *)((uintptr_t)PDE->Entries[PDEIndex].GetAddress() << 12);
+ if (PTE)
+ {
+ for (int PTEIndex = 0; PTEIndex < 512; PTEIndex++)
+ {
+ EHPrint("\e888888# \eAABBCC%03d-%03d-%03d-%03d\e4500F5: P:%s RW:%s US:%s PWT:%s PCB:%s A:%s D:%s PAT:%s G:%s PK:%d NX:%s Address:\e888888%#lx\n",
+ PMLIndex, PDPTEIndex, PDEIndex, PTEIndex,
+ PTE->Entries[PTEIndex].Present ? "\e00FF001\e4500F5" : "\eFF00000\e4500F5",
+ PTE->Entries[PTEIndex].ReadWrite ? "\e00FF001\e4500F5" : "\eFF00000\e4500F5",
+ PTE->Entries[PTEIndex].UserSupervisor ? "\e00FF001\e4500F5" : "\eFF00000\e4500F5",
+ PTE->Entries[PTEIndex].WriteThrough ? "\e00FF001\e4500F5" : "\eFF00000\e4500F5",
+ PTE->Entries[PTEIndex].CacheDisable ? "\e00FF001\e4500F5" : "\eFF00000\e4500F5",
+ PTE->Entries[PTEIndex].Accessed ? "\e00FF001\e4500F5" : "\eFF00000\e4500F5",
+ PTE->Entries[PTEIndex].Dirty ? "\e00FF001\e4500F5" : "\eFF00000\e4500F5",
+ PTE->Entries[PTEIndex].PageAttributeTable ? "\e00FF001\e4500F5" : "\eFF00000\e4500F5",
+ PTE->Entries[PTEIndex].Global ? "\e00FF001\e4500F5" : "\eFF00000\e4500F5",
+ PTE->Entries[PTEIndex].ProtectionKey,
+ PTE->Entries[PTEIndex].ExecuteDisable ? "\e00FF001\e4500F5" : "\eFF00000\e4500F5",
+ PTE->Entries[PTEIndex].GetAddress() << 12);
+ Display->SetBuffer(SBIdx);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ else if (strncmp(Input, "bitmap", 6) == 0)
+ {
+ Bitmap bm = KernelAllocator.GetPageBitmap();
+
+ EHPrint("\n\eFAFAFA[0%%] %08ld: ", 0);
+ for (size_t i = 0; i < bm.Size; i++)
+ {
+ if (bm.Get(i))
+ EHPrint("\eFF00001");
+ else
+ EHPrint("\e00FF000");
+ if (i % 128 == 127)
+ {
+ short Percentage = s_cst(short, (i * 100) / bm.Size);
+ EHPrint("\n\eFAFAFA[%03ld%%] %08ld: ", Percentage, i);
+ Display->SetBuffer(SBIdx);
+ }
+ }
+ EHPrint("\n\e22AA44--- END OF BITMAP ---\nBitmap size: %ld\n\n.", bm.Size);
+ Display->SetBuffer(SBIdx);
+ }
+ else if (strcmp(Input, "mem") == 0)
+ {
+ uint64_t Total = KernelAllocator.GetTotalMemory();
+ uint64_t Used = KernelAllocator.GetUsedMemory();
+ uint64_t Free = KernelAllocator.GetFreeMemory();
+ uint64_t Reserved = KernelAllocator.GetReservedMemory();
+
+ EHPrint("\e22AA44Total: %ld bytes\n\eFF0000Used: %ld bytes\n\e00FF00Free: %ld bytes\n\eFF00FFReserved: %ld bytes\n", Total, Used, Free, Reserved);
+ int Progress = s_cst(int, (Used * 100) / Total);
+ int ReservedProgress = s_cst(int, (Reserved * 100) / Total);
+ EHPrint("\e22AA44%3d%% \eCCCCCC[", Progress);
+ for (int i = 0; i < Progress; i++)
+ EHPrint("\eFF0000|");
+ for (int i = 0; i < 100 - Progress; i++)
+ EHPrint("\e00FF00|");
+ for (int i = 0; i < ReservedProgress; i++)
+ EHPrint("\eFF00FF|");
+ EHPrint("\eCCCCCC]\n");
+
+ Display->SetBuffer(SBIdx);
+ }
+ else if (strncmp(Input, "cr", 2) == 0)
+ {
+ char *cr = TrimWhiteSpace(Input + 2);
+ switch (cr[0])
+ {
+ case '0':
+ {
+#if defined(a64)
+ EHPrint("\e44AA000: %#lx\n", CPU::x64::readcr0());
+#elif defined(a32)
+ EHPrint("\e44AA000: %#lx\n", CPU::x32::readcr0());
+#endif
+ break;
+ }
+ case '2':
+ {
+#if defined(a64)
+ EHPrint("\e44AA002: %#lx\n", PageFaultAddress);
+#elif defined(a32)
+ EHPrint("\e44AA002: %#lx\n", CPU::x32::readcr2());
+#endif
+ break;
+ }
+ case '3':
+ {
+#if defined(a64)
+ EHPrint("\e44AA003: %#lx\n", CPU::x64::readcr3());
+#elif defined(a32)
+ EHPrint("\e44AA003: %#lx\n", CPU::x32::readcr3());
+#endif
+ break;
+ }
+ case '4':
+ {
+#if defined(a64)
+ EHPrint("\e44AA004: %#lx\n", CPU::x64::readcr4());
+#elif defined(a32)
+ EHPrint("\e44AA004: %#lx\n", CPU::x32::readcr4());
+#endif
+ break;
+ }
+ case '8':
+ {
+#if defined(a64)
+ EHPrint("\e44AA008: %#lx\n", CPU::x64::readcr8());
+#elif defined(a32)
+ EHPrint("\e44AA008: %#lx\n", CPU::x32::readcr8());
+#endif
+ break;
+ }
+ default:
+ EHPrint("\eFF0000Invalid CR\n");
+ break;
+ }
+ }
+ else if (strncmp(Input, "tss", 3) == 0)
+ {
+ char *arg = TrimWhiteSpace(Input + 3);
+ int TSSIndex = atoi(arg);
+ if (TSSIndex > SMP::CPUCores)
+ {
+ EHPrint("\eFF0000Invalid TSS index\n");
+ }
+ else
+ {
+#if defined(a86)
+ GlobalDescriptorTable::TaskStateSegment tss = GlobalDescriptorTable::tss[TSSIndex];
+ EHPrint("\eFAFAFAStack Pointer 0: \eAABB22%#lx\n", tss.StackPointer[0]);
+ EHPrint("\eFAFAFAStack Pointer 1: \eAABB22%#lx\n", tss.StackPointer[1]);
+ EHPrint("\eFAFAFAStack Pointer 2: \eAABB22%#lx\n", tss.StackPointer[2]);
+
+ EHPrint("\eFAFAFAInterrupt Stack Table: \eAABB22%#lx\n", tss.InterruptStackTable[0]);
+ EHPrint("\eFAFAFAInterrupt Stack Table: \eAABB22%#lx\n", tss.InterruptStackTable[1]);
+ EHPrint("\eFAFAFAInterrupt Stack Table: \eAABB22%#lx\n", tss.InterruptStackTable[2]);
+ EHPrint("\eFAFAFAInterrupt Stack Table: \eAABB22%#lx\n", tss.InterruptStackTable[3]);
+ EHPrint("\eFAFAFAInterrupt Stack Table: \eAABB22%#lx\n", tss.InterruptStackTable[4]);
+ EHPrint("\eFAFAFAInterrupt Stack Table: \eAABB22%#lx\n", tss.InterruptStackTable[5]);
+ EHPrint("\eFAFAFAInterrupt Stack Table: \eAABB22%#lx\n", tss.InterruptStackTable[6]);
+
+ EHPrint("\eFAFAFAI/O Map Base Address Offset: \eAABB22%#lx\n", tss.IOMapBaseAddressOffset);
+
+ EHPrint("\eFAFAFAReserved 0: \eAABB22%#lx\n", tss.Reserved0);
+ EHPrint("\eFAFAFAReserved 1: \eAABB22%#lx\n", tss.Reserved1);
+ EHPrint("\eFAFAFAReserved 2: \eAABB22%#lx\n", tss.Reserved2);
+#elif defined(aa64)
+ EHPrint("\eFF0000AArch64 does not have TSS\n");
+#endif
+ }
+ }
+ else if (strncmp(Input, "dump", 4) == 0)
+ {
+ char *arg = TrimWhiteSpace(Input + 4);
+ char *addr = strtok(arg, " ");
+ char *len = strtok(NULL, " ");
+ if (addr == NULL || len == NULL)
+ {
+ EHPrint("\eFF0000Invalid arguments\n");
+ }
+ else
+ {
+ uint64_t Address = strtoul(addr, NULL, 16);
+ uint64_t Length = strtoul(len, NULL, 10);
+ debug("Dumping %ld bytes from %#lx\n", Length, Address);
+ EHDumpData((void *)Address, Length);
+ }
+ }
+ else if (strncmp(Input, "uartmemdmp", 10) == 0)
+ {
+ char *arg = TrimWhiteSpace(Input + 10);
+ char *cPort = strtok(arg, " ");
+ char *cBoolSkip = strtok(NULL, " ");
+ UniversalAsynchronousReceiverTransmitter::SerialPorts port = UniversalAsynchronousReceiverTransmitter::SerialPorts::COM1;
+ switch (cPort[0])
+ {
+ case '1':
+ port = UniversalAsynchronousReceiverTransmitter::SerialPorts::COM1;
+ break;
+ case '2':
+ port = UniversalAsynchronousReceiverTransmitter::SerialPorts::COM2;
+ break;
+ case '3':
+ port = UniversalAsynchronousReceiverTransmitter::SerialPorts::COM3;
+ break;
+ case '4':
+ port = UniversalAsynchronousReceiverTransmitter::SerialPorts::COM4;
+ break;
+ case '5':
+ port = UniversalAsynchronousReceiverTransmitter::SerialPorts::COM5;
+ break;
+ case '6':
+ port = UniversalAsynchronousReceiverTransmitter::SerialPorts::COM6;
+ break;
+ case '7':
+ port = UniversalAsynchronousReceiverTransmitter::SerialPorts::COM7;
+ break;
+ case '8':
+ port = UniversalAsynchronousReceiverTransmitter::SerialPorts::COM8;
+ break;
+ default:
+ EHPrint("\eFF0000Invalid port! Defaulting to 1.\n");
+ break;
+ }
+ EHPrint("\eF8F8F8Dumping memory to UART port %c (%#lx) and %s inaccessible pages.\n", cPort[0], port, cBoolSkip[0] == '1' ? "skipping" : "zeroing");
+ Display->SetBuffer(SBIdx);
+ uint64_t Length = KernelAllocator.GetTotalMemory();
+ uint64_t ProgressLength = Length;
+ UniversalAsynchronousReceiverTransmitter::UART uart(port);
+ Memory::Virtual vma;
+ uint8_t *Address = reinterpret_cast(0x0);
+ int Progress = 0;
+ for (size_t i = 0; i < Length; i++)
+ {
+ if (vma.Check(Address))
+ uart.Write(*Address);
+ else if (cBoolSkip[0] == '0')
+ uart.Write((uint8_t)0);
+ else
+ ProgressLength--;
+ Address++;
+
+ if (unlikely(i % 0x1000 == 0))
+ {
+ int NewProgress = (int)((i * 100) / ProgressLength);
+ if (unlikely(NewProgress != Progress))
+ {
+ Progress = NewProgress;
+ EHPrint("\n%d%%\n", Progress);
+ Display->SetBuffer(SBIdx);
+ }
+ Display->Print('.', SBIdx);
+ if (unlikely(i % 0x500 == 0))
+ Display->SetBuffer(SBIdx);
+ }
+ }
+ EHPrint("\nDone.\n");
+ }
+ else if (strcmp(Input, "main") == 0)
+ {
+ SBIdx = 255;
+ DisplayTopOverlay();
+ DisplayMainScreen(crashdata);
+ Display->SetBuffer(SBIdx);
+ }
+ else if (strcmp(Input, "details") == 0)
+ {
+ SBIdx = 254;
+ DisplayTopOverlay();
+ DisplayDetailsScreen(crashdata);
+ Display->SetBuffer(SBIdx);
+ }
+ else if (strcmp(Input, "frames") == 0)
+ {
+ SBIdx = 253;
+ DisplayTopOverlay();
+ DisplayStackFrameScreen(crashdata);
+ Display->SetBuffer(SBIdx);
+ }
+ else if (strcmp(Input, "tasks") == 0)
+ {
+ SBIdx = 252;
+ DisplayTopOverlay();
+ DisplayTasksScreen(crashdata);
+ Display->SetBuffer(SBIdx);
+ }
+ else if (strcmp(Input, "console") == 0)
+ {
+ SBIdx = 251;
+ DisplayTopOverlay();
+ DisplayConsoleScreen(crashdata);
+ Display->SetBuffer(SBIdx);
+ }
+ else if (strlen(Input) > 0)
+ EHPrint("Unknown command: %s", Input);
+
+ DisplayBottomOverlay();
+ Display->SetBuffer(SBIdx);
+ }
+
+ SafeFunction void StopAllCores()
+ {
+#if defined(a86)
+ /* FIXME: Can't send IPIs to other cores
+ * because it causes another exception on
+ * the other cores.
+ *
+ * Also it makes every core to stay at 100% usage for some reason.
+ */
+
+ // if (SMP::CPUCores > 1)
+ // {
+ // for (int i = 1; i < SMP::CPUCores; i++)
+ // {
+ // APIC::InterruptCommandRegisterLow icr;
+ // icr.Vector = CPU::x86::IRQ29;
+ // icr.Level = APIC::APICLevel::Assert;
+ // ((APIC::APIC *)Interrupts::apic[i])->IPI(i, icr);
+ // __sync;
+ // }
+ // }
+ // APIC::InterruptCommandRegisterLow icr;
+ // icr.Vector = CPU::x86::IRQ29;
+ // icr.Level = APIC::APICLevel::Assert;
+ // icr.DestinationShorthand = APIC::APICDestinationShorthand::AllExcludingSelf;
+ // ((APIC::APIC *)Interrupts::apic[0])->IPI(0, icr);
+ // CPU::Interrupts(CPU::Enable);
+ __sync;
+ CPU::Interrupts(CPU::Disable);
+ // }
+#elif defined(aa64)
+#endif
+ }
+
+ SafeFunction void Handle(void *Data)
+ {
+ // TODO: SUPPORT SMP
+ CPU::Interrupts(CPU::Disable);
+ SBIdx = 255;
+ CHArchTrapFrame *Frame = (CHArchTrapFrame *)Data;
+#if defined(a64)
+ debug("-----------------------------------------------------------------------------------");
+ error("Exception: %#llx", Frame->InterruptNumber);
+ for (size_t i = 0; i < INT_FRAMES_MAX; i++)
+ EHIntFrames[i] = Interrupts::InterruptFrames[i];
+ PageFaultAddress = CPU::x64::readcr2().PFLA;
+
+ if (Frame->cs != GDT_USER_CODE && Frame->cs != GDT_USER_DATA)
+ {
+ if (PageFaultAddress)
+ {
+ debug("Exception in kernel mode (ip: %#lx cr2: %#lx (%s))",
+ Frame->rip, PageFaultAddress, KernelSymbolTable ? KernelSymbolTable->GetSymbolFromAddress(Frame->rip) : "No symbol");
+ }
+ else
+ {
+ debug("Exception in kernel mode (ip: %#lx (%s))",
+ Frame->rip, KernelSymbolTable ? KernelSymbolTable->GetSymbolFromAddress(Frame->rip) : "No symbol");
+ }
+
+ CPUData *data = GetCurrentCPU();
+ if (data)
+ {
+ if (data->CurrentThread)
+ {
+ if (!data->CurrentThread->Security.IsCritical)
+ {
+ fixme("Exception in non-critical thread (kernel mode)");
+ }
+ }
+ }
+
+ if (TaskManager)
+ TaskManager->Panic();
+ ForceUnlock = true;
+ Display->CreateBuffer(0, 0, SBIdx);
+ StopAllCores();
+ }
+ else
+ {
+ if (PageFaultAddress)
+ {
+ debug("Exception in user mode (ip: %#lx cr2: %#lx (%s))",
+ Frame->rip, PageFaultAddress, KernelSymbolTable ? KernelSymbolTable->GetSymbolFromAddress(Frame->rip) : "No symbol");
+ }
+ else
+ {
+ debug("Exception in user mode (ip: %#lx (%s))",
+ Frame->rip, KernelSymbolTable ? KernelSymbolTable->GetSymbolFromAddress(Frame->rip) : "No symbol");
+ }
+ CPUData *data = GetCurrentCPU();
+ if (!data)
+ {
+ ForceUnlock = true;
+ Display->CreateBuffer(0, 0, SBIdx);
+ StopAllCores();
+ EHPrint("\eFF0000Cannot get CPU data! This results in a kernel crash!");
+ error("Cannot get CPU data! This results in a kernel crash!");
+ error("This should never happen!");
+ }
+ else
+ {
+ debug("CPU %ld data is valid", data->ID);
+ if (data->CurrentThread->Security.IsCritical)
+ {
+ debug("Critical thread \"%s\"(%d) died", data->CurrentThread->Name, data->CurrentThread->ID);
+ if (TaskManager)
+ TaskManager->Panic();
+ ForceUnlock = true;
+ Display->CreateBuffer(0, 0, SBIdx);
+ StopAllCores();
+ }
+ else
+ {
+ debug("Current thread is valid %#lx", data->CurrentThread);
+ UserModeExceptionHandler(Frame);
+ return;
+ }
+ }
+ }
+
+ if (ExceptionOccurred)
+ {
+ SBIdx = 255;
+ Display->ClearBuffer(SBIdx);
+ Display->SetBufferCursor(SBIdx, 0, 0);
+
+ CPU::x64::CR0 cr0 = CPU::x64::readcr0();
+ CPU::x64::CR2 cr2 = CPU::x64::CR2{.PFLA = PageFaultAddress};
+ CPU::x64::CR3 cr3 = CPU::x64::readcr3();
+ CPU::x64::CR4 cr4 = CPU::x64::readcr4();
+ CPU::x64::CR8 cr8 = CPU::x64::readcr8();
+ CPU::x64::EFER efer;
+ efer.raw = CPU::x64::rdmsr(CPU::x64::MSR_EFER);
+ uintptr_t ds;
+ asmv("mov %%ds, %0"
+ : "=r"(ds));
+
+ EHPrint("\eFF2525FS=%#llx GS=%#llx SS=%#llx CS=%#llx DS=%#llx\n",
+ CPU::x64::rdmsr(CPU::x64::MSR_FS_BASE), CPU::x64::rdmsr(CPU::x64::MSR_GS_BASE),
+ Frame->ss, Frame->cs, ds);
+ EHPrint("R8=%#llx R9=%#llx R10=%#llx R11=%#llx\n", Frame->r8, Frame->r9, Frame->r10, Frame->r11);
+ EHPrint("R12=%#llx R13=%#llx R14=%#llx R15=%#llx\n", Frame->r12, Frame->r13, Frame->r14, Frame->r15);
+ EHPrint("RAX=%#llx RBX=%#llx RCX=%#llx RDX=%#llx\n", Frame->rax, Frame->rbx, Frame->rcx, Frame->rdx);
+ EHPrint("RSI=%#llx RDI=%#llx RBP=%#llx RSP=%#llx\n", Frame->rsi, Frame->rdi, Frame->rbp, Frame->rsp);
+ EHPrint("RIP=%#llx RFL=%#llx INT=%#llx ERR=%#llx EFER=%#llx\n", Frame->rip, Frame->rflags.raw, Frame->InterruptNumber, Frame->ErrorCode, efer.raw);
+ EHPrint("CR0=%#llx CR2=%#llx CR3=%#llx CR4=%#llx CR8=%#llx\n", cr0.raw, cr2.raw, cr3.raw, cr4.raw, cr8.raw);
+ EHPrint("CR0: PE:%s MP:%s EM:%s TS:%s\n ET:%s NE:%s WP:%s AM:%s\n NW:%s CD:%s PG:%s\n R0:%#x R1:%#x R2:%#x\n",
+ cr0.PE ? "True " : "False", cr0.MP ? "True " : "False", cr0.EM ? "True " : "False", cr0.TS ? "True " : "False",
+ cr0.ET ? "True " : "False", cr0.NE ? "True " : "False", cr0.WP ? "True " : "False", cr0.AM ? "True " : "False",
+ cr0.NW ? "True " : "False", cr0.CD ? "True " : "False", cr0.PG ? "True " : "False",
+ cr0.Reserved0, cr0.Reserved1, cr0.Reserved2);
+ EHPrint("CR2: PFLA: %#llx\n",
+ cr2.PFLA);
+ EHPrint("CR3: PWT:%s PCD:%s PDBR:%#llx\n",
+ cr3.PWT ? "True " : "False", cr3.PCD ? "True " : "False", cr3.PDBR);
+ EHPrint("CR4: VME:%s PVI:%s TSD:%s DE:%s\n PSE:%s PAE:%s MCE:%s PGE:%s\n PCE:%s UMIP:%s OSFXSR:%s OSXMMEXCPT:%s\n LA57:%s VMXE:%s SMXE:%s PCIDE:%s\n OSXSAVE:%s SMEP:%s SMAP:%s PKE:%s\n R0:%#x R1:%#x R2:%#x\n",
+ cr4.VME ? "True " : "False", cr4.PVI ? "True " : "False", cr4.TSD ? "True " : "False", cr4.DE ? "True " : "False",
+ cr4.PSE ? "True " : "False", cr4.PAE ? "True " : "False", cr4.MCE ? "True " : "False", cr4.PGE ? "True " : "False",
+ cr4.PCE ? "True " : "False", cr4.UMIP ? "True " : "False", cr4.OSFXSR ? "True " : "False", cr4.OSXMMEXCPT ? "True " : "False",
+ cr4.LA57 ? "True " : "False", cr4.VMXE ? "True " : "False", cr4.SMXE ? "True " : "False", cr4.PCIDE ? "True " : "False",
+ cr4.OSXSAVE ? "True " : "False", cr4.SMEP ? "True " : "False", cr4.SMAP ? "True " : "False", cr4.PKE ? "True " : "False",
+ cr4.Reserved0, cr4.Reserved1, cr4.Reserved2);
+ EHPrint("CR8: TPL:%d\n", cr8.TPL);
+ EHPrint("RFL: CF:%s PF:%s AF:%s ZF:%s\n SF:%s TF:%s IF:%s DF:%s\n OF:%s IOPL:%s NT:%s RF:%s\n VM:%s AC:%s VIF:%s VIP:%s\n ID:%s AlwaysOne:%d\n R0:%#x R1:%#x R2:%#x R3:%#x\n",
+ Frame->rflags.CF ? "True " : "False", Frame->rflags.PF ? "True " : "False", Frame->rflags.AF ? "True " : "False", Frame->rflags.ZF ? "True " : "False",
+ Frame->rflags.SF ? "True " : "False", Frame->rflags.TF ? "True " : "False", Frame->rflags.IF ? "True " : "False", Frame->rflags.DF ? "True " : "False",
+ Frame->rflags.OF ? "True " : "False", Frame->rflags.IOPL ? "True " : "False", Frame->rflags.NT ? "True " : "False", Frame->rflags.RF ? "True " : "False",
+ Frame->rflags.VM ? "True " : "False", Frame->rflags.AC ? "True " : "False", Frame->rflags.VIF ? "True " : "False", Frame->rflags.VIP ? "True " : "False",
+ Frame->rflags.ID ? "True " : "False", Frame->rflags.AlwaysOne,
+ Frame->rflags.Reserved0, Frame->rflags.Reserved1, Frame->rflags.Reserved2, Frame->rflags.Reserved3);
+ EHPrint("EFER: SCE:%s LME:%s LMA:%s NXE:%s\n SVME:%s LMSLE:%s FFXSR:%s TCE:%s\n R0:%#x R1:%#x R2:%#x\n",
+ efer.SCE ? "True " : "False", efer.LME ? "True " : "False", efer.LMA ? "True " : "False", efer.NXE ? "True " : "False",
+ efer.SVME ? "True " : "False", efer.LMSLE ? "True " : "False", efer.FFXSR ? "True " : "False", efer.TCE ? "True " : "False",
+ efer.Reserved0, efer.Reserved1, efer.Reserved2);
+
+ EHPrint("\nException occurred while handling exception! HALTED!");
+ Display->SetBuffer(SBIdx);
+ Interrupts::RemoveAll();
+ CPU::Stop();
+ }
+
+ ExceptionOccurred = true;
+
+ if (DriverManager)
+ DriverManager->Panic();
+
+ debug("Reading control registers...");
+ crashdata.Frame = Frame;
+ crashdata.cr0 = CPU::x64::readcr0();
+ crashdata.cr2 = CPU::x64::CR2{.PFLA = PageFaultAddress};
+ crashdata.cr3 = CPU::x64::readcr3();
+ crashdata.cr4 = CPU::x64::readcr4();
+ crashdata.cr8 = CPU::x64::readcr8();
+ crashdata.efer.raw = CPU::x64::rdmsr(CPU::x64::MSR_EFER);
+ uintptr_t ds;
+ asmv("mov %%ds, %0"
+ : "=r"(ds));
+
+ // Get debug registers
+ asmv("movq %%dr0, %0"
+ : "=r"(crashdata.dr0));
+ asmv("movq %%dr1, %0"
+ : "=r"(crashdata.dr1));
+ asmv("movq %%dr2, %0"
+ : "=r"(crashdata.dr2));
+ asmv("movq %%dr3, %0"
+ : "=r"(crashdata.dr3));
+ asmv("movq %%dr6, %0"
+ : "=r"(crashdata.dr6));
+ asmv("movq %%dr7, %0"
+ : "=r"(crashdata.dr7));
+
+ CPUData *cpudata = GetCurrentCPU();
+
+ if (cpudata == nullptr)
+ {
+ EHPrint("\eFFA500Invalid CPU data!\n");
+ for (long i = 0; i < MAX_CPU; i++)
+ {
+ cpudata = GetCPU(i);
+ if (cpudata != nullptr)
+ break;
+ if (i == MAX_CPU - 1)
+ {
+ EHPrint("\eFF0000No CPU data found!\n");
+ cpudata = nullptr;
+ }
+ }
+ debug("CPU ptr %#lx", cpudata);
+ }
+
+ if (cpudata != nullptr)
+ {
+ crashdata.ID = cpudata->ID;
+ crashdata.CPUData = cpudata;
+ error("Technical Informations on CPU %lld:", cpudata->ID);
+ }
+
+ if (TaskManager && cpudata != nullptr)
+ {
+ crashdata.Process = cpudata->CurrentProcess.load();
+ crashdata.Thread = cpudata->CurrentThread.load();
+
+ error("Current Process: %s(%ld)",
+ cpudata->CurrentProcess->Name,
+ cpudata->CurrentProcess->ID);
+ error("Current Thread: %s(%ld)",
+ cpudata->CurrentThread->Name,
+ cpudata->CurrentThread->ID);
+ }
+
+ {
+ error("FS=%#llx GS=%#llx SS=%#llx CS=%#llx DS=%#llx",
+ CPU::x64::rdmsr(CPU::x64::MSR_FS_BASE), CPU::x64::rdmsr(CPU::x64::MSR_GS_BASE),
+ Frame->ss, Frame->cs, ds);
+ error("R8=%#llx R9=%#llx R10=%#llx R11=%#llx", Frame->r8, Frame->r9, Frame->r10, Frame->r11);
+ error("R12=%#llx R13=%#llx R14=%#llx R15=%#llx", Frame->r12, Frame->r13, Frame->r14, Frame->r15);
+ error("RAX=%#llx RBX=%#llx RCX=%#llx RDX=%#llx", Frame->rax, Frame->rbx, Frame->rcx, Frame->rdx);
+ error("RSI=%#llx RDI=%#llx RBP=%#llx RSP=%#llx", Frame->rsi, Frame->rdi, Frame->rbp, Frame->rsp);
+ error("RIP=%#llx RFL=%#llx INT=%#llx ERR=%#llx EFER=%#llx", Frame->rip, Frame->rflags.raw, Frame->InterruptNumber, Frame->ErrorCode, crashdata.efer.raw);
+ error("CR0=%#llx CR2=%#llx CR3=%#llx CR4=%#llx CR8=%#llx", crashdata.cr0.raw, crashdata.cr2.raw, crashdata.cr3.raw, crashdata.cr4.raw, crashdata.cr8.raw);
+ error("DR0=%#llx DR1=%#llx DR2=%#llx DR3=%#llx DR6=%#llx DR7=%#llx", crashdata.dr0, crashdata.dr1, crashdata.dr2, crashdata.dr3, crashdata.dr6, crashdata.dr7.raw);
+
+ error("CR0: PE:%s MP:%s EM:%s TS:%s ET:%s NE:%s WP:%s AM:%s NW:%s CD:%s PG:%s R0:%#x R1:%#x R2:%#x",
+ crashdata.cr0.PE ? "True " : "False", crashdata.cr0.MP ? "True " : "False", crashdata.cr0.EM ? "True " : "False", crashdata.cr0.TS ? "True " : "False",
+ crashdata.cr0.ET ? "True " : "False", crashdata.cr0.NE ? "True " : "False", crashdata.cr0.WP ? "True " : "False", crashdata.cr0.AM ? "True " : "False",
+ crashdata.cr0.NW ? "True " : "False", crashdata.cr0.CD ? "True " : "False", crashdata.cr0.PG ? "True " : "False",
+ crashdata.cr0.Reserved0, crashdata.cr0.Reserved1, crashdata.cr0.Reserved2);
+
+ error("CR2: PFLA: %#llx",
+ crashdata.cr2.PFLA);
+
+ error("CR3: PWT:%s PCD:%s PDBR:%#llx",
+ crashdata.cr3.PWT ? "True " : "False", crashdata.cr3.PCD ? "True " : "False", crashdata.cr3.PDBR);
+
+ error("CR4: VME:%s PVI:%s TSD:%s DE:%s PSE:%s PAE:%s MCE:%s PGE:%s PCE:%s UMIP:%s OSFXSR:%s OSXMMEXCPT:%s LA57:%s VMXE:%s SMXE:%s PCIDE:%s OSXSAVE:%s SMEP:%s SMAP:%s PKE:%s R0:%#x R1:%#x R2:%#x",
+ crashdata.cr4.VME ? "True " : "False", crashdata.cr4.PVI ? "True " : "False", crashdata.cr4.TSD ? "True " : "False", crashdata.cr4.DE ? "True " : "False",
+ crashdata.cr4.PSE ? "True " : "False", crashdata.cr4.PAE ? "True " : "False", crashdata.cr4.MCE ? "True " : "False", crashdata.cr4.PGE ? "True " : "False",
+ crashdata.cr4.PCE ? "True " : "False", crashdata.cr4.UMIP ? "True " : "False", crashdata.cr4.OSFXSR ? "True " : "False", crashdata.cr4.OSXMMEXCPT ? "True " : "False",
+ crashdata.cr4.LA57 ? "True " : "False", crashdata.cr4.VMXE ? "True " : "False", crashdata.cr4.SMXE ? "True " : "False", crashdata.cr4.PCIDE ? "True " : "False",
+ crashdata.cr4.OSXSAVE ? "True " : "False", crashdata.cr4.SMEP ? "True " : "False", crashdata.cr4.SMAP ? "True " : "False", crashdata.cr4.PKE ? "True " : "False",
+ crashdata.cr4.Reserved0, crashdata.cr4.Reserved1, crashdata.cr4.Reserved2);
+
+ error("CR8: TPL:%d", crashdata.cr8.TPL);
+
+ error("RFL: CF:%s PF:%s AF:%s ZF:%s SF:%s TF:%s IF:%s DF:%s OF:%s IOPL:%s NT:%s RF:%s VM:%s AC:%s VIF:%s VIP:%s ID:%s AlwaysOne:%d R0:%#x R1:%#x R2:%#x R3:%#x",
+ Frame->rflags.CF ? "True " : "False", Frame->rflags.PF ? "True " : "False", Frame->rflags.AF ? "True " : "False", Frame->rflags.ZF ? "True " : "False",
+ Frame->rflags.SF ? "True " : "False", Frame->rflags.TF ? "True " : "False", Frame->rflags.IF ? "True " : "False", Frame->rflags.DF ? "True " : "False",
+ Frame->rflags.OF ? "True " : "False", Frame->rflags.IOPL ? "True " : "False", Frame->rflags.NT ? "True " : "False", Frame->rflags.RF ? "True " : "False",
+ Frame->rflags.VM ? "True " : "False", Frame->rflags.AC ? "True " : "False", Frame->rflags.VIF ? "True " : "False", Frame->rflags.VIP ? "True " : "False",
+ Frame->rflags.ID ? "True " : "False", Frame->rflags.AlwaysOne,
+ Frame->rflags.Reserved0, Frame->rflags.Reserved1, Frame->rflags.Reserved2, Frame->rflags.Reserved3);
+
+ error("DR7: LDR0:%s GDR0:%s LDR1:%s GDR1:%s LDR2:%s GDR2:%s LDR3:%s GDR3:%s CDR0:%s SDR0:%s CDR1:%s SDR1:%s CDR2:%s SDR2:%s CDR3:%s SDR3:%s R:%#x",
+ crashdata.dr7.LocalDR0 ? "True " : "False", crashdata.dr7.GlobalDR0 ? "True " : "False", crashdata.dr7.LocalDR1 ? "True " : "False", crashdata.dr7.GlobalDR1 ? "True " : "False",
+ crashdata.dr7.LocalDR2 ? "True " : "False", crashdata.dr7.GlobalDR2 ? "True " : "False", crashdata.dr7.LocalDR3 ? "True " : "False", crashdata.dr7.GlobalDR3 ? "True " : "False",
+ crashdata.dr7.ConditionsDR0 ? "True " : "False", crashdata.dr7.SizeDR0 ? "True " : "False", crashdata.dr7.ConditionsDR1 ? "True " : "False", crashdata.dr7.SizeDR1 ? "True " : "False",
+ crashdata.dr7.ConditionsDR2 ? "True " : "False", crashdata.dr7.SizeDR2 ? "True " : "False", crashdata.dr7.ConditionsDR3 ? "True " : "False", crashdata.dr7.SizeDR3 ? "True " : "False",
+ crashdata.dr7.Reserved);
+
+ error("EFER: SCE:%s LME:%s LMA:%s NXE:%s SVME:%s LMSLE:%s FFXSR:%s TCE:%s R0:%#x R1:%#x R2:%#x",
+ crashdata.efer.SCE ? "True " : "False", crashdata.efer.LME ? "True " : "False", crashdata.efer.LMA ? "True " : "False", crashdata.efer.NXE ? "True " : "False",
+ crashdata.efer.SVME ? "True " : "False", crashdata.efer.LMSLE ? "True " : "False", crashdata.efer.FFXSR ? "True " : "False", crashdata.efer.TCE ? "True " : "False",
+ crashdata.efer.Reserved0, crashdata.efer.Reserved1, crashdata.efer.Reserved2);
+ }
+ goto CrashEnd;
+
+#elif defined(a32)
+ goto CrashEnd;
+#elif defined(aa64)
+ goto CrashEnd;
+#endif
+
+ CrashEnd:
+ if (Config.InterruptsOnCrash)
+ {
+ // 255 // Main
+ Display->CreateBuffer(0, 0, 254); // Details
+ Display->CreateBuffer(0, 0, 253); // Frames
+ Display->CreateBuffer(0, 0, 252); // Tasks
+ Display->CreateBuffer(0, 0, 251); // Console
+ Display->CreateBuffer(0, 0, 250); // Empty
+
+ DisplayTopOverlay();
+ DisplayMainScreen(crashdata);
+ DisplayBottomOverlay();
+ Display->SetBuffer(255);
+ debug("Interrupts are enabled, waiting for user input");
+ CPU::Interrupts(CPU::Enable);
+ HookKeyboard();
+ }
+ else
+ {
+ /*
+ TODO: Stuff that should be done when IOC is disabled.
+ */
+ Display->SetBuffer(255);
+ }
+
+ CPU::Halt(true);
+ }
+}
diff --git a/Kernel/Core/Crash/KBDrv.cpp b/Kernel/Core/Crash/KBDrv.cpp
new file mode 100644
index 00000000..19a1e62f
--- /dev/null
+++ b/Kernel/Core/Crash/KBDrv.cpp
@@ -0,0 +1,194 @@
+/*
+ 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 .
+*/
+
+#include "../crashhandler.hpp"
+#include "chfcts.hpp"
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#if defined(a64)
+#include "../../Architecture/amd64/cpu/gdt.hpp"
+#elif defined(a32)
+#elif defined(aa64)
+#endif
+
+#include "../../kernel.h"
+
+const char sc_ascii_low[] = {'?', '?', '1', '2', '3', '4', '5', '6',
+ '7', '8', '9', '0', '-', '=', '?', '?', 'q', 'w', 'e', 'r', 't', 'y',
+ 'u', 'i', 'o', 'p', '[', ']', '?', '?', 'a', 's', 'd', 'f', 'g',
+ 'h', 'j', 'k', 'l', ';', '\'', '`', '?', '\\', 'z', 'x', 'c', 'v',
+ 'b', 'n', 'm', ',', '.', '/', '?', '?', '?', ' '};
+
+const char sc_ascii_high[] = {'?', '?', '!', '@', '#', '$', '%', '^',
+ '&', '*', '(', ')', '_', '+', '?', '?', 'Q', 'W', 'E', 'R', 'T', 'Y',
+ 'U', 'I', 'O', 'P', '{', '}', '?', '?', 'A', 'S', 'D', 'F', 'G',
+ 'H', 'J', 'K', 'L', ';', '\"', '~', '?', '|', 'Z', 'X', 'C', 'V',
+ 'B', 'N', 'M', '<', '>', '?', '?', '?', '?', ' '};
+
+static int LowerCase = true;
+
+static inline int GetLetterFromScanCode(uint8_t ScanCode)
+{
+ if (ScanCode & 0x80)
+ {
+ switch (ScanCode)
+ {
+ case KEY_U_LSHIFT:
+ LowerCase = true;
+ return KEY_INVALID;
+ case KEY_U_RSHIFT:
+ LowerCase = true;
+ return KEY_INVALID;
+ default:
+ return KEY_INVALID;
+ }
+ }
+ else
+ {
+ switch (ScanCode)
+ {
+ case KEY_D_RETURN:
+ return '\n';
+ case KEY_D_LSHIFT:
+ LowerCase = false;
+ return KEY_INVALID;
+ case KEY_D_RSHIFT:
+ LowerCase = false;
+ return KEY_INVALID;
+ case KEY_D_BACKSPACE:
+ return ScanCode;
+ default:
+ {
+ if (ScanCode > 0x39)
+ break;
+ if (LowerCase)
+ return sc_ascii_low[ScanCode];
+ else
+ return sc_ascii_high[ScanCode];
+ }
+ }
+ }
+ return KEY_INVALID;
+}
+
+namespace CrashHandler
+{
+ CrashKeyboardDriver::CrashKeyboardDriver() : Interrupts::Handler(1) /* IRQ1 */
+ {
+#if defined(a86)
+ while (inb(0x64) & 0x1)
+ inb(0x60);
+
+ outb(0x64, 0xAE);
+ outb(0x64, 0x20);
+ uint8_t ret = (inb(0x60) | 1) & ~0x10;
+ outb(0x64, 0x60);
+ outb(0x60, ret);
+ outb(0x60, 0xF4);
+
+ outb(0x21, 0xFD);
+ outb(0xA1, 0xFF);
+#endif // defined(a86)
+
+ CPU::Interrupts(CPU::Enable); // Just to be sure.
+ }
+
+ CrashKeyboardDriver::~CrashKeyboardDriver()
+ {
+ error("CrashKeyboardDriver::~CrashKeyboardDriver() called!");
+ }
+
+ int BackSpaceLimit = 0;
+ static char UserInputBuffer[1024];
+
+#if defined(a64)
+ SafeFunction void CrashKeyboardDriver::OnInterruptReceived(CPU::x64::TrapFrame *Frame)
+#elif defined(a32)
+ SafeFunction void CrashKeyboardDriver::OnInterruptReceived(CPU::x32::TrapFrame *Frame)
+#elif defined(aa64)
+ SafeFunction void CrashKeyboardDriver::OnInterruptReceived(CPU::aarch64::TrapFrame *Frame)
+#endif
+ {
+#if defined(a86)
+ UNUSED(Frame);
+ uint8_t scanCode = inb(0x60);
+ if (scanCode == KEY_D_TAB ||
+ scanCode == KEY_D_LCTRL ||
+ scanCode == KEY_D_LALT ||
+ scanCode == KEY_U_LCTRL ||
+ scanCode == KEY_U_LALT)
+ return;
+
+ switch (scanCode)
+ {
+ case KEY_D_UP:
+ case KEY_D_LEFT:
+ case KEY_D_RIGHT:
+ case KEY_D_DOWN:
+ ArrowInput(scanCode);
+ break;
+ default:
+ break;
+ }
+
+ int key = GetLetterFromScanCode(scanCode);
+ if (key != KEY_INVALID)
+ {
+ if (key == KEY_D_BACKSPACE)
+ {
+ if (BackSpaceLimit > 0)
+ {
+ Display->Print('\b', SBIdx);
+ backspace(UserInputBuffer);
+ BackSpaceLimit--;
+ }
+ }
+ else if (key == '\n')
+ {
+ UserInput(UserInputBuffer);
+ BackSpaceLimit = 0;
+ UserInputBuffer[0] = '\0';
+ }
+ else
+ {
+ append(UserInputBuffer, s_cst(char, key));
+ Display->Print((char)key, SBIdx);
+ BackSpaceLimit++;
+ }
+ Display->SetBuffer(SBIdx); // Update as we type.
+ }
+#endif // a64 || a32
+ }
+
+ SafeFunction void HookKeyboard()
+ {
+ CrashKeyboardDriver kbd; // We don't want to allocate memory.
+#if defined(a86)
+ asmv("KeyboardHookLoop: nop; jmp KeyboardHookLoop;");
+#elif defined(aa64)
+ asmv("KeyboardHookLoop: nop; b KeyboardHookLoop;");
+#endif
+ // CPU::Halt(true); // This is an infinite loop.
+ }
+}
diff --git a/Kernel/Core/Crash/SFrame.cpp b/Kernel/Core/Crash/SFrame.cpp
new file mode 100644
index 00000000..026177f4
--- /dev/null
+++ b/Kernel/Core/Crash/SFrame.cpp
@@ -0,0 +1,148 @@
+/*
+ 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 .
+*/
+
+#include "../crashhandler.hpp"
+#include "chfcts.hpp"
+
+#include
+#include
+#include
+#include
+#include
+
+#if defined(a64)
+#include "../../Architecture/amd64/cpu/gdt.hpp"
+#elif defined(a32)
+#elif defined(aa64)
+#endif
+
+#include "../../kernel.h"
+
+namespace CrashHandler
+{
+ struct StackFrame
+ {
+ struct StackFrame *rbp;
+ uintptr_t rip;
+ };
+
+ SafeFunction void TraceFrames(CRData data, int Count, SymbolResolver::Symbols *SymHandle, bool Kernel)
+ {
+ if (!Memory::Virtual().Check(data.Frame))
+ {
+ EHPrint("Invalid frame pointer: %p\n", data.Frame);
+ return;
+ }
+
+ if (!Memory::Virtual().Check(SymHandle))
+ {
+ EHPrint("Invalid symbol handle: %p\n", SymHandle);
+ return;
+ }
+
+ bool TriedRetryBP = false;
+ struct StackFrame *frames = nullptr;
+ RetryBP:
+#if defined(a64)
+ if (TriedRetryBP == false)
+ frames = (struct StackFrame *)data.Frame->rbp;
+#elif defined(a32)
+ if (TriedRetryBP == false)
+ frames = (struct StackFrame *)data.Frame->ebp;
+#elif defined(aa64)
+#endif
+ if (!Memory::Virtual().Check((void *)frames))
+ {
+ if (TriedRetryBP == false)
+ {
+ frames = (struct StackFrame *)Memory::Virtual(data.Process->PageTable).GetPhysical((void *)frames);
+ TriedRetryBP = true;
+ goto RetryBP;
+ }
+#if defined(a64)
+ EHPrint("Invalid rbp pointer: %p\n", data.Frame->rbp);
+#elif defined(a32)
+ EHPrint("Invalid ebp pointer: %p\n", data.Frame->ebp);
+#elif defined(aa64)
+#endif
+ return;
+ }
+
+ debug("\nStack tracing... %p %d %p %d", data.Frame, Count, frames, Kernel);
+ EHPrint("\e7981FC\nStack Trace:\n");
+ if (!frames || !frames->rip || !frames->rbp)
+ {
+#if defined(a64)
+ EHPrint("\e2565CC%p", (void *)data.Frame->rip);
+#elif defined(a32)
+ EHPrint("\e2565CC%p", (void *)data.Frame->eip);
+#elif defined(aa64)
+#endif
+ EHPrint("\e7925CC-");
+#if defined(a64)
+ EHPrint("\eAA25CC%s", SymHandle->GetSymbolFromAddress(data.Frame->rip));
+#elif defined(a32)
+ EHPrint("\eAA25CC%s", SymHandle->GetSymbolFromAddress(data.Frame->eip));
+#elif defined(aa64)
+#endif
+ EHPrint("\e7981FC <- Exception");
+ EHPrint("\eFF0000\n< No stack trace available. >\n");
+ }
+ else
+ {
+#if defined(a64)
+ EHPrint("\e2565CC%p", (void *)data.Frame->rip);
+ EHPrint("\e7925CC-");
+ if ((data.Frame->rip >= 0xFFFFFFFF80000000 && data.Frame->rip <= (uintptr_t)&_kernel_end) || !Kernel)
+ EHPrint("\eAA25CC%s", SymHandle->GetSymbolFromAddress(data.Frame->rip));
+ else
+ EHPrint("Outside Kernel");
+#elif defined(a32)
+ EHPrint("\e2565CC%p", (void *)data.Frame->eip);
+ EHPrint("\e7925CC-");
+ if ((data.Frame->eip >= 0xC0000000 && data.Frame->eip <= (uintptr_t)&_kernel_end) || !Kernel)
+ EHPrint("\eAA25CC%s", SymHandle->GetSymbolFromAddress(data.Frame->eip));
+ else
+ EHPrint("Outside Kernel");
+#elif defined(aa64)
+#endif
+ EHPrint("\e7981FC <- Exception");
+ for (int frame = 0; frame < Count; ++frame)
+ {
+ if (!frames->rip)
+ break;
+ EHPrint("\n\e2565CC%p", (void *)frames->rip);
+ EHPrint("\e7925CC-");
+#if defined(a64)
+ if ((frames->rip >= 0xFFFFFFFF80000000 && frames->rip <= (uintptr_t)&_kernel_end) || !Kernel)
+#elif defined(a32)
+ if ((frames->rip >= 0xC0000000 && frames->rip <= (uintptr_t)&_kernel_end) || !Kernel)
+#elif defined(aa64)
+ if ((frames->rip >= 0xFFFFFFFF80000000 && frames->rip <= (uintptr_t)&_kernel_end) || !Kernel)
+#endif
+ EHPrint("\e25CCC9%s", SymHandle->GetSymbolFromAddress(frames->rip));
+ else
+ EHPrint("\eFF4CA9Outside Kernel");
+
+ if (!Memory::Virtual().Check(frames->rbp))
+ return;
+ frames = frames->rbp;
+ }
+ }
+ EHPrint("\n");
+ }
+}
diff --git a/Kernel/Core/Crash/Screens/Console.cpp b/Kernel/Core/Crash/Screens/Console.cpp
new file mode 100644
index 00000000..44da0909
--- /dev/null
+++ b/Kernel/Core/Crash/Screens/Console.cpp
@@ -0,0 +1,42 @@
+/*
+ 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 .
+*/
+
+#include "../../crashhandler.hpp"
+#include "../chfcts.hpp"
+
+#include
+#include
+#include
+#include
+#include
+
+#if defined(a64)
+#include "../../../Architecture/amd64/cpu/gdt.hpp"
+#elif defined(a32)
+#elif defined(aa64)
+#endif
+
+#include "../../../kernel.h"
+
+namespace CrashHandler
+{
+ SafeFunction void DisplayConsoleScreen(CRData data)
+ {
+ EHPrint("TODO");
+ UNUSED(data);
+ }
+}
\ No newline at end of file
diff --git a/Kernel/Core/Crash/Screens/Details.cpp b/Kernel/Core/Crash/Screens/Details.cpp
new file mode 100644
index 00000000..f23e97db
--- /dev/null
+++ b/Kernel/Core/Crash/Screens/Details.cpp
@@ -0,0 +1,267 @@
+/*
+ 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 .
+*/
+
+#include "../../crashhandler.hpp"
+#include "../chfcts.hpp"
+
+#include
+#include
+#include
+#include
+#include
+
+#if defined(a64)
+#include "../../../Architecture/amd64/cpu/gdt.hpp"
+#elif defined(a32)
+#elif defined(aa64)
+#endif
+
+#include "../../../kernel.h"
+
+namespace CrashHandler
+{
+ SafeFunction void DisplayDetailsScreen(CRData data)
+ {
+ if (data.Process)
+ EHPrint("\e7981FCCurrent Process: %s(%ld)\n",
+ data.Process->Name,
+ data.Process->ID);
+ if (data.Thread)
+ EHPrint("\e7981FCCurrent Thread: %s(%ld)\n",
+ data.Thread->Name,
+ data.Thread->ID);
+ EHPrint("\e7981FCTechnical Informations on CPU %lld:\n", data.ID);
+ uintptr_t ds;
+#if defined(a64)
+
+ CPUData *cpu = (CPUData *)data.CPUData;
+ if (cpu)
+ {
+ EHPrint("\eE46CEBCPU Data Address: %#lx\n", cpu);
+ EHPrint("Syscalls Stack: %#lx, TempStack: %#lx\n", cpu->SystemCallStack, cpu->TempStack);
+ EHPrint("Core Stack: %#lx, Core ID: %ld, Error Code: %ld\n", cpu->Stack, cpu->ID, cpu->ErrorCode);
+ EHPrint("Is Active: %s\n", cpu->IsActive ? "true" : "false");
+ EHPrint("Current Process: %#lx, Current Thread: %#lx\n", cpu->CurrentProcess, cpu->CurrentThread);
+ EHPrint("Arch Specific Data: %#lx\n", cpu->Data);
+ EHPrint("Checksum: 0x%X\n", cpu->Checksum);
+ }
+
+ asmv("mov %%ds, %0"
+ : "=r"(ds));
+#elif defined(a32)
+ asmv("mov %%ds, %0"
+ : "=r"(ds));
+#elif defined(aa64)
+#endif
+
+#if defined(a64)
+ EHPrint("\e7981FCFS=%#llx GS=%#llx SS=%#llx CS=%#llx DS=%#llx\n",
+ CPU::x64::rdmsr(CPU::x64::MSR_FS_BASE), CPU::x64::rdmsr(CPU::x64::MSR_GS_BASE),
+ data.Frame->ss, data.Frame->cs, ds);
+ EHPrint("R8=%#llx R9=%#llx R10=%#llx R11=%#llx\n", data.Frame->r8, data.Frame->r9, data.Frame->r10, data.Frame->r11);
+ EHPrint("R12=%#llx R13=%#llx R14=%#llx R15=%#llx\n", data.Frame->r12, data.Frame->r13, data.Frame->r14, data.Frame->r15);
+ EHPrint("RAX=%#llx RBX=%#llx RCX=%#llx RDX=%#llx\n", data.Frame->rax, data.Frame->rbx, data.Frame->rcx, data.Frame->rdx);
+ EHPrint("RSI=%#llx RDI=%#llx RBP=%#llx RSP=%#llx\n", data.Frame->rsi, data.Frame->rdi, data.Frame->rbp, data.Frame->rsp);
+ EHPrint("RIP=%#llx RFL=%#llx INT=%#llx ERR=%#llx EFER=%#llx\n", data.Frame->rip, data.Frame->rflags.raw, data.Frame->InterruptNumber, data.Frame->ErrorCode, data.efer.raw);
+#elif defined(a32)
+ EHPrint("\e7981FCFS=%#llx GS=%#llx SS=%#llx CS=%#llx DS=%#llx\n",
+ CPU::x32::rdmsr(CPU::x32::MSR_FS_BASE), CPU::x32::rdmsr(CPU::x32::MSR_GS_BASE),
+ data.Frame->ss, data.Frame->cs, ds);
+ EHPrint("EAX=%#llx EBX=%#llx ECX=%#llx EDX=%#llx\n", data.Frame->eax, data.Frame->ebx, data.Frame->ecx, data.Frame->edx);
+ EHPrint("ESI=%#llx EDI=%#llx EBP=%#llx ESP=%#llx\n", data.Frame->esi, data.Frame->edi, data.Frame->ebp, data.Frame->esp);
+ EHPrint("EIP=%#llx EFL=%#llx INT=%#llx ERR=%#llx EFER=%#llx\n", data.Frame->eip, data.Frame->eflags.raw, data.Frame->InterruptNumber, data.Frame->ErrorCode, data.efer.raw);
+#elif defined(aa64)
+#endif
+
+#if defined(a86)
+ EHPrint("CR0=%#llx CR2=%#llx CR3=%#llx CR4=%#llx CR8=%#llx\n", data.cr0.raw, data.cr2.raw, data.cr3.raw, data.cr4.raw, data.cr8.raw);
+ EHPrint("DR0=%#llx DR1=%#llx DR2=%#llx DR3=%#llx DR6=%#llx DR7=%#llx\n", data.dr0, data.dr1, data.dr2, data.dr3, data.dr6, data.dr7.raw);
+
+ EHPrint("\eFC797BCR0: PE:%s MP:%s EM:%s TS:%s\n ET:%s NE:%s WP:%s AM:%s\n NW:%s CD:%s PG:%s\n R0:%#x R1:%#x R2:%#x\n",
+ data.cr0.PE ? "True " : "False", data.cr0.MP ? "True " : "False", data.cr0.EM ? "True " : "False", data.cr0.TS ? "True " : "False",
+ data.cr0.ET ? "True " : "False", data.cr0.NE ? "True " : "False", data.cr0.WP ? "True " : "False", data.cr0.AM ? "True " : "False",
+ data.cr0.NW ? "True " : "False", data.cr0.CD ? "True " : "False", data.cr0.PG ? "True " : "False",
+ data.cr0.Reserved0, data.cr0.Reserved1, data.cr0.Reserved2);
+
+ EHPrint("\eFCBD79CR2: PFLA: %#llx\n",
+ data.cr2.PFLA);
+
+ EHPrint("\e79FC84CR3: PWT:%s PCD:%s PDBR:%#llx\n",
+ data.cr3.PWT ? "True " : "False", data.cr3.PCD ? "True " : "False", data.cr3.PDBR);
+
+ EHPrint("\eBD79FCCR4: VME:%s PVI:%s TSD:%s DE:%s\n PSE:%s PAE:%s MCE:%s PGE:%s\n PCE:%s UMIP:%s OSFXSR:%s OSXMMEXCPT:%s\n LA57:%s VMXE:%s SMXE:%s PCIDE:%s\n OSXSAVE:%s SMEP:%s SMAP:%s PKE:%s\n R0:%#x R1:%#x R2:%#x\n",
+ data.cr4.VME ? "True " : "False", data.cr4.PVI ? "True " : "False", data.cr4.TSD ? "True " : "False", data.cr4.DE ? "True " : "False",
+ data.cr4.PSE ? "True " : "False", data.cr4.PAE ? "True " : "False", data.cr4.MCE ? "True " : "False", data.cr4.PGE ? "True " : "False",
+ data.cr4.PCE ? "True " : "False", data.cr4.UMIP ? "True " : "False", data.cr4.OSFXSR ? "True " : "False", data.cr4.OSXMMEXCPT ? "True " : "False",
+ data.cr4.LA57 ? "True " : "False", data.cr4.VMXE ? "True " : "False", data.cr4.SMXE ? "True " : "False", data.cr4.PCIDE ? "True " : "False",
+ data.cr4.OSXSAVE ? "True " : "False", data.cr4.SMEP ? "True " : "False", data.cr4.SMAP ? "True " : "False", data.cr4.PKE ? "True " : "False",
+#if defined(a64)
+ data.cr4.Reserved0, data.cr4.Reserved1, data.cr4.Reserved2);
+#elif defined(a32)
+ data.cr4.Reserved0, data.cr4.Reserved1, 0);
+#endif
+ EHPrint("\e79FCF5CR8: TPL:%d\n", data.cr8.TPL);
+#endif // a64 || a32
+
+#if defined(a64)
+ EHPrint("\eFCFC02RFL: CF:%s PF:%s AF:%s ZF:%s\n SF:%s TF:%s IF:%s DF:%s\n OF:%s IOPL:%s NT:%s RF:%s\n VM:%s AC:%s VIF:%s VIP:%s\n ID:%s AlwaysOne:%d\n R0:%#x R1:%#x R2:%#x R3:%#x\n",
+ data.Frame->rflags.CF ? "True " : "False", data.Frame->rflags.PF ? "True " : "False", data.Frame->rflags.AF ? "True " : "False", data.Frame->rflags.ZF ? "True " : "False",
+ data.Frame->rflags.SF ? "True " : "False", data.Frame->rflags.TF ? "True " : "False", data.Frame->rflags.IF ? "True " : "False", data.Frame->rflags.DF ? "True " : "False",
+ data.Frame->rflags.OF ? "True " : "False", data.Frame->rflags.IOPL ? "True " : "False", data.Frame->rflags.NT ? "True " : "False", data.Frame->rflags.RF ? "True " : "False",
+ data.Frame->rflags.VM ? "True " : "False", data.Frame->rflags.AC ? "True " : "False", data.Frame->rflags.VIF ? "True " : "False", data.Frame->rflags.VIP ? "True " : "False",
+ data.Frame->rflags.ID ? "True " : "False", data.Frame->rflags.AlwaysOne,
+ data.Frame->rflags.Reserved0, data.Frame->rflags.Reserved1, data.Frame->rflags.Reserved2, data.Frame->rflags.Reserved3);
+#elif defined(a32)
+ EHPrint("\eFCFC02EFL: CF:%s PF:%s AF:%s ZF:%s\n SF:%s TF:%s IF:%s DF:%s\n OF:%s IOPL:%s NT:%s RF:%s\n VM:%s AC:%s VIF:%s VIP:%s\n ID:%s AlwaysOne:%d\n R0:%#x R1:%#x R2:%#x\n",
+ data.Frame->eflags.CF ? "True " : "False", data.Frame->eflags.PF ? "True " : "False", data.Frame->eflags.AF ? "True " : "False", data.Frame->eflags.ZF ? "True " : "False",
+ data.Frame->eflags.SF ? "True " : "False", data.Frame->eflags.TF ? "True " : "False", data.Frame->eflags.IF ? "True " : "False", data.Frame->eflags.DF ? "True " : "False",
+ data.Frame->eflags.OF ? "True " : "False", data.Frame->eflags.IOPL ? "True " : "False", data.Frame->eflags.NT ? "True " : "False", data.Frame->eflags.RF ? "True " : "False",
+ data.Frame->eflags.VM ? "True " : "False", data.Frame->eflags.AC ? "True " : "False", data.Frame->eflags.VIF ? "True " : "False", data.Frame->eflags.VIP ? "True " : "False",
+ data.Frame->eflags.ID ? "True " : "False", data.Frame->eflags.AlwaysOne,
+ data.Frame->eflags.Reserved0, data.Frame->eflags.Reserved1, data.Frame->eflags.Reserved2);
+#elif defined(aa64)
+#endif
+
+#if defined(a86)
+ EHPrint("\eA0F0F0DR7: LDR0:%s GDR0:%s LDR1:%s GDR1:%s\n LDR2:%s GDR2:%s LDR3:%s GDR3:%s\n CDR0:%s SDR0:%s CDR1:%s SDR1:%s\n CDR2:%s SDR2:%s CDR3:%s SDR3:%s\n R:%#x\n",
+ data.dr7.LocalDR0 ? "True " : "False", data.dr7.GlobalDR0 ? "True " : "False", data.dr7.LocalDR1 ? "True " : "False", data.dr7.GlobalDR1 ? "True " : "False",
+ data.dr7.LocalDR2 ? "True " : "False", data.dr7.GlobalDR2 ? "True " : "False", data.dr7.LocalDR3 ? "True " : "False", data.dr7.GlobalDR3 ? "True " : "False",
+ data.dr7.ConditionsDR0 ? "True " : "False", data.dr7.SizeDR0 ? "True " : "False", data.dr7.ConditionsDR1 ? "True " : "False", data.dr7.SizeDR1 ? "True " : "False",
+ data.dr7.ConditionsDR2 ? "True " : "False", data.dr7.SizeDR2 ? "True " : "False", data.dr7.ConditionsDR3 ? "True " : "False", data.dr7.SizeDR3 ? "True " : "False",
+ data.dr7.Reserved);
+
+ EHPrint("\e009FF0EFER: SCE:%s LME:%s LMA:%s NXE:%s\n SVME:%s LMSLE:%s FFXSR:%s TCE:%s\n R0:%#x R1:%#x R2:%#x\n",
+ data.efer.SCE ? "True " : "False", data.efer.LME ? "True " : "False", data.efer.LMA ? "True " : "False", data.efer.NXE ? "True " : "False",
+ data.efer.SVME ? "True " : "False", data.efer.LMSLE ? "True " : "False", data.efer.FFXSR ? "True " : "False", data.efer.TCE ? "True " : "False",
+ data.efer.Reserved0, data.efer.Reserved1, data.efer.Reserved2);
+#endif
+
+ switch (data.Frame->InterruptNumber)
+ {
+ case CPU::x86::DivideByZero:
+ {
+ DivideByZeroExceptionHandler(data.Frame);
+ break;
+ }
+ case CPU::x86::Debug:
+ {
+ DebugExceptionHandler(data.Frame);
+ break;
+ }
+ case CPU::x86::NonMaskableInterrupt:
+ {
+ NonMaskableInterruptExceptionHandler(data.Frame);
+ break;
+ }
+ case CPU::x86::Breakpoint:
+ {
+ BreakpointExceptionHandler(data.Frame);
+ break;
+ }
+ case CPU::x86::Overflow:
+ {
+ OverflowExceptionHandler(data.Frame);
+ break;
+ }
+ case CPU::x86::BoundRange:
+ {
+ BoundRangeExceptionHandler(data.Frame);
+ break;
+ }
+ case CPU::x86::InvalidOpcode:
+ {
+ InvalidOpcodeExceptionHandler(data.Frame);
+ break;
+ }
+ case CPU::x86::DeviceNotAvailable:
+ {
+ DeviceNotAvailableExceptionHandler(data.Frame);
+ break;
+ }
+ case CPU::x86::DoubleFault:
+ {
+ DoubleFaultExceptionHandler(data.Frame);
+ break;
+ }
+ case CPU::x86::CoprocessorSegmentOverrun:
+ {
+ CoprocessorSegmentOverrunExceptionHandler(data.Frame);
+ break;
+ }
+ case CPU::x86::InvalidTSS:
+ {
+ InvalidTSSExceptionHandler(data.Frame);
+ break;
+ }
+ case CPU::x86::SegmentNotPresent:
+ {
+ SegmentNotPresentExceptionHandler(data.Frame);
+ break;
+ }
+ case CPU::x86::StackSegmentFault:
+ {
+ StackFaultExceptionHandler(data.Frame);
+ break;
+ }
+ case CPU::x86::GeneralProtectionFault:
+ {
+ GeneralProtectionExceptionHandler(data.Frame);
+ break;
+ }
+ case CPU::x86::PageFault:
+ {
+ PageFaultExceptionHandler(data.Frame);
+ break;
+ }
+ case CPU::x86::x87FloatingPoint:
+ {
+ x87FloatingPointExceptionHandler(data.Frame);
+ break;
+ }
+ case CPU::x86::AlignmentCheck:
+ {
+ AlignmentCheckExceptionHandler(data.Frame);
+ break;
+ }
+ case CPU::x86::MachineCheck:
+ {
+ MachineCheckExceptionHandler(data.Frame);
+ break;
+ }
+ case CPU::x86::SIMDFloatingPoint:
+ {
+ SIMDFloatingPointExceptionHandler(data.Frame);
+ break;
+ }
+ case CPU::x86::Virtualization:
+ {
+ VirtualizationExceptionHandler(data.Frame);
+ break;
+ }
+ case CPU::x86::Security:
+ {
+ SecurityExceptionHandler(data.Frame);
+ break;
+ }
+ default:
+ {
+ UnknownExceptionHandler(data.Frame);
+ break;
+ }
+ }
+ }
+}
diff --git a/Kernel/Core/Crash/Screens/Main.cpp b/Kernel/Core/Crash/Screens/Main.cpp
new file mode 100644
index 00000000..437324fc
--- /dev/null
+++ b/Kernel/Core/Crash/Screens/Main.cpp
@@ -0,0 +1,390 @@
+/*
+ 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 .
+*/
+
+#include "../../crashhandler.hpp"
+#include "../chfcts.hpp"
+
+#include
+#include
+#include
+#include
+#include
+
+#if defined(a64)
+#include "../../../Architecture/amd64/cpu/gdt.hpp"
+#elif defined(a32)
+#elif defined(aa64)
+#endif
+
+#include "../../../kernel.h"
+
+static const char *PagefaultDescriptions[8] = {
+ "Supervisory process tried to read a non-present page entry\n",
+ "Supervisory process tried to read a page and caused a protection fault\n",
+ "Supervisory process tried to write to a non-present page entry\n",
+ "Supervisory process tried to write a page and caused a protection fault\n",
+ "User process tried to read a non-present page entry\n",
+ "User process tried to read a page and caused a protection fault\n",
+ "User process tried to write to a non-present page entry\n",
+ "User process tried to write a page and caused a protection fault\n"};
+
+namespace CrashHandler
+{
+ SafeFunction void DisplayMainScreen(CRData data)
+ {
+ CHArchTrapFrame *Frame = data.Frame;
+
+ /*
+ _______ ___ ___ _______ _______ _______ _______ ______ ______ _______ _______ _______ _______ _____
+| __| | | __|_ _| ___| | | | | __ \ _ | __| | | ___| \
+|__ |\ /|__ | | | | ___| | | ---| < |__ | | ___| -- |
+|_______| |___| |_______| |___| |_______|__|_|__| |______|___|__|___|___|_______|___|___|_______|_____/
+ */
+ EHPrint("\eFF5500 _______ ___ ___ _______ _______ _______ _______ ______ ______ _______ _______ _______ _______ _____ \n");
+ EHPrint("| __| | | __|_ _| ___| | | | | __ \\ _ | __| | | ___| \\ \n");
+ EHPrint("|__ |\\ /|__ | | | | ___| | | ---| < |__ | | ___| -- |\n");
+ EHPrint("|_______| |___| |_______| |___| |_______|__|_|__| |______|___|__|___|___|_______|___|___|_______|_____/ \n\eFAFAFA");
+
+ switch (Frame->InterruptNumber)
+ {
+ case CPU::x86::DivideByZero:
+ {
+ EHPrint("Exception: Divide By Zero\n");
+ EHPrint("The processor attempted to divide a number by zero.\n");
+ break;
+ }
+ case CPU::x86::Debug:
+ {
+ EHPrint("Exception: Debug\n");
+ EHPrint("A debug exception has occurred.\n");
+ break;
+ }
+ case CPU::x86::NonMaskableInterrupt:
+ {
+ EHPrint("Exception: Non-Maskable Interrupt\n");
+ EHPrint("A non-maskable interrupt was received.\n");
+ break;
+ }
+ case CPU::x86::Breakpoint:
+ {
+ EHPrint("Exception: Breakpoint\n");
+ EHPrint("The processor encountered a breakpoint.\n");
+ break;
+ }
+ case CPU::x86::Overflow:
+ {
+ EHPrint("Exception: Overflow\n");
+ EHPrint("The processor attempted to add a number to a number that was too large.\n");
+ break;
+ }
+ case CPU::x86::BoundRange:
+ {
+ EHPrint("Exception: Bound Range\n");
+ EHPrint("The processor attempted to access an array element that is out of bounds.\n");
+ break;
+ }
+ case CPU::x86::InvalidOpcode:
+ {
+ EHPrint("Exception: Invalid Opcode\n");
+ EHPrint("The processor attempted to execute an invalid opcode.\n");
+ break;
+ }
+ case CPU::x86::DeviceNotAvailable:
+ {
+ EHPrint("Exception: Device Not Available\n");
+ EHPrint("The processor attempted to use a device that is not available.\n");
+ break;
+ }
+ case CPU::x86::DoubleFault:
+ {
+ EHPrint("Exception: Double Fault\n");
+ EHPrint("The processor encountered a double fault.\n");
+ break;
+ }
+ case CPU::x86::CoprocessorSegmentOverrun:
+ {
+ EHPrint("Exception: Coprocessor Segment Overrun\n");
+ EHPrint("The processor attempted to access a segment that is not available.\n");
+ break;
+ }
+ case CPU::x86::InvalidTSS:
+ {
+ EHPrint("Exception: Invalid TSS\n");
+ EHPrint("The processor attempted to access a task state segment that is not available or valid.\n");
+ CPU::x64::SelectorErrorCode SelCode = {.raw = Frame->ErrorCode};
+ EHPrint("External? %s\n", SelCode.External ? "Yes" : "No");
+ EHPrint("GDT IDT LDT IDT\n");
+ switch (SelCode.Table)
+ {
+ case 0b00:
+ {
+ EHPrint(" ^ \n");
+ EHPrint(" | \n");
+ EHPrint(" %ld\n", SelCode.Idx);
+ break;
+ }
+ case 0b01:
+ {
+ EHPrint(" ^ \n");
+ EHPrint(" | \n");
+ EHPrint(" %ld\n", SelCode.Idx);
+ break;
+ }
+ case 0b10:
+ {
+ EHPrint(" ^ \n");
+ EHPrint(" | \n");
+ EHPrint(" %ld\n", SelCode.Idx);
+ break;
+ }
+ case 0b11:
+ {
+ EHPrint(" ^ \n");
+ EHPrint(" | \n");
+ EHPrint(" %ld\n", SelCode.Idx);
+ break;
+ }
+ default:
+ {
+ EHPrint(" ? \n");
+ EHPrint(" ? \n");
+ EHPrint(" %ld\n", SelCode.Idx);
+ break;
+ }
+ }
+ break;
+ }
+ case CPU::x86::SegmentNotPresent:
+ {
+ EHPrint("Exception: Segment Not Present\n");
+ EHPrint("The processor attempted to access a segment that is not present.\n");
+ CPU::x64::SelectorErrorCode SelCode = {.raw = Frame->ErrorCode};
+ EHPrint("External? %s\n", SelCode.External ? "Yes" : "No");
+ EHPrint("GDT IDT LDT IDT\n");
+ switch (SelCode.Table)
+ {
+ case 0b00:
+ {
+ EHPrint(" ^ \n");
+ EHPrint(" | \n");
+ EHPrint(" %ld\n", SelCode.Idx);
+ break;
+ }
+ case 0b01:
+ {
+ EHPrint(" ^ \n");
+ EHPrint(" | \n");
+ EHPrint(" %ld\n", SelCode.Idx);
+ break;
+ }
+ case 0b10:
+ {
+ EHPrint(" ^ \n");
+ EHPrint(" | \n");
+ EHPrint(" %ld\n", SelCode.Idx);
+ break;
+ }
+ case 0b11:
+ {
+ EHPrint(" ^ \n");
+ EHPrint(" | \n");
+ EHPrint(" %ld\n", SelCode.Idx);
+ break;
+ }
+ default:
+ {
+ EHPrint(" ? \n");
+ EHPrint(" ? \n");
+ EHPrint(" %ld\n", SelCode.Idx);
+ break;
+ }
+ }
+ break;
+ }
+ case CPU::x86::StackSegmentFault:
+ {
+ EHPrint("Exception: Stack Segment Fault\n");
+ CPU::x64::SelectorErrorCode SelCode = {.raw = Frame->ErrorCode};
+ EHPrint("External? %s\n", SelCode.External ? "Yes" : "No");
+ EHPrint("GDT IDT LDT IDT\n");
+ switch (SelCode.Table)
+ {
+ case 0b00:
+ {
+ EHPrint(" ^ \n");
+ EHPrint(" | \n");
+ EHPrint(" %ld\n", SelCode.Idx);
+ break;
+ }
+ case 0b01:
+ {
+ EHPrint(" ^ \n");
+ EHPrint(" | \n");
+ EHPrint(" %ld\n", SelCode.Idx);
+ break;
+ }
+ case 0b10:
+ {
+ EHPrint(" ^ \n");
+ EHPrint(" | \n");
+ EHPrint(" %ld\n", SelCode.Idx);
+ break;
+ }
+ case 0b11:
+ {
+ EHPrint(" ^ \n");
+ EHPrint(" | \n");
+ EHPrint(" %ld\n", SelCode.Idx);
+ break;
+ }
+ default:
+ {
+ EHPrint(" ? \n");
+ EHPrint(" ? \n");
+ EHPrint(" %ld\n", SelCode.Idx);
+ break;
+ }
+ }
+ break;
+ }
+ case CPU::x86::GeneralProtectionFault:
+ {
+ EHPrint("Exception: General Protection Fault\n");
+ EHPrint("Kernel performed an illegal operation.\n");
+ CPU::x64::SelectorErrorCode SelCode = {.raw = Frame->ErrorCode};
+ EHPrint("External? %s\n", SelCode.External ? "Yes" : "No");
+ EHPrint("GDT IDT LDT IDT\n");
+ switch (SelCode.Table)
+ {
+ case 0b00:
+ {
+ EHPrint(" ^ \n");
+ EHPrint(" | \n");
+ EHPrint(" %ld\n", SelCode.Idx);
+ break;
+ }
+ case 0b01:
+ {
+ EHPrint(" ^ \n");
+ EHPrint(" | \n");
+ EHPrint(" %ld\n", SelCode.Idx);
+ break;
+ }
+ case 0b10:
+ {
+ EHPrint(" ^ \n");
+ EHPrint(" | \n");
+ EHPrint(" %ld\n", SelCode.Idx);
+ break;
+ }
+ case 0b11:
+ {
+ EHPrint(" ^ \n");
+ EHPrint(" | \n");
+ EHPrint(" %ld\n", SelCode.Idx);
+ break;
+ }
+ default:
+ {
+ EHPrint(" ? \n");
+ EHPrint(" ? \n");
+ EHPrint(" %ld\n", SelCode.Idx);
+ break;
+ }
+ }
+ break;
+ }
+ case CPU::x86::PageFault:
+ {
+ EHPrint("Exception: Page Fault\n");
+ EHPrint("The processor attempted to access a page that is not present.\n");
+
+ CPU::x64::PageFaultErrorCode params = {.raw = (uint32_t)Frame->ErrorCode};
+#if defined(a64)
+ EHPrint("At \e8888FF%#lx \eFAFAFAby \e8888FF%#lx\eFAFAFA\n", PageFaultAddress, Frame->rip);
+#elif defined(a32)
+ EHPrint("At \e8888FF%#lx \eFAFAFAby \e8888FF%#lx\eFAFAFA\n", PageFaultAddress, Frame->eip);
+#elif defined(aa64)
+#endif
+ EHPrint("Page: %s\eFAFAFA\n", params.P ? "\e058C19Present" : "\eE85230Not Present");
+ EHPrint("Write Operation: \e8888FF%s\eFAFAFA\n", params.W ? "Read-Only" : "Read-Write");
+ EHPrint("Processor Mode: \e8888FF%s\eFAFAFA\n", params.U ? "User-Mode" : "Kernel-Mode");
+ EHPrint("CPU Reserved Bits: %s\eFAFAFA\n", params.R ? "\eE85230Reserved" : "\e058C19Unreserved");
+ EHPrint("Caused By An Instruction Fetch: %s\eFAFAFA\n", params.I ? "\eE85230Yes" : "\e058C19No");
+ EHPrint("Caused By A Protection-Key Violation: %s\eFAFAFA\n", params.PK ? "\eE85230Yes" : "\e058C19No");
+ EHPrint("Caused By A Shadow Stack Access: %s\eFAFAFA\n", params.SS ? "\eE85230Yes" : "\e058C19No");
+ EHPrint("Caused By An SGX Violation: %s\eFAFAFA\n", params.SGX ? "\eE85230Yes" : "\e058C19No");
+ EHPrint("More Info: \e8888FF");
+ if (Frame->ErrorCode & 0x00000008)
+ EHPrint("One or more page directory entries contain reserved bits which are set to 1.\n");
+ else
+ EHPrint(PagefaultDescriptions[Frame->ErrorCode & 0b111]);
+ EHPrint("\eFAFAFA");
+ break;
+ }
+ case CPU::x86::x87FloatingPoint:
+ {
+ EHPrint("Exception: x87 Floating Point\n");
+ EHPrint("The x87 FPU generated an error.\n");
+ break;
+ }
+ case CPU::x86::AlignmentCheck:
+ {
+ EHPrint("Exception: Alignment Check\n");
+ EHPrint("The CPU detected an unaligned memory access.\n");
+ break;
+ }
+ case CPU::x86::MachineCheck:
+ {
+ EHPrint("Exception: Machine Check\n");
+ EHPrint("The CPU detected a hardware error.\n");
+ break;
+ }
+ case CPU::x86::SIMDFloatingPoint:
+ {
+ EHPrint("Exception: SIMD Floating Point\n");
+ EHPrint("The CPU detected an error in the SIMD unit.\n");
+ break;
+ }
+ case CPU::x86::Virtualization:
+ {
+ EHPrint("Exception: Virtualization\n");
+ EHPrint("The CPU detected a virtualization error.\n");
+ break;
+ }
+ case CPU::x86::Security:
+ {
+ EHPrint("Exception: Security\n");
+ EHPrint("The CPU detected a security violation.\n");
+ break;
+ }
+ default:
+ {
+ EHPrint("Exception: Unknown\n");
+ EHPrint("The CPU generated an unknown exception.\n");
+ break;
+ }
+ }
+
+#if defined(a64)
+ EHPrint("The exception happened at \e8888FF%#lx\eFAFAFA\n", Frame->rip);
+#elif defined(a32)
+ EHPrint("The exception happened at \e8888FF%#lx\eFAFAFA\n", Frame->eip);
+#elif defined(aa64)
+#endif
+ }
+}
diff --git a/Kernel/Core/Crash/Screens/StackFrame.cpp b/Kernel/Core/Crash/Screens/StackFrame.cpp
new file mode 100644
index 00000000..0b23cf5b
--- /dev/null
+++ b/Kernel/Core/Crash/Screens/StackFrame.cpp
@@ -0,0 +1,99 @@
+/*
+ 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 .
+*/
+
+#include "../../crashhandler.hpp"
+#include "../chfcts.hpp"
+
+#include
+#include
+#include
+#include
+#include
+#include
+
+#if defined(a64)
+#include "../../../Architecture/amd64/cpu/gdt.hpp"
+#elif defined(a32)
+#elif defined(aa64)
+#endif
+
+#include "../../../kernel.h"
+
+namespace CrashHandler
+{
+ SafeFunction void DisplayStackFrameScreen(CRData data)
+ {
+ EHPrint("\eFAFAFATracing 10 frames...");
+ TraceFrames(data, 10, KernelSymbolTable, true);
+ if (data.Process)
+ {
+ EHPrint("\n\eFAFAFATracing 10 process frames...");
+ SymbolResolver::Symbols *sh = data.Process->ELFSymbolTable;
+ if (!sh)
+ EHPrint("\n\eFF0000< No symbol table available. >\n");
+ else
+ TraceFrames(data, 10, sh, false);
+ }
+ EHPrint("\n\eFAFAFATracing interrupt frames...");
+ for (short i = 0; i < 8; i++)
+ {
+ if (EHIntFrames[i])
+ {
+ if (!Memory::Virtual().Check(EHIntFrames[i]))
+ continue;
+ EHPrint("\n\e2565CC%p", EHIntFrames[i]);
+ EHPrint("\e7925CC-");
+#if defined(a64)
+ if ((uintptr_t)EHIntFrames[i] >= 0xFFFFFFFF80000000 && (uintptr_t)EHIntFrames[i] <= (uintptr_t)&_kernel_end)
+#elif defined(a32)
+ if ((uintptr_t)EHIntFrames[i] >= 0xC0000000 && (uintptr_t)EHIntFrames[i] <= (uintptr_t)&_kernel_end)
+#elif defined(aa64)
+ if ((uintptr_t)EHIntFrames[i] >= 0xFFFFFFFF80000000 && (uintptr_t)EHIntFrames[i] <= (uintptr_t)&_kernel_end)
+#endif
+ EHPrint("\e25CCC9%s", KernelSymbolTable->GetSymbolFromAddress((uintptr_t)EHIntFrames[i]));
+ else
+ EHPrint("\eFF4CA9Outside Kernel");
+ }
+ }
+ if (data.Process && data.Thread)
+ {
+ EHPrint("\n\n\eFAFAFATracing thread instruction pointer history...");
+ SymbolResolver::Symbols *sh = data.Process->ELFSymbolTable;
+ if (!sh)
+ EHPrint("\n\eFFA500Warning: No symbol table available.");
+ int SameItr = 0;
+ uintptr_t LastRIP = 0;
+ for (size_t i = 0; i < sizeof(data.Thread->IPHistory) / sizeof(data.Thread->IPHistory[0]); i++)
+ {
+ if (data.Thread->IPHistory[i] == LastRIP)
+ {
+ SameItr++;
+ if (SameItr > 2)
+ continue;
+ }
+ else
+ SameItr = 0;
+ LastRIP = data.Thread->IPHistory[i];
+ if (!sh)
+ EHPrint("\n\eCCCCCC%d: \e2565CC%p", i, data.Thread->IPHistory[i]);
+ else
+ EHPrint("\n\eCCCCCC%d: \e2565CC%p\e7925CC-\e25CCC9%s", i, data.Thread->IPHistory[i], sh->GetSymbolFromAddress(data.Thread->IPHistory[i]));
+ }
+ EHPrint("\n\e7925CCNote: \e2565CCSame instruction pointers are not shown more than 3 times.\n");
+ }
+ }
+}
diff --git a/Kernel/Core/Crash/Screens/Tasks.cpp b/Kernel/Core/Crash/Screens/Tasks.cpp
new file mode 100644
index 00000000..27be8327
--- /dev/null
+++ b/Kernel/Core/Crash/Screens/Tasks.cpp
@@ -0,0 +1,87 @@
+/*
+ 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 .
+*/
+
+#include "../../crashhandler.hpp"
+#include "../chfcts.hpp"
+
+#include
+#include
+#include
+#include
+#include
+
+#if defined(a64)
+#include "../../../Architecture/amd64/cpu/gdt.hpp"
+#elif defined(a32)
+#elif defined(aa64)
+#endif
+
+#include "../../../kernel.h"
+
+namespace CrashHandler
+{
+ SafeFunction void DisplayTasksScreen(CRData data)
+ {
+ const char *StatusColor[7] = {
+ "FF0000", // Unknown
+ "AAFF00", // Ready
+ "00AA00", // Running
+ "FFAA00", // Sleeping
+ "FFAA00", // Waiting
+ "FF0088", // Stopped
+ "FF0000", // Terminated
+ };
+
+ const char *StatusString[7] = {
+ "Unknown", // Unknown
+ "Ready", // Ready
+ "Running", // Running
+ "Sleeping", // Sleeping
+ "Waiting", // Waiting
+ "Stopped", // Stopped
+ "Terminated", // Terminated
+ };
+
+ std::vector Plist = TaskManager->GetProcessList();
+
+ if (TaskManager)
+ {
+ if (data.Thread)
+#if defined(a64)
+ EHPrint("\eFAFAFACrash occurred in thread \eAA0F0F%s\eFAFAFA(%ld) at \e00AAAA%#lx\n", data.Thread->Name, data.Thread->ID, data.Frame->rip);
+#elif defined(a32)
+ EHPrint("\eFAFAFACrash occurred in thread \eAA0F0F%s\eFAFAFA(%ld) at \e00AAAA%#lx\n", data.Thread->Name, data.Thread->ID, data.Frame->eip);
+#elif defined(aa64)
+#endif
+
+ EHPrint("\eFAFAFAProcess list (%ld):\n", Plist.size());
+ foreach (auto Process in Plist)
+ {
+ EHPrint("\e%s-> \eFAFAFA%s\eCCCCCC(%ld) \e00AAAA%s\eFAFAFA PT:\e00AAAA%#lx\n",
+ StatusColor[Process->Status], Process->Name, Process->ID, StatusString[Process->Status],
+ Process->PageTable);
+
+ foreach (auto Thread in Process->Threads)
+ EHPrint("\e%s -> \eFAFAFA%s\eCCCCCC(%ld) \e00AAAA%s\eFAFAFA Stack:\e00AAAA%#lx\n",
+ StatusColor[Thread->Status], Thread->Name, Thread->ID, StatusString[Thread->Status],
+ Thread->Stack);
+ }
+ }
+ else
+ EHPrint("\eFAFAFATaskManager is not initialized!\n");
+ }
+}
diff --git a/Kernel/Core/Crash/UserHandler.cpp b/Kernel/Core/Crash/UserHandler.cpp
new file mode 100644
index 00000000..89e3958a
--- /dev/null
+++ b/Kernel/Core/Crash/UserHandler.cpp
@@ -0,0 +1,398 @@
+/*
+ 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 .
+*/
+
+#include "../crashhandler.hpp"
+#include "chfcts.hpp"
+
+#include
+#include
+#include
+#include
+#include
+
+#if defined(a64)
+#include "../../Architecture/amd64/cpu/gdt.hpp"
+#elif defined(a32)
+#elif defined(aa64)
+#endif
+
+#include "../../kernel.h"
+
+static const char *PageFaultDescriptions[8] = {
+ "Supervisory process tried to read a non-present page entry\n",
+ "Supervisory process tried to read a page and caused a protection fault\n",
+ "Supervisory process tried to write to a non-present page entry\n",
+ "Supervisory process tried to write a page and caused a protection fault\n",
+ "User process tried to read a non-present page entry\n",
+ "User process tried to read a page and caused a protection fault\n",
+ "User process tried to write to a non-present page entry\n",
+ "User process tried to write a page and caused a protection fault\n"};
+
+SafeFunction void UserModeExceptionHandler(CHArchTrapFrame *Frame)
+{
+ CriticalSection cs;
+ debug("Interrupts? %s.", cs.IsInterruptsEnabled() ? "Yes" : "No");
+ fixme("Handling user mode exception");
+ TaskManager->GetCurrentThread()->Status = Tasking::TaskStatus::Stopped;
+ CPUData *CurCPU = GetCurrentCPU();
+
+ {
+#if defined(a64)
+ CPU::x64::CR0 cr0 = CPU::x64::readcr0();
+ CPU::x64::CR2 cr2 = CPU::x64::CR2{.PFLA = CrashHandler::PageFaultAddress};
+ CPU::x64::CR3 cr3 = CPU::x64::readcr3();
+ CPU::x64::CR4 cr4 = CPU::x64::readcr4();
+ CPU::x64::CR8 cr8 = CPU::x64::readcr8();
+ CPU::x64::EFER efer;
+ efer.raw = CPU::x64::rdmsr(CPU::x64::MSR_EFER);
+
+ error("Technical Informations on CPU %lld:", CurCPU->ID);
+ uintptr_t ds;
+ asmv("mov %%ds, %0"
+ : "=r"(ds));
+#elif defined(a32)
+ CPU::x32::CR0 cr0 = CPU::x32::readcr0();
+ CPU::x32::CR2 cr2 = CPU::x32::CR2{.PFLA = CrashHandler::PageFaultAddress};
+ CPU::x32::CR3 cr3 = CPU::x32::readcr3();
+ CPU::x32::CR4 cr4 = CPU::x32::readcr4();
+ CPU::x32::CR8 cr8 = CPU::x32::readcr8();
+ CPU::x32::EFER efer;
+ efer.raw = CPU::x32::rdmsr(CPU::x32::MSR_EFER);
+
+ error("Technical Informations on CPU %lld:", CurCPU->ID);
+ uintptr_t ds;
+ asmv("mov %%ds, %0"
+ : "=r"(ds));
+#elif defined(aa64)
+#endif
+
+#if defined(a64)
+ error("FS=%#llx GS=%#llx SS=%#llx CS=%#llx DS=%#llx",
+ CPU::x64::rdmsr(CPU::x64::MSR_FS_BASE), CPU::x64::rdmsr(CPU::x64::MSR_GS_BASE),
+ Frame->ss, Frame->cs, ds);
+ error("R8=%#llx R9=%#llx R10=%#llx R11=%#llx", Frame->r8, Frame->r9, Frame->r10, Frame->r11);
+ error("R12=%#llx R13=%#llx R14=%#llx R15=%#llx", Frame->r12, Frame->r13, Frame->r14, Frame->r15);
+ error("RAX=%#llx RBX=%#llx RCX=%#llx RDX=%#llx", Frame->rax, Frame->rbx, Frame->rcx, Frame->rdx);
+ error("RSI=%#llx RDI=%#llx RBP=%#llx RSP=%#llx", Frame->rsi, Frame->rdi, Frame->rbp, Frame->rsp);
+ error("RIP=%#llx RFL=%#llx INT=%#llx ERR=%#llx EFER=%#llx", Frame->rip, Frame->rflags.raw, Frame->InterruptNumber, Frame->ErrorCode, efer.raw);
+#elif defined(a32)
+ error("FS=%#llx GS=%#llx SS=%#llx CS=%#llx DS=%#llx",
+ CPU::x32::rdmsr(CPU::x32::MSR_FS_BASE), CPU::x32::rdmsr(CPU::x32::MSR_GS_BASE),
+ Frame->ss, Frame->cs, ds);
+ error("EAX=%#llx EBX=%#llx ECX=%#llx EDX=%#llx", Frame->eax, Frame->ebx, Frame->ecx, Frame->edx);
+ error("ESI=%#llx EDI=%#llx EBP=%#llx ESP=%#llx", Frame->esi, Frame->edi, Frame->ebp, Frame->esp);
+ error("EIP=%#llx EFL=%#llx INT=%#llx ERR=%#llx EFER=%#llx", Frame->eip, Frame->eflags.raw, Frame->InterruptNumber, Frame->ErrorCode, efer.raw);
+#elif defined(aa64)
+#endif
+
+#if defined(a86)
+ error("CR0=%#llx CR2=%#llx CR3=%#llx CR4=%#llx CR8=%#llx", cr0.raw, cr2.raw, cr3.raw, cr4.raw, cr8.raw);
+
+ error("CR0: PE:%s MP:%s EM:%s TS:%s ET:%s NE:%s WP:%s AM:%s NW:%s CD:%s PG:%s R0:%#x R1:%#x R2:%#x",
+ cr0.PE ? "True " : "False", cr0.MP ? "True " : "False", cr0.EM ? "True " : "False", cr0.TS ? "True " : "False",
+ cr0.ET ? "True " : "False", cr0.NE ? "True " : "False", cr0.WP ? "True " : "False", cr0.AM ? "True " : "False",
+ cr0.NW ? "True " : "False", cr0.CD ? "True " : "False", cr0.PG ? "True " : "False",
+ cr0.Reserved0, cr0.Reserved1, cr0.Reserved2);
+
+ error("CR2: PFLA: %#llx",
+ cr2.PFLA);
+
+ error("CR3: PWT:%s PCD:%s PDBR:%#llx",
+ cr3.PWT ? "True " : "False", cr3.PCD ? "True " : "False", cr3.PDBR);
+#endif // defined(a86)
+
+#if defined(a64)
+ error("CR4: VME:%s PVI:%s TSD:%s DE:%s PSE:%s PAE:%s MCE:%s PGE:%s PCE:%s UMIP:%s OSFXSR:%s OSXMMEXCPT:%s LA57:%s VMXE:%s SMXE:%s PCIDE:%s OSXSAVE:%s SMEP:%s SMAP:%s PKE:%s R0:%#x R1:%#x R2:%#x",
+ cr4.VME ? "True " : "False", cr4.PVI ? "True " : "False", cr4.TSD ? "True " : "False", cr4.DE ? "True " : "False",
+ cr4.PSE ? "True " : "False", cr4.PAE ? "True " : "False", cr4.MCE ? "True " : "False", cr4.PGE ? "True " : "False",
+ cr4.PCE ? "True " : "False", cr4.UMIP ? "True " : "False", cr4.OSFXSR ? "True " : "False", cr4.OSXMMEXCPT ? "True " : "False",
+ cr4.LA57 ? "True " : "False", cr4.VMXE ? "True " : "False", cr4.SMXE ? "True " : "False", cr4.PCIDE ? "True " : "False",
+ cr4.OSXSAVE ? "True " : "False", cr4.SMEP ? "True " : "False", cr4.SMAP ? "True " : "False", cr4.PKE ? "True " : "False",
+ cr4.Reserved0, cr4.Reserved1, cr4.Reserved2);
+#elif defined(a32)
+ error("CR4: VME:%s PVI:%s TSD:%s DE:%s PSE:%s PAE:%s MCE:%s PGE:%s PCE:%s UMIP:%s OSFXSR:%s OSXMMEXCPT:%s LA57:%s VMXE:%s SMXE:%s PCIDE:%s OSXSAVE:%s SMEP:%s SMAP:%s PKE:%s R0:%#x R1:%#x",
+ cr4.VME ? "True " : "False", cr4.PVI ? "True " : "False", cr4.TSD ? "True " : "False", cr4.DE ? "True " : "False",
+ cr4.PSE ? "True " : "False", cr4.PAE ? "True " : "False", cr4.MCE ? "True " : "False", cr4.PGE ? "True " : "False",
+ cr4.PCE ? "True " : "False", cr4.UMIP ? "True " : "False", cr4.OSFXSR ? "True " : "False", cr4.OSXMMEXCPT ? "True " : "False",
+ cr4.LA57 ? "True " : "False", cr4.VMXE ? "True " : "False", cr4.SMXE ? "True " : "False", cr4.PCIDE ? "True " : "False",
+ cr4.OSXSAVE ? "True " : "False", cr4.SMEP ? "True " : "False", cr4.SMAP ? "True " : "False", cr4.PKE ? "True " : "False",
+ cr4.Reserved0, cr4.Reserved1);
+#endif
+
+#if defined(a86)
+ error("CR8: TPL:%d", cr8.TPL);
+#endif // defined(a86)
+
+#if defined(a64)
+ error("RFL: CF:%s PF:%s AF:%s ZF:%s SF:%s TF:%s IF:%s DF:%s OF:%s IOPL:%s NT:%s RF:%s VM:%s AC:%s VIF:%s VIP:%s ID:%s AlwaysOne:%d R0:%#x R1:%#x R2:%#x R3:%#x",
+ Frame->rflags.CF ? "True " : "False", Frame->rflags.PF ? "True " : "False", Frame->rflags.AF ? "True " : "False", Frame->rflags.ZF ? "True " : "False",
+ Frame->rflags.SF ? "True " : "False", Frame->rflags.TF ? "True " : "False", Frame->rflags.IF ? "True " : "False", Frame->rflags.DF ? "True " : "False",
+ Frame->rflags.OF ? "True " : "False", Frame->rflags.IOPL ? "True " : "False", Frame->rflags.NT ? "True " : "False", Frame->rflags.RF ? "True " : "False",
+ Frame->rflags.VM ? "True " : "False", Frame->rflags.AC ? "True " : "False", Frame->rflags.VIF ? "True " : "False", Frame->rflags.VIP ? "True " : "False",
+ Frame->rflags.ID ? "True " : "False", Frame->rflags.AlwaysOne,
+ Frame->rflags.Reserved0, Frame->rflags.Reserved1, Frame->rflags.Reserved2, Frame->rflags.Reserved3);
+#elif defined(a32)
+ error("EFL: CF:%s PF:%s AF:%s ZF:%s SF:%s TF:%s IF:%s DF:%s OF:%s IOPL:%s NT:%s RF:%s VM:%s AC:%s VIF:%s VIP:%s ID:%s AlwaysOne:%d R0:%#x R1:%#x R2:%#x",
+ Frame->eflags.CF ? "True " : "False", Frame->eflags.PF ? "True " : "False", Frame->eflags.AF ? "True " : "False", Frame->eflags.ZF ? "True " : "False",
+ Frame->eflags.SF ? "True " : "False", Frame->eflags.TF ? "True " : "False", Frame->eflags.IF ? "True " : "False", Frame->eflags.DF ? "True " : "False",
+ Frame->eflags.OF ? "True " : "False", Frame->eflags.IOPL ? "True " : "False", Frame->eflags.NT ? "True " : "False", Frame->eflags.RF ? "True " : "False",
+ Frame->eflags.VM ? "True " : "False", Frame->eflags.AC ? "True " : "False", Frame->eflags.VIF ? "True " : "False", Frame->eflags.VIP ? "True " : "False",
+ Frame->eflags.ID ? "True " : "False", Frame->eflags.AlwaysOne,
+ Frame->eflags.Reserved0, Frame->eflags.Reserved1, Frame->eflags.Reserved2);
+#elif defined(aa64)
+#endif
+
+#if defined(a86)
+ error("EFER: SCE:%s LME:%s LMA:%s NXE:%s SVME:%s LMSLE:%s FFXSR:%s TCE:%s R0:%#x R1:%#x R2:%#x",
+ efer.SCE ? "True " : "False", efer.LME ? "True " : "False", efer.LMA ? "True " : "False", efer.NXE ? "True " : "False",
+ efer.SVME ? "True " : "False", efer.LMSLE ? "True " : "False", efer.FFXSR ? "True " : "False", efer.TCE ? "True " : "False",
+ efer.Reserved0, efer.Reserved1, efer.Reserved2);
+#endif // a64 || a32
+ }
+
+ switch (Frame->InterruptNumber)
+ {
+ case CPU::x86::DivideByZero:
+ {
+ break;
+ }
+ case CPU::x86::Debug:
+ {
+ break;
+ }
+ case CPU::x86::NonMaskableInterrupt:
+ {
+ break;
+ }
+ case CPU::x86::Breakpoint:
+ {
+ break;
+ }
+ case CPU::x86::Overflow:
+ {
+ break;
+ }
+ case CPU::x86::BoundRange:
+ {
+ break;
+ }
+ case CPU::x86::InvalidOpcode:
+ {
+ break;
+ }
+ case CPU::x86::DeviceNotAvailable:
+ {
+ break;
+ }
+ case CPU::x86::DoubleFault:
+ {
+ break;
+ }
+ case CPU::x86::CoprocessorSegmentOverrun:
+ {
+ break;
+ }
+ case CPU::x86::InvalidTSS:
+ {
+ break;
+ }
+ case CPU::x86::SegmentNotPresent:
+ {
+ break;
+ }
+ case CPU::x86::StackSegmentFault:
+ {
+ break;
+ }
+ case CPU::x86::GeneralProtectionFault:
+ {
+ break;
+ }
+ case CPU::x86::PageFault:
+ {
+ uintptr_t CheckPageFaultAddress = 0;
+ CPU::x64::PageFaultErrorCode params = {.raw = (uint32_t)Frame->ErrorCode};
+#if defined(a64)
+ CheckPageFaultAddress = CrashHandler::PageFaultAddress;
+ if (CheckPageFaultAddress == 0)
+ CheckPageFaultAddress = Frame->rip;
+
+ error("An exception occurred at %#lx by %#lx", CrashHandler::PageFaultAddress, Frame->rip);
+#elif defined(a32)
+ error("An exception occurred at %#lx by %#lx", CrashHandler::PageFaultAddress, Frame->eip);
+#elif defined(aa64)
+#endif
+ error("Page: %s", params.P ? "Present" : "Not Present");
+ error("Write Operation: %s", params.W ? "Read-Only" : "Read-Write");
+ error("Processor Mode: %s", params.U ? "User-Mode" : "Kernel-Mode");
+ error("CPU Reserved Bits: %s", params.R ? "Reserved" : "Unreserved");
+ error("Caused By An Instruction Fetch: %s", params.I ? "Yes" : "No");
+ error("Caused By A Protection-Key Violation: %s", params.PK ? "Yes" : "No");
+ error("Caused By A Shadow Stack Access: %s", params.SS ? "Yes" : "No");
+ error("Caused By An SGX Violation: %s", params.SGX ? "Yes" : "No");
+ if (Frame->ErrorCode & 0x00000008)
+ error("One or more page directory entries contain reserved bits which are set to 1.");
+ else
+ error(PageFaultDescriptions[Frame->ErrorCode & 0b111]);
+
+#ifdef DEBUG
+ if (CurCPU)
+ {
+ Memory::Virtual vma = Memory::Virtual(CurCPU->CurrentProcess->PageTable);
+ bool PageAvailable = vma.Check((void *)CheckPageFaultAddress);
+ debug("Page available (Check(...)): %s. %s",
+ PageAvailable ? "Yes" : "No",
+ (params.P && !PageAvailable) ? "CR2 == Present; Check() != Present??????" : "CR2 confirms Check() result.");
+
+ if (PageAvailable)
+ {
+ bool Present = vma.Check((void *)CheckPageFaultAddress);
+ bool ReadWrite = vma.Check((void *)CheckPageFaultAddress, Memory::PTFlag::RW);
+ bool User = vma.Check((void *)CheckPageFaultAddress, Memory::PTFlag::US);
+ bool WriteThrough = vma.Check((void *)CheckPageFaultAddress, Memory::PTFlag::PWT);
+ bool CacheDisabled = vma.Check((void *)CheckPageFaultAddress, Memory::PTFlag::PCD);
+ bool Accessed = vma.Check((void *)CheckPageFaultAddress, Memory::PTFlag::A);
+ bool Dirty = vma.Check((void *)CheckPageFaultAddress, Memory::PTFlag::D);
+ bool Global = vma.Check((void *)CheckPageFaultAddress, Memory::PTFlag::G);
+ /* ... */
+
+ debug("Page available: %s", Present ? "Yes" : "No");
+ debug("Page read/write: %s", ReadWrite ? "Yes" : "No");
+ debug("Page user/kernel: %s", User ? "User" : "Kernel");
+ debug("Page write-through: %s", WriteThrough ? "Yes" : "No");
+ debug("Page cache disabled: %s", CacheDisabled ? "Yes" : "No");
+ debug("Page accessed: %s", Accessed ? "Yes" : "No");
+ debug("Page dirty: %s", Dirty ? "Yes" : "No");
+ debug("Page global: %s", Global ? "Yes" : "No");
+
+ if (Present)
+ {
+ uintptr_t CheckPageFaultLinearAddress = (uintptr_t)CheckPageFaultAddress;
+ CheckPageFaultLinearAddress &= 0xFFFFFFFFFFFFF000;
+ debug("%#lx -> %#lx", CheckPageFaultAddress, CheckPageFaultLinearAddress);
+
+ Memory::Virtual::PageMapIndexer Index = Memory::Virtual::PageMapIndexer((uintptr_t)CheckPageFaultLinearAddress);
+ debug("Index for %#lx is PML:%d PDPTE:%d PDE:%d PTE:%d",
+ CheckPageFaultLinearAddress,
+ Index.PMLIndex,
+ Index.PDPTEIndex,
+ Index.PDEIndex,
+ Index.PTEIndex);
+ Memory::PageMapLevel4 PML4 = CurCPU->CurrentProcess->PageTable->Entries[Index.PMLIndex];
+
+ Memory::PageDirectoryPointerTableEntryPtr *PDPTE = (Memory::PageDirectoryPointerTableEntryPtr *)((uintptr_t)PML4.GetAddress() << 12);
+ Memory::PageDirectoryEntryPtr *PDE = (Memory::PageDirectoryEntryPtr *)((uintptr_t)PDPTE->Entries[Index.PDPTEIndex].GetAddress() << 12);
+ Memory::PageTableEntryPtr *PTE = (Memory::PageTableEntryPtr *)((uintptr_t)PDE->Entries[Index.PDEIndex].GetAddress() << 12);
+
+ debug("# %03d-%03d-%03d-%03d: P:%s RW:%s US:%s PWT:%s PCB:%s A:%s NX:%s Address:%#lx",
+ Index.PMLIndex, 0, 0, 0,
+ PML4.Present ? "1" : "0",
+ PML4.ReadWrite ? "1" : "0",
+ PML4.UserSupervisor ? "1" : "0",
+ PML4.WriteThrough ? "1" : "0",
+ PML4.CacheDisable ? "1" : "0",
+ PML4.Accessed ? "1" : "0",
+ PML4.ExecuteDisable ? "1" : "0",
+ PML4.GetAddress() << 12);
+
+ debug("# %03d-%03d-%03d-%03d: P:%s RW:%s US:%s PWT:%s PCB:%s A:%s NX:%s Address:%#lx",
+ Index.PMLIndex, Index.PDPTEIndex, 0, 0,
+ PDPTE->Entries[Index.PDPTEIndex].Present ? "1" : "0",
+ PDPTE->Entries[Index.PDPTEIndex].ReadWrite ? "1" : "0",
+ PDPTE->Entries[Index.PDPTEIndex].UserSupervisor ? "1" : "0",
+ PDPTE->Entries[Index.PDPTEIndex].WriteThrough ? "1" : "0",
+ PDPTE->Entries[Index.PDPTEIndex].CacheDisable ? "1" : "0",
+ PDPTE->Entries[Index.PDPTEIndex].Accessed ? "1" : "0",
+ PDPTE->Entries[Index.PDPTEIndex].ExecuteDisable ? "1" : "0",
+ PDPTE->Entries[Index.PDPTEIndex].GetAddress() << 12);
+
+ debug("# %03d-%03d-%03d-%03d: P:%s RW:%s US:%s PWT:%s PCB:%s A:%s NX:%s Address:%#lx",
+ Index.PMLIndex, Index.PDPTEIndex, Index.PDEIndex, 0,
+ PDE->Entries[Index.PDEIndex].Present ? "1" : "0",
+ PDE->Entries[Index.PDEIndex].ReadWrite ? "1" : "0",
+ PDE->Entries[Index.PDEIndex].UserSupervisor ? "1" : "0",
+ PDE->Entries[Index.PDEIndex].WriteThrough ? "1" : "0",
+ PDE->Entries[Index.PDEIndex].CacheDisable ? "1" : "0",
+ PDE->Entries[Index.PDEIndex].Accessed ? "1" : "0",
+ PDE->Entries[Index.PDEIndex].ExecuteDisable ? "1" : "0",
+ PDE->Entries[Index.PDEIndex].GetAddress() << 12);
+
+ debug("# %03d-%03d-%03d-%03d: P:%s RW:%s US:%s PWT:%s PCB:%s A:%s D:%s PAT:%s G:%s PK:%d NX:%s Address:%#lx",
+ Index.PMLIndex, Index.PDPTEIndex, Index.PDEIndex, Index.PTEIndex,
+ PTE->Entries[Index.PTEIndex].Present ? "1" : "0",
+ PTE->Entries[Index.PTEIndex].ReadWrite ? "1" : "0",
+ PTE->Entries[Index.PTEIndex].UserSupervisor ? "1" : "0",
+ PTE->Entries[Index.PTEIndex].WriteThrough ? "1" : "0",
+ PTE->Entries[Index.PTEIndex].CacheDisable ? "1" : "0",
+ PTE->Entries[Index.PTEIndex].Accessed ? "1" : "0",
+ PTE->Entries[Index.PTEIndex].Dirty ? "1" : "0",
+ PTE->Entries[Index.PTEIndex].PageAttributeTable ? "1" : "0",
+ PTE->Entries[Index.PTEIndex].Global ? "1" : "0",
+ PTE->Entries[Index.PTEIndex].ProtectionKey,
+ PTE->Entries[Index.PTEIndex].ExecuteDisable ? "1" : "0",
+ PTE->Entries[Index.PTEIndex].GetAddress() << 12);
+ }
+ }
+ }
+#endif
+
+ if (CurCPU)
+ if (CurCPU->CurrentThread->Stack->Expand(CrashHandler::PageFaultAddress))
+ {
+ debug("Stack expanded");
+ TaskManager->GetCurrentThread()->Status = Tasking::TaskStatus::Ready;
+ return;
+ }
+ break;
+ }
+ case CPU::x86::x87FloatingPoint:
+ {
+ break;
+ }
+ case CPU::x86::AlignmentCheck:
+ {
+ break;
+ }
+ case CPU::x86::MachineCheck:
+ {
+ break;
+ }
+ case CPU::x86::SIMDFloatingPoint:
+ {
+ break;
+ }
+ case CPU::x86::Virtualization:
+ {
+ break;
+ }
+ case CPU::x86::Security:
+ {
+ break;
+ }
+ default:
+ {
+ break;
+ }
+ }
+
+ TaskManager->GetCurrentThread()->Status = Tasking::TaskStatus::Terminated;
+ __sync;
+ error("End of report.");
+ CPU::Interrupts(CPU::Enable);
+ debug("Interrupts enabled back.");
+ return;
+}
diff --git a/Kernel/Core/Crash/chfcts.hpp b/Kernel/Core/Crash/chfcts.hpp
new file mode 100644
index 00000000..41a7a700
--- /dev/null
+++ b/Kernel/Core/Crash/chfcts.hpp
@@ -0,0 +1,322 @@
+/*
+ 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 .
+*/
+
+#ifndef __FENNIX_KERNEL_CRASH_HANDLERS_FUNCTIONS_H__
+#define __FENNIX_KERNEL_CRASH_HANDLERS_FUNCTIONS_H__
+
+#include
+
+#include
+#include
+#include
+
+#if defined(a64)
+typedef struct CPU::x64::TrapFrame CHArchTrapFrame;
+
+struct CRData
+{
+ CHArchTrapFrame *Frame;
+
+ CPU::x64::CR0 cr0;
+ CPU::x64::CR2 cr2;
+ CPU::x64::CR3 cr3;
+ CPU::x64::CR4 cr4;
+ CPU::x64::CR8 cr8;
+ CPU::x64::EFER efer;
+ uintptr_t dr0, dr1, dr2, dr3, dr6;
+ CPU::x64::DR7 dr7;
+
+ long ID;
+ void *CPUData;
+ Tasking::PCB *Process;
+ Tasking::TCB *Thread;
+};
+
+#elif defined(a32)
+typedef struct CPU::x32::TrapFrame CHArchTrapFrame;
+
+struct CRData
+{
+ CHArchTrapFrame *Frame;
+
+ CPU::x32::CR0 cr0;
+ CPU::x32::CR2 cr2;
+ CPU::x32::CR3 cr3;
+ CPU::x32::CR4 cr4;
+ CPU::x32::CR8 cr8;
+ CPU::x32::EFER efer;
+ uintptr_t dr0, dr1, dr2, dr3, dr6;
+ CPU::x32::DR7 dr7;
+
+ long ID;
+ Tasking::PCB *Process;
+ Tasking::TCB *Thread;
+};
+#elif defined(aa64)
+typedef struct CPU::aarch64::TrapFrame CHArchTrapFrame;
+
+struct CRData
+{
+ CHArchTrapFrame *Frame;
+
+ long ID;
+ Tasking::PCB *Process;
+ Tasking::TCB *Thread;
+};
+#endif
+
+enum Keys
+{
+ KEY_INVALID = 0x0,
+ KEY_D_ESCAPE = 0x1,
+ KEY_D_1 = 0x2,
+ KEY_D_2 = 0x3,
+ KEY_D_3 = 0x4,
+ KEY_D_4 = 0x5,
+ KEY_D_5 = 0x6,
+ KEY_D_6 = 0x7,
+ KEY_D_7 = 0x8,
+ KEY_D_8 = 0x9,
+ KEY_D_9 = 0xa,
+ KEY_D_0 = 0xb,
+ KEY_D_MINUS = 0xc,
+ KEY_D_EQUALS = 0xd,
+ KEY_D_BACKSPACE = 0xe,
+ KEY_D_TAB = 0xf,
+ KEY_D_Q = 0x10,
+ KEY_D_W = 0x11,
+ KEY_D_E = 0x12,
+ KEY_D_R = 0x13,
+ KEY_D_T = 0x14,
+ KEY_D_Y = 0x15,
+ KEY_D_U = 0x16,
+ KEY_D_I = 0x17,
+ KEY_D_O = 0x18,
+ KEY_D_P = 0x19,
+ KEY_D_LBRACKET = 0x1a,
+ KEY_D_RBRACKET = 0x1b,
+ KEY_D_RETURN = 0x1c,
+ KEY_D_LCTRL = 0x1d,
+ KEY_D_A = 0x1e,
+ KEY_D_S = 0x1f,
+ KEY_D_D = 0x20,
+ KEY_D_F = 0x21,
+ KEY_D_G = 0x22,
+ KEY_D_H = 0x23,
+ KEY_D_J = 0x24,
+ KEY_D_K = 0x25,
+ KEY_D_L = 0x26,
+ KEY_D_SEMICOLON = 0x27,
+ KEY_D_APOSTROPHE = 0x28,
+ KEY_D_GRAVE = 0x29,
+ KEY_D_LSHIFT = 0x2a,
+ KEY_D_BACKSLASH = 0x2b,
+ KEY_D_Z = 0x2c,
+ KEY_D_X = 0x2d,
+ KEY_D_C = 0x2e,
+ KEY_D_V = 0x2f,
+ KEY_D_B = 0x30,
+ KEY_D_N = 0x31,
+ KEY_D_M = 0x32,
+ KEY_D_COMMA = 0x33,
+ KEY_D_PERIOD = 0x34,
+ KEY_D_SLASH = 0x35,
+ KEY_D_RSHIFT = 0x36,
+ KEY_D_PRTSC = 0x37,
+ KEY_D_LALT = 0x38,
+ KEY_D_SPACE = 0x39,
+ KEY_D_CAPSLOCK = 0x3a,
+ KEY_D_NUMLOCK = 0x45,
+ KEY_D_SCROLLLOCK = 0x46,
+
+ KEY_D_KP_MULTIPLY = 0x37,
+ KEY_D_KP_7 = 0x47,
+ KEY_D_KP_8 = 0x48,
+ KEY_D_KP_9 = 0x49,
+ KEY_D_KP_MINUS = 0x4a,
+ KEY_D_KP_4 = 0x4b,
+ KEY_D_KP_5 = 0x4c,
+ KEY_D_KP_6 = 0x4d,
+ KEY_D_KP_PLUS = 0x4e,
+ KEY_D_KP_1 = 0x4f,
+ KEY_D_KP_2 = 0x50,
+ KEY_D_KP_3 = 0x51,
+ KEY_D_KP_0 = 0x52,
+ KEY_D_KP_PERIOD = 0x53,
+
+ KEY_D_F1 = 0x3b,
+ KEY_D_F2 = 0x3c,
+ KEY_D_F3 = 0x3d,
+ KEY_D_F4 = 0x3e,
+ KEY_D_F5 = 0x3f,
+ KEY_D_F6 = 0x40,
+ KEY_D_F7 = 0x41,
+ KEY_D_F8 = 0x42,
+ KEY_D_F9 = 0x43,
+ KEY_D_F10 = 0x44,
+ KEY_D_F11 = 0x57,
+ KEY_D_F12 = 0x58,
+
+ KEY_D_UP = 0x48,
+ KEY_D_LEFT = 0x4b,
+ KEY_D_RIGHT = 0x4d,
+ KEY_D_DOWN = 0x50,
+
+ KEY_U_ESCAPE = 0x81,
+ KEY_U_1 = 0x82,
+ KEY_U_2 = 0x83,
+ KEY_U_3 = 0x84,
+ KEY_U_4 = 0x85,
+ KEY_U_5 = 0x86,
+ KEY_U_6 = 0x87,
+ KEY_U_7 = 0x88,
+ KEY_U_8 = 0x89,
+ KEY_U_9 = 0x8a,
+ KEY_U_0 = 0x8b,
+ KEY_U_MINUS = 0x8c,
+ KEY_U_EQUALS = 0x8d,
+ KEY_U_BACKSPACE = 0x8e,
+ KEY_U_TAB = 0x8f,
+ KEY_U_Q = 0x90,
+ KEY_U_W = 0x91,
+ KEY_U_E = 0x92,
+ KEY_U_R = 0x93,
+ KEY_U_T = 0x94,
+ KEY_U_Y = 0x95,
+ KEY_U_U = 0x96,
+ KEY_U_I = 0x97,
+ KEY_U_O = 0x98,
+ KEY_U_P = 0x99,
+ KEY_U_LBRACKET = 0x9a,
+ KEY_U_RBRACKET = 0x9b,
+ KEY_U_RETURN = 0x9c,
+ KEY_U_LCTRL = 0x9d,
+ KEY_U_A = 0x9e,
+ KEY_U_S = 0x9f,
+ KEY_U_D = 0xa0,
+ KEY_U_F = 0xa1,
+ KEY_U_G = 0xa2,
+ KEY_U_H = 0xa3,
+ KEY_U_J = 0xa4,
+ KEY_U_K = 0xa5,
+ KEY_U_L = 0xa6,
+ KEY_U_SEMICOLON = 0xa7,
+ KEY_U_APOSTROPHE = 0xa8,
+ KEY_U_GRAVE = 0xa9,
+ KEY_U_LSHIFT = 0xaa,
+ KEY_U_BACKSLASH = 0xab,
+ KEY_U_Z = 0xac,
+ KEY_U_X = 0xad,
+ KEY_U_C = 0xae,
+ KEY_U_V = 0xaf,
+ KEY_U_B = 0xb0,
+ KEY_U_N = 0xb1,
+ KEY_U_M = 0xb2,
+ KEY_U_COMMA = 0xb3,
+ KEY_U_PERIOD = 0xb4,
+ KEY_U_SLASH = 0xb5,
+ KEY_U_RSHIFT = 0xb6,
+ KEY_U_KP_MULTIPLY = 0xb7,
+ KEY_U_LALT = 0xb8,
+ KEY_U_SPACE = 0xb9,
+ KEY_U_CAPSLOCK = 0xba,
+ KEY_U_F1 = 0xbb,
+ KEY_U_F2 = 0xbc,
+ KEY_U_F3 = 0xbd,
+ KEY_U_F4 = 0xbe,
+ KEY_U_F5 = 0xbf,
+ KEY_U_F6 = 0xc0,
+ KEY_U_F7 = 0xc1,
+ KEY_U_F8 = 0xc2,
+ KEY_U_F9 = 0xc3,
+ KEY_U_F10 = 0xc4,
+ KEY_U_NUMLOCK = 0xc5,
+ KEY_U_SCROLLLOCK = 0xc6,
+ KEY_U_KP_7 = 0xc7,
+ KEY_U_KP_8 = 0xc8,
+ KEY_U_KP_9 = 0xc9,
+ KEY_U_KP_MINUS = 0xca,
+ KEY_U_KP_4 = 0xcb,
+ KEY_U_KP_5 = 0xcc,
+ KEY_U_KP_6 = 0xcd,
+ KEY_U_KP_PLUS = 0xce,
+ KEY_U_KP_1 = 0xcf,
+ KEY_U_KP_2 = 0xd0,
+ KEY_U_KP_3 = 0xd1,
+ KEY_U_KP_0 = 0xd2,
+ KEY_U_KP_PERIOD = 0xd3,
+ KEY_U_F11 = 0xd7,
+ KEY_U_F12 = 0xd8,
+};
+
+namespace CrashHandler
+{
+ extern int SBIdx;
+
+ class CrashKeyboardDriver : public Interrupts::Handler
+ {
+ private:
+#if defined(a64)
+ void OnInterruptReceived(CPU::x64::TrapFrame *Frame);
+#elif defined(a32)
+ void OnInterruptReceived(CPU::x32::TrapFrame *Frame);
+#elif defined(aa64)
+ void OnInterruptReceived(CPU::aarch64::TrapFrame *Frame);
+#endif
+ public:
+ CrashKeyboardDriver();
+ ~CrashKeyboardDriver();
+ };
+
+ void TraceFrames(CRData data, int Count, SymbolResolver::Symbols *SymHandle, bool Kernel);
+
+ void ArrowInput(uint8_t key);
+ void UserInput(char *Input);
+ void HookKeyboard();
+
+ void DisplayMainScreen(CRData data);
+ void DisplayDetailsScreen(CRData data);
+ void DisplayStackFrameScreen(CRData data);
+ void DisplayTasksScreen(CRData data);
+ void DisplayConsoleScreen(CRData data);
+}
+
+void DivideByZeroExceptionHandler(CHArchTrapFrame *Frame);
+void DebugExceptionHandler(CHArchTrapFrame *Frame);
+void NonMaskableInterruptExceptionHandler(CHArchTrapFrame *Frame);
+void BreakpointExceptionHandler(CHArchTrapFrame *Frame);
+void OverflowExceptionHandler(CHArchTrapFrame *Frame);
+void BoundRangeExceptionHandler(CHArchTrapFrame *Frame);
+void InvalidOpcodeExceptionHandler(CHArchTrapFrame *Frame);
+void DeviceNotAvailableExceptionHandler(CHArchTrapFrame *Frame);
+void DoubleFaultExceptionHandler(CHArchTrapFrame *Frame);
+void CoprocessorSegmentOverrunExceptionHandler(CHArchTrapFrame *Frame);
+void InvalidTSSExceptionHandler(CHArchTrapFrame *Frame);
+void SegmentNotPresentExceptionHandler(CHArchTrapFrame *Frame);
+void StackFaultExceptionHandler(CHArchTrapFrame *Frame);
+void GeneralProtectionExceptionHandler(CHArchTrapFrame *Frame);
+void PageFaultExceptionHandler(CHArchTrapFrame *Frame);
+void x87FloatingPointExceptionHandler(CHArchTrapFrame *Frame);
+void AlignmentCheckExceptionHandler(CHArchTrapFrame *Frame);
+void MachineCheckExceptionHandler(CHArchTrapFrame *Frame);
+void SIMDFloatingPointExceptionHandler(CHArchTrapFrame *Frame);
+void VirtualizationExceptionHandler(CHArchTrapFrame *Frame);
+void SecurityExceptionHandler(CHArchTrapFrame *Frame);
+void UnknownExceptionHandler(CHArchTrapFrame *Frame);
+void UserModeExceptionHandler(CHArchTrapFrame *Frame);
+
+#endif // !__FENNIX_KERNEL_CRASH_HANDLERS_FUNCTIONS_H__
diff --git a/Kernel/Core/Debugger.cpp b/Kernel/Core/Debugger.cpp
new file mode 100644
index 00000000..7d29c4ee
--- /dev/null
+++ b/Kernel/Core/Debugger.cpp
@@ -0,0 +1,155 @@
+/*
+ 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 .
+*/
+
+#include
+
+#include
+#include
+#include
+
+NewLock(DebuggerLock);
+
+using namespace UniversalAsynchronousReceiverTransmitter;
+
+static inline NIF void uart_wrapper(char c, void *unused)
+{
+ UART(COM1).Write(c);
+ UNUSED(unused);
+}
+
+static inline NIF void WritePrefix(DebugLevel Level, const char *File, int Line, const char *Function)
+{
+ const char *DbgLvlString;
+ switch (Level)
+ {
+ case DebugLevelError:
+ DbgLvlString = "ERROR";
+ break;
+ case DebugLevelWarning:
+ DbgLvlString = "WARN ";
+ break;
+ case DebugLevelInfo:
+ DbgLvlString = "INFO ";
+ break;
+ case DebugLevelDebug:
+ DbgLvlString = "DEBUG";
+ break;
+ case DebugLevelTrace:
+ DbgLvlString = "TRACE";
+ break;
+ case DebugLevelFixme:
+ DbgLvlString = "FIXME";
+ break;
+ case DebugLevelUbsan:
+ {
+ DbgLvlString = "UBSAN";
+ fctprintf(uart_wrapper, nullptr, "%s|%s: ", DbgLvlString, Function);
+ return;
+ }
+ default:
+ DbgLvlString = "UNKNW";
+ break;
+ }
+ fctprintf(uart_wrapper, nullptr, "%s|%s->%s:%d: ", DbgLvlString, File, Function, Line);
+}
+
+namespace SysDbg
+{
+ NIF void Write(DebugLevel Level, const char *File, int Line, const char *Function, const char *Format, ...)
+ {
+ WritePrefix(Level, File, Line, Function);
+ va_list args;
+ va_start(args, Format);
+ vfctprintf(uart_wrapper, nullptr, Format, args);
+ va_end(args);
+ }
+
+ NIF void WriteLine(DebugLevel Level, const char *File, int Line, const char *Function, const char *Format, ...)
+ {
+ WritePrefix(Level, File, Line, Function);
+ va_list args;
+ va_start(args, Format);
+ vfctprintf(uart_wrapper, nullptr, Format, args);
+ va_end(args);
+ uart_wrapper('\n', nullptr);
+ }
+
+ NIF void LockedWrite(DebugLevel Level, const char *File, int Line, const char *Function, const char *Format, ...)
+ {
+ SmartTimeoutLock(DebuggerLock, 1000);
+ WritePrefix(Level, File, Line, Function);
+ va_list args;
+ va_start(args, Format);
+ vfctprintf(uart_wrapper, nullptr, Format, args);
+ va_end(args);
+ }
+
+ NIF void LockedWriteLine(DebugLevel Level, const char *File, int Line, const char *Function, const char *Format, ...)
+ {
+ SmartTimeoutLock(DebuggerLock, 1000);
+ WritePrefix(Level, File, Line, Function);
+ va_list args;
+ va_start(args, Format);
+ vfctprintf(uart_wrapper, nullptr, Format, args);
+ va_end(args);
+ uart_wrapper('\n', nullptr);
+ }
+}
+
+// C compatibility
+extern "C" NIF void SysDbgWrite(enum DebugLevel Level, const char *File, int Line, const char *Function, const char *Format, ...)
+{
+ WritePrefix(Level, File, Line, Function);
+ va_list args;
+ va_start(args, Format);
+ vfctprintf(uart_wrapper, nullptr, Format, args);
+ va_end(args);
+}
+
+// C compatibility
+extern "C" NIF void SysDbgWriteLine(enum DebugLevel Level, const char *File, int Line, const char *Function, const char *Format, ...)
+{
+ WritePrefix(Level, File, Line, Function);
+ va_list args;
+ va_start(args, Format);
+ vfctprintf(uart_wrapper, nullptr, Format, args);
+ va_end(args);
+ uart_wrapper('\n', nullptr);
+}
+
+// C compatibility
+extern "C" NIF void SysDbgLockedWrite(enum DebugLevel Level, const char *File, int Line, const char *Function, const char *Format, ...)
+{
+ SmartTimeoutLock(DebuggerLock, 1000);
+ WritePrefix(Level, File, Line, Function);
+ va_list args;
+ va_start(args, Format);
+ vfctprintf(uart_wrapper, nullptr, Format, args);
+ va_end(args);
+}
+
+// C compatibility
+extern "C" NIF void SysDbgLockedWriteLine(enum DebugLevel Level, const char *File, int Line, const char *Function, const char *Format, ...)
+{
+ SmartTimeoutLock(DebuggerLock, 1000);
+ WritePrefix(Level, File, Line, Function);
+ va_list args;
+ va_start(args, Format);
+ vfctprintf(uart_wrapper, nullptr, Format, args);
+ va_end(args);
+ uart_wrapper('\n', nullptr);
+}
diff --git a/Kernel/Core/Disk.cpp b/Kernel/Core/Disk.cpp
new file mode 100644
index 00000000..0a734ad9
--- /dev/null
+++ b/Kernel/Core/Disk.cpp
@@ -0,0 +1,169 @@
+/*
+ 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 .
+*/
+
+#include
+
+#include
+#include
+
+#include "../kernel.h"
+#include "../DAPI.hpp"
+#include "../Fex.hpp"
+
+namespace Disk
+{
+ void Manager::FetchDisks(unsigned long DriverUID)
+ {
+ KernelCallback callback{};
+ callback.Reason = FetchReason;
+ DriverManager->IOCB(DriverUID, &callback);
+ this->AvailablePorts = callback.DiskCallback.Fetch.Ports;
+ this->BytesPerSector = callback.DiskCallback.Fetch.BytesPerSector;
+ debug("AvailablePorts:%ld BytesPerSector:%ld", this->AvailablePorts, this->BytesPerSector);
+
+ if (this->AvailablePorts <= 0)
+ return;
+
+ uint8_t *RWBuffer = (uint8_t *)KernelAllocator.RequestPages(TO_PAGES(this->BytesPerSector + 1));
+
+ for (unsigned char ItrPort = 0; ItrPort < this->AvailablePorts; ItrPort++)
+ {
+ Drive drive{};
+ sprintf(drive.Name, "sd%ld-%d", DriverUID, this->AvailablePorts);
+ debug("Drive Name: %s", drive.Name);
+ // TODO: Implement disk type detection. Very useful in the future.
+ drive.MechanicalDisk = true;
+
+ memset(RWBuffer, 0, this->BytesPerSector);
+ callback.Reason = ReceiveReason;
+ callback.DiskCallback.RW = {
+ .Sector = 0,
+ .SectorCount = 2,
+ .Port = ItrPort,
+ .Buffer = RWBuffer,
+ .Write = false,
+ };
+ DriverManager->IOCB(DriverUID, &callback);
+ memcpy(&drive.Table, RWBuffer, sizeof(PartitionTable));
+
+ /*
+ TODO: Add to devfs the disk
+ */
+
+ if (drive.Table.GPT.Signature == GPT_MAGIC)
+ {
+ drive.Style = GPT;
+ uint32_t Entries = 512 / drive.Table.GPT.EntrySize;
+ uint32_t Sectors = drive.Table.GPT.PartCount / Entries;
+ for (uint32_t Block = 0; Block < Sectors; Block++)
+ {
+ memset(RWBuffer, 0, this->BytesPerSector);
+ callback.Reason = ReceiveReason;
+ callback.DiskCallback.RW = {
+ .Sector = 2 + Block,
+ .SectorCount = 1,
+ .Port = ItrPort,
+ .Buffer = RWBuffer,
+ .Write = false,
+ };
+ DriverManager->IOCB(DriverUID, &callback);
+
+ for (uint32_t e = 0; e < Entries; e++)
+ {
+ GUIDPartitionTablePartition GPTPartition = reinterpret_cast(RWBuffer)[e];
+ if (GPTPartition.TypeLow || GPTPartition.TypeHigh)
+ {
+ Partition partition{};
+ memcpy(partition.Label, GPTPartition.Label, sizeof(partition.Label));
+ partition.StartLBA = GPTPartition.StartLBA;
+ partition.EndLBA = GPTPartition.EndLBA;
+ partition.Sectors = partition.EndLBA - partition.StartLBA;
+ partition.Port = ItrPort;
+ partition.Flags = Present;
+ partition.Style = GPT;
+ if (GPTPartition.Attributes & 1)
+ partition.Flags |= EFISystemPartition;
+ partition.Index = drive.Partitions.size();
+ // why there is NUL (\0) between every char?????
+ char PartName[72];
+ memcpy(PartName, GPTPartition.Label, 72);
+ for (int i = 0; i < 72; i++)
+ if (PartName[i] == '\0')
+ PartName[i] = ' ';
+ PartName[71] = '\0';
+ trace("GPT partition \"%s\" found with %lld sectors", PartName, partition.Sectors);
+ drive.Partitions.push_back(partition);
+
+ // char *PartitionName = new char[64];
+ // sprintf(PartitionName, "sd%ldp%ld", drives.size() - 1, partition.Index);
+
+ /*
+ TODO: Add to devfs the disk
+ */
+
+ // delete[] PartitionName;
+ }
+ }
+ }
+ trace("%d GPT partitions found.", drive.Partitions.size());
+ }
+ else if (drive.Table.MBR.Signature[0] == MBR_MAGIC0 && drive.Table.MBR.Signature[1] == MBR_MAGIC1)
+ {
+ drive.Style = MBR;
+ for (size_t p = 0; p < 4; p++)
+ if (drive.Table.MBR.Partitions[p].LBAFirst != 0)
+ {
+ Partition partition{};
+ partition.StartLBA = drive.Table.MBR.Partitions[p].LBAFirst;
+ partition.EndLBA = drive.Table.MBR.Partitions[p].LBAFirst + drive.Table.MBR.Partitions[p].Sectors;
+ partition.Sectors = drive.Table.MBR.Partitions[p].Sectors;
+ partition.Port = ItrPort;
+ partition.Flags = Present;
+ partition.Style = MBR;
+ partition.Index = drive.Partitions.size();
+ trace("Partition \"%#llx\" found with %lld sectors.", drive.Table.MBR.UniqueID, partition.Sectors);
+ drive.Partitions.push_back(partition);
+
+ // char *PartitionName = new char[64];
+ // sprintf(PartitionName, "sd%ldp%ld", drives.size() - 1, partition.Index);
+
+ /*
+ TODO: Add to devfs the disk
+ */
+
+ // delete[] PartitionName;
+ }
+ trace("%d MBR partitions found.", drive.Partitions.size());
+ }
+ else
+ warn("No partition table found on port %d!", ItrPort);
+
+ drives.push_back(drive);
+ }
+
+ KernelAllocator.FreePages(RWBuffer, TO_PAGES(this->BytesPerSector + 1));
+ }
+
+ Manager::Manager()
+ {
+ }
+
+ Manager::~Manager()
+ {
+ debug("Destructor called");
+ }
+}
diff --git a/Kernel/Core/Driver/Driver.cpp b/Kernel/Core/Driver/Driver.cpp
new file mode 100644
index 00000000..0f392e37
--- /dev/null
+++ b/Kernel/Core/Driver/Driver.cpp
@@ -0,0 +1,343 @@
+/*
+ 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 .
+*/
+
+#include
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include "../../kernel.h"
+#include "../../DAPI.hpp"
+#include "../../Fex.hpp"
+#include "api.hpp"
+
+NewLock(DriverInitLock);
+NewLock(DriverInterruptLock);
+
+namespace Driver
+{
+ void Driver::Panic()
+ {
+#ifdef DEBUG
+ size_t DriversNum = Drivers.size();
+ debug("%ld drivers loaded, [DUIDs: %ld]", DriversNum, DriverUIDs);
+ debug("driver size %ld", DriversNum);
+#endif
+
+ foreach (auto drv in Drivers)
+ {
+ KernelCallback callback{};
+ callback.Reason = StopReason;
+ DriverManager->IOCB(drv.DriverUID, &callback);
+
+ for (size_t j = 0; j < sizeof(drv.InterruptHook) / sizeof(drv.InterruptHook[0]); j++)
+ {
+ if (!drv.InterruptHook[j])
+ continue;
+ drv.InterruptHook[j]->Disable();
+ debug("Interrupt hook %#lx disabled", drv.InterruptHook[j]);
+ }
+ }
+ }
+
+ void Driver::UnloadAllDrivers()
+ {
+#ifdef DEBUG
+ size_t DriversNum = Drivers.size();
+ debug("%ld drivers loaded, [DUIDs: %ld]", DriversNum, DriverUIDs);
+ debug("driver size %ld", DriversNum);
+#endif
+
+ foreach (auto drv in Drivers)
+ {
+ KernelCallback callback{};
+ callback.Reason = StopReason;
+ debug("Stopping & unloading driver %ld [%#lx]", drv.DriverUID, drv.Address);
+ DriverManager->IOCB(drv.DriverUID, &callback);
+
+ for (size_t j = 0; j < sizeof(drv.InterruptHook) / sizeof(drv.InterruptHook[0]); j++)
+ {
+ if (!drv.InterruptHook[j])
+ continue;
+ debug("Interrupt hook %#lx", drv.InterruptHook[j]);
+ delete drv.InterruptHook[j], drv.InterruptHook[j] = nullptr;
+ }
+ if (drv.MemTrk)
+ delete drv.MemTrk, drv.MemTrk = nullptr;
+ }
+ Drivers.clear();
+ }
+
+ bool Driver::UnloadDriver(unsigned long DUID)
+ {
+ debug("Searching for driver %ld", DUID);
+
+ foreach (auto drv in Drivers)
+ {
+ if (drv.DriverUID == DUID)
+ {
+ KernelCallback callback{};
+ callback.Reason = StopReason;
+ debug("Stopping and unloading driver %ld [%#lx]", drv.DriverUID, drv.Address);
+ this->IOCB(drv.DriverUID, &callback);
+
+ for (size_t j = 0; j < sizeof(drv.InterruptHook) / sizeof(drv.InterruptHook[0]); j++)
+ {
+ if (!drv.InterruptHook[j])
+ continue;
+ debug("Interrupt hook %#lx", drv.InterruptHook[j]);
+ delete drv.InterruptHook[j], drv.InterruptHook[j] = nullptr;
+ }
+ delete drv.MemTrk, drv.MemTrk = nullptr;
+ Drivers.remove(drv);
+ return true;
+ }
+ }
+ return false;
+ }
+
+ int Driver::IOCB(unsigned long DUID, void *KCB)
+ {
+ foreach (auto Drv in Drivers)
+ {
+ if (Drv.DriverUID == DUID)
+ {
+ FexExtended *DrvExtHdr = (FexExtended *)((uintptr_t)Drv.Address + EXTENDED_SECTION_ADDRESS);
+ int ret = ((int (*)(void *))((uintptr_t)DrvExtHdr->Driver.Callback + (uintptr_t)Drv.Address))(KCB);
+ __sync;
+ return ret;
+ }
+ }
+ return -1;
+ }
+
+ DriverCode Driver::CallDriverEntryPoint(void *fex, void *KAPIAddress)
+ {
+ memcpy(KAPIAddress, &KernelAPITemplate, sizeof(KernelAPI));
+
+ ((KernelAPI *)KAPIAddress)->Info.Offset = (unsigned long)fex;
+ ((KernelAPI *)KAPIAddress)->Info.DriverUID = DriverUIDs++;
+ ((KernelAPI *)KAPIAddress)->Info.KernelDebug = DebuggerIsAttached;
+
+#ifdef DEBUG
+ FexExtended *fexExtended = (FexExtended *)((uintptr_t)fex + EXTENDED_SECTION_ADDRESS);
+ debug("DRIVER: %s HAS DRIVER ID %ld", fexExtended->Driver.Name, ((KernelAPI *)KAPIAddress)->Info.DriverUID);
+#endif
+
+ debug("Calling driver entry point ( %#lx %ld )", (unsigned long)fex, ((KernelAPI *)KAPIAddress)->Info.DriverUID);
+ int ret = ((int (*)(KernelAPI *))((uintptr_t)((Fex *)fex)->EntryPoint + (uintptr_t)fex))(((KernelAPI *)KAPIAddress));
+
+ if (DriverReturnCode::OK != ret)
+ return DriverCode::DRIVER_RETURNED_ERROR;
+ return DriverCode::OK;
+ }
+
+ DriverCode Driver::LoadDriver(uintptr_t DriverAddress, uintptr_t Size)
+ {
+ Fex *DrvHdr = (Fex *)DriverAddress;
+ if (DrvHdr->Magic[0] != 'F' || DrvHdr->Magic[1] != 'E' || DrvHdr->Magic[2] != 'X' || DrvHdr->Magic[3] != '\0')
+ {
+ if (Size > 0x1000)
+ {
+ Fex *ElfDrvHdr = (Fex *)(DriverAddress + 0x1000);
+ if (ElfDrvHdr->Magic[0] != 'F' || ElfDrvHdr->Magic[1] != 'E' || ElfDrvHdr->Magic[2] != 'X' || ElfDrvHdr->Magic[3] != '\0')
+ return DriverCode::INVALID_FEX_HEADER;
+ else
+ {
+ debug("Fex Magic: \"%s\"; Type: %d; OS: %d; EntryPoint: %#lx", ElfDrvHdr->Magic, ElfDrvHdr->Type, ElfDrvHdr->OS, ElfDrvHdr->EntryPoint);
+
+ if (ElfDrvHdr->Type == FexFormatType::FexFormatType_Driver)
+ {
+ FexExtended *ElfDrvExtHdr = (FexExtended *)((uintptr_t)ElfDrvHdr + EXTENDED_SECTION_ADDRESS);
+ debug("Name: \"%s\"; Type: %d; Callback: %#lx", ElfDrvExtHdr->Driver.Name, ElfDrvExtHdr->Driver.Type, ElfDrvExtHdr->Driver.Callback);
+
+ if (ElfDrvExtHdr->Driver.Bind.Type == DriverBindType::BIND_PCI)
+ return this->DriverLoadBindPCI(ElfDrvExtHdr, DriverAddress, Size, true);
+ else if (ElfDrvExtHdr->Driver.Bind.Type == DriverBindType::BIND_INTERRUPT)
+ return this->DriverLoadBindInterrupt(ElfDrvExtHdr, DriverAddress, Size, true);
+ else if (ElfDrvExtHdr->Driver.Bind.Type == DriverBindType::BIND_PROCESS)
+ return this->DriverLoadBindProcess(ElfDrvExtHdr, DriverAddress, Size, true);
+ else if (ElfDrvExtHdr->Driver.Bind.Type == DriverBindType::BIND_INPUT)
+ return this->DriverLoadBindInput(ElfDrvExtHdr, DriverAddress, Size, true);
+ else
+ error("Unknown driver bind type: %d", ElfDrvExtHdr->Driver.Bind.Type);
+ }
+ else
+ return DriverCode::NOT_DRIVER;
+ }
+ }
+ else
+ return DriverCode::INVALID_FEX_HEADER;
+ }
+ debug("Fex Magic: \"%s\"; Type: %d; OS: %d; EntryPoint: %#lx", DrvHdr->Magic, DrvHdr->Type, DrvHdr->OS, DrvHdr->EntryPoint);
+
+ if (DrvHdr->Type == FexFormatType::FexFormatType_Driver)
+ {
+ FexExtended *DrvExtHdr = (FexExtended *)((uintptr_t)DrvHdr + EXTENDED_SECTION_ADDRESS);
+ debug("Name: \"%s\"; Type: %d; Callback: %#lx", DrvExtHdr->Driver.Name, DrvExtHdr->Driver.Type, DrvExtHdr->Driver.Callback);
+
+ if (DrvExtHdr->Driver.Bind.Type == DriverBindType::BIND_PCI)
+ return this->DriverLoadBindPCI(DrvExtHdr, DriverAddress, Size);
+ else if (DrvExtHdr->Driver.Bind.Type == DriverBindType::BIND_INTERRUPT)
+ return this->DriverLoadBindInterrupt(DrvExtHdr, DriverAddress, Size);
+ else if (DrvExtHdr->Driver.Bind.Type == DriverBindType::BIND_PROCESS)
+ return this->DriverLoadBindProcess(DrvExtHdr, DriverAddress, Size);
+ else if (DrvExtHdr->Driver.Bind.Type == DriverBindType::BIND_INPUT)
+ return this->DriverLoadBindInput(DrvExtHdr, DriverAddress, Size);
+ else
+ error("Unknown driver bind type: %d", DrvExtHdr->Driver.Bind.Type);
+ }
+ else
+ return DriverCode::NOT_DRIVER;
+ return DriverCode::ERROR;
+ }
+
+ Driver::Driver()
+ {
+ SmartCriticalSection(DriverInitLock);
+
+ std::string DriverConfigFile = Config.DriverDirectory;
+ DriverConfigFile << "/config.ini";
+ fixme("Loading driver config file: %s", DriverConfigFile.c_str());
+
+ VirtualFileSystem::File DriverDirectory = vfs->Open(Config.DriverDirectory);
+ if (DriverDirectory.IsOK())
+ {
+ foreach (auto driver in DriverDirectory.node->Children)
+ if (driver->Flags == VirtualFileSystem::NodeFlags::FILE)
+ if (cwk_path_has_extension(driver->Name))
+ {
+ const char *extension;
+ size_t extension_length;
+ cwk_path_get_extension(driver->Name, &extension, &extension_length);
+ debug("Driver: %s; Extension: %s", driver->Name, extension);
+ if (strcmp(extension, ".fex") == 0 || strcmp(extension, ".elf") == 0)
+ {
+ uintptr_t ret = this->LoadDriver(driver->Address, driver->Length);
+ char RetString[128];
+ if (ret == DriverCode::OK)
+ strncpy(RetString, "\e058C19OK", 10);
+ else if (ret == DriverCode::NOT_AVAILABLE)
+ strncpy(RetString, "\eFF7900NOT AVAILABLE", 21);
+ else
+ sprintf(RetString, "\eE85230FAILED (%#lx)", ret);
+ KPrint("%s %s", driver->Name, RetString);
+ }
+ }
+ }
+ else
+ {
+ KPrint("\eE85230Failed to open driver directory: %s! (Status: %#lx)", Config.DriverDirectory, DriverDirectory.Status);
+ CPU::Stop();
+ }
+ vfs->Close(DriverDirectory);
+ }
+
+ Driver::~Driver()
+ {
+ debug("Destructor called");
+ this->UnloadAllDrivers();
+ }
+
+#if defined(a64)
+ SafeFunction void DriverInterruptHook::OnInterruptReceived(CPU::x64::TrapFrame *Frame)
+#elif defined(a32)
+ SafeFunction void DriverInterruptHook::OnInterruptReceived(CPU::x32::TrapFrame *Frame)
+#elif defined(aa64)
+ SafeFunction void DriverInterruptHook::OnInterruptReceived(CPU::aarch64::TrapFrame *Frame)
+#endif
+ {
+ SmartLock(DriverInterruptLock); /* Lock in case of multiple interrupts firing at the same time */
+ if (!this->Enabled)
+ {
+ debug("Interrupt hook is not enabled");
+ return;
+ }
+
+ if (!Handle.InterruptCallback)
+ {
+#if defined(a86)
+ uint64_t IntNum = Frame->InterruptNumber - 32;
+#elif defined(aa64)
+ uint64_t IntNum = Frame->InterruptNumber;
+#endif
+ warn("Interrupt callback for %ld is not set for driver %ld!", IntNum, Handle.DriverUID);
+ return;
+ }
+ CPURegisters regs;
+#if defined(a64)
+ regs.r15 = Frame->r15;
+ regs.r14 = Frame->r14;
+ regs.r13 = Frame->r13;
+ regs.r12 = Frame->r12;
+ regs.r11 = Frame->r11;
+ regs.r10 = Frame->r10;
+ regs.r9 = Frame->r9;
+ regs.r8 = Frame->r8;
+
+ regs.rbp = Frame->rbp;
+ regs.rdi = Frame->rdi;
+ regs.rsi = Frame->rsi;
+ regs.rdx = Frame->rdx;
+ regs.rcx = Frame->rcx;
+ regs.rbx = Frame->rbx;
+ regs.rax = Frame->rax;
+
+ regs.InterruptNumber = Frame->InterruptNumber;
+ regs.ErrorCode = Frame->ErrorCode;
+ regs.rip = Frame->rip;
+ regs.cs = Frame->cs;
+ regs.rflags = Frame->rflags.raw;
+ regs.rsp = Frame->rsp;
+ regs.ss = Frame->ss;
+#elif defined(a32)
+ regs.ebp = Frame->ebp;
+ regs.edi = Frame->edi;
+ regs.esi = Frame->esi;
+ regs.edx = Frame->edx;
+ regs.ecx = Frame->ecx;
+ regs.ebx = Frame->ebx;
+ regs.eax = Frame->eax;
+
+ regs.InterruptNumber = Frame->InterruptNumber;
+ regs.ErrorCode = Frame->ErrorCode;
+ regs.eip = Frame->eip;
+ regs.cs = Frame->cs;
+ regs.eflags = Frame->eflags.raw;
+ regs.esp = Frame->esp;
+ regs.ss = Frame->ss;
+#elif defined(aa64)
+#endif
+ ((int (*)(void *))(Handle.InterruptCallback))(®s);
+ UNUSED(Frame);
+ }
+
+ DriverInterruptHook::DriverInterruptHook(int Interrupt, DriverFile Handle) : Interrupts::Handler(Interrupt)
+ {
+ this->Handle = Handle;
+#if defined(a86)
+ trace("Interrupt %d hooked to driver %ld", Interrupt, Handle.DriverUID);
+#elif defined(aa64)
+ trace("Interrupt %d hooked to driver %ld", Interrupt, Handle.DriverUID);
+#endif
+ }
+}
diff --git a/Kernel/Core/Driver/DriverAPI.cpp b/Kernel/Core/Driver/DriverAPI.cpp
new file mode 100644
index 00000000..e9e26407
--- /dev/null
+++ b/Kernel/Core/Driver/DriverAPI.cpp
@@ -0,0 +1,203 @@
+/*
+ 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 .
+*/
+
+#include
+
+#include
+#include
+
+#include "../../kernel.h"
+#include "../../Fex.hpp"
+#include "api.hpp"
+
+// show debug messages
+// #define DEBUG_DRIVER_API 1
+
+#ifdef DEBUG_DRIVER_API
+#define drvdbg(m, ...) debug(m, ##__VA_ARGS__)
+#else
+#define drvdbg(m, ...)
+#endif
+
+NewLock(DriverDisplayPrintLock);
+
+void DriverDebugPrint(char *String, unsigned long DriverUID) { trace("[%ld] %s", DriverUID, String); }
+
+void DriverDisplayPrint(char *String)
+{
+ SmartLock(DriverDisplayPrintLock);
+ for (unsigned long i = 0; i < strlen(String); i++)
+ Display->Print(String[i], 0, true);
+}
+
+void *RequestPage(unsigned long Size)
+{
+ void *ret = KernelAllocator.RequestPages(Size + 1);
+ drvdbg("Allocated %ld pages (%#lx-%#lx)", Size, (unsigned long)ret, (unsigned long)ret + FROM_PAGES(Size));
+ return ret;
+}
+
+void FreePage(void *Page, unsigned long Size)
+{
+ drvdbg("Freeing %ld pages (%#lx-%#lx)", Size, (unsigned long)Page, (unsigned long)Page + FROM_PAGES(Size));
+ KernelAllocator.FreePages(Page, Size + 1);
+}
+
+void MapMemory(void *VirtualAddress, void *PhysicalAddress, unsigned long Flags)
+{
+ SmartLock(DriverDisplayPrintLock);
+ drvdbg("Mapping %#lx to %#lx with flags %#lx...", (unsigned long)VirtualAddress, (unsigned long)PhysicalAddress, Flags);
+ Memory::Virtual(KernelPageTable).Map(VirtualAddress, PhysicalAddress, Flags);
+}
+
+void UnmapMemory(void *VirtualAddress)
+{
+ SmartLock(DriverDisplayPrintLock);
+ drvdbg("Unmapping %#lx...", (unsigned long)VirtualAddress);
+ Memory::Virtual(KernelPageTable).Unmap(VirtualAddress);
+}
+
+void *Drivermemcpy(void *Destination, void *Source, unsigned long Size)
+{
+ SmartLock(DriverDisplayPrintLock);
+ drvdbg("Copying %ld bytes from %#lx-%#lx to %#lx-%#lx...", Size,
+ (unsigned long)Source, (unsigned long)Source + Size,
+ (unsigned long)Destination, (unsigned long)Destination + Size);
+ return memcpy(Destination, Source, Size);
+}
+
+void *Drivermemset(void *Destination, int Value, unsigned long Size)
+{
+ SmartLock(DriverDisplayPrintLock);
+ drvdbg("Setting value %#x at %#lx-%#lx (%ld bytes)...", Value,
+ (unsigned long)Destination, (unsigned long)Destination + Size,
+ Size);
+ return memset(Destination, Value, Size);
+}
+
+void DriverNetSend(unsigned int DriverID, unsigned char *Data, unsigned short Size)
+{
+ // This is useless I guess...
+ if (NIManager)
+ NIManager->DrvSend(DriverID, Data, Size);
+}
+
+void DriverNetReceive(unsigned int DriverID, unsigned char *Data, unsigned short Size)
+{
+ if (NIManager)
+ NIManager->DrvReceive(DriverID, Data, Size);
+}
+
+void DriverAHCIDiskRead(unsigned int DriverID, unsigned long Sector, unsigned char *Data, unsigned int SectorCount, unsigned char Port)
+{
+ DumpData("DriverDiskRead", Data, SectorCount * 512);
+ UNUSED(DriverID);
+ UNUSED(Sector);
+ UNUSED(Port);
+}
+
+void DriverAHCIDiskWrite(unsigned int DriverID, unsigned long Sector, unsigned char *Data, unsigned int SectorCount, unsigned char Port)
+{
+ DumpData("DriverDiskWrite", Data, SectorCount * 512);
+ UNUSED(DriverID);
+ UNUSED(Sector);
+ UNUSED(Port);
+}
+
+char *DriverPCIGetDeviceName(unsigned int VendorID, unsigned int DeviceID)
+{
+ UNUSED(VendorID);
+ UNUSED(DeviceID);
+ return (char *)"Unknown";
+}
+
+unsigned int DriverGetWidth()
+{
+ /* TODO: We won't rely only on display buffers, what about graphics drivers and changing resolutions? */
+ return Display->GetBuffer(0)->Width;
+}
+
+unsigned int DriverGetHeight()
+{
+ /* TODO: We won't rely only on display buffers, what about graphics drivers and changing resolutions? */
+ return Display->GetBuffer(0)->Height;
+}
+
+void DriverSleep(unsigned long Milliseconds)
+{
+ SmartLock(DriverDisplayPrintLock);
+ drvdbg("Sleeping for %ld milliseconds...", Milliseconds);
+ if (TaskManager)
+ TaskManager->Sleep(Milliseconds);
+ else
+ TimeManager->Sleep(Milliseconds, Time::Units::Milliseconds);
+}
+
+int Driversprintf(char *Buffer, const char *Format, ...)
+{
+ va_list args;
+ va_start(args, Format);
+ int ret = vsprintf(Buffer, Format, args);
+ va_end(args);
+ return ret;
+}
+
+KernelAPI KernelAPITemplate = {
+ .Version = {
+ .Major = 0,
+ .Minor = 0,
+ .Patch = 1},
+ .Info = {
+ .Offset = 0,
+ .DriverUID = 0,
+ .KernelDebug = false,
+ },
+ .Memory = {
+ .PageSize = PAGE_SIZE,
+ .RequestPage = RequestPage,
+ .FreePage = FreePage,
+ .Map = MapMemory,
+ .Unmap = UnmapMemory,
+ },
+ .PCI = {
+ .GetDeviceName = DriverPCIGetDeviceName,
+ },
+ .Util = {
+ .DebugPrint = DriverDebugPrint,
+ .DisplayPrint = DriverDisplayPrint,
+ .memcpy = Drivermemcpy,
+ .memset = Drivermemset,
+ .Sleep = DriverSleep,
+ .sprintf = Driversprintf,
+ },
+ .Command = {
+ .Network = {
+ .SendPacket = DriverNetSend,
+ .ReceivePacket = DriverNetReceive,
+ },
+ .Disk = {
+ .AHCI = {
+ .ReadSector = DriverAHCIDiskRead,
+ .WriteSector = DriverAHCIDiskWrite,
+ },
+ },
+ },
+ .Display = {
+ .GetWidth = DriverGetWidth,
+ .GetHeight = DriverGetHeight,
+ },
+};
diff --git a/Kernel/Core/Driver/DriverBinding/BindInput.cpp b/Kernel/Core/Driver/DriverBinding/BindInput.cpp
new file mode 100644
index 00000000..b93d02af
--- /dev/null
+++ b/Kernel/Core/Driver/DriverBinding/BindInput.cpp
@@ -0,0 +1,73 @@
+/*
+ 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 .
+*/
+
+#include "../api.hpp"
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include "../../../kernel.h"
+#include "../../../DAPI.hpp"
+#include "../../../Fex.hpp"
+
+namespace Driver
+{
+ DriverCode Driver::DriverLoadBindInput(void *DrvExtHdr, uintptr_t DriverAddress, size_t Size, bool IsElf)
+ {
+ UNUSED(DrvExtHdr);
+ UNUSED(IsElf);
+ Memory::MemMgr *mem = new Memory::MemMgr(nullptr, TaskManager->GetCurrentProcess()->memDirectory);
+ Fex *fex = (Fex *)mem->RequestPages(TO_PAGES(Size + 1));
+ memcpy(fex, (void *)DriverAddress, Size);
+ FexExtended *fexExtended = (FexExtended *)((uintptr_t)fex + EXTENDED_SECTION_ADDRESS);
+ debug("Driver allocated at %#lx-%#lx", fex, (uintptr_t)fex + Size);
+#ifdef DEBUG
+ uint8_t *result = md5File((uint8_t *)fex, Size);
+ debug("MD5: %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x",
+ result[0], result[1], result[2], result[3], result[4], result[5], result[6], result[7],
+ result[8], result[9], result[10], result[11], result[12], result[13], result[14], result[15]);
+ kfree(result);
+#endif
+ KernelAPI *KAPI = (KernelAPI *)mem->RequestPages(TO_PAGES(sizeof(KernelAPI) + 1));
+
+ if (CallDriverEntryPoint(fex, KAPI) != DriverCode::OK)
+ {
+ delete mem, mem = nullptr;
+ return DriverCode::DRIVER_RETURNED_ERROR;
+ }
+ debug("Starting driver %s (offset: %#lx)", fexExtended->Driver.Name, fex);
+
+ switch (fexExtended->Driver.Type)
+ {
+ case FexDriverType::FexDriverType_Input:
+ return BindInputInput(mem, fex);
+ default:
+ {
+ warn("Unknown driver type: %d", fexExtended->Driver.Type);
+ delete mem, mem = nullptr;
+ return DriverCode::UNKNOWN_DRIVER_TYPE;
+ }
+ }
+
+ return DriverCode::OK;
+ }
+}
diff --git a/Kernel/Core/Driver/DriverBinding/BindInterrupt.cpp b/Kernel/Core/Driver/DriverBinding/BindInterrupt.cpp
new file mode 100644
index 00000000..7bab3886
--- /dev/null
+++ b/Kernel/Core/Driver/DriverBinding/BindInterrupt.cpp
@@ -0,0 +1,85 @@
+/*
+ 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 .
+*/
+
+#include "../api.hpp"
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include "../../../kernel.h"
+#include "../../../DAPI.hpp"
+#include "../../../Fex.hpp"
+
+namespace Driver
+{
+ DriverCode Driver::DriverLoadBindInterrupt(void *DrvExtHdr, uintptr_t DriverAddress, size_t Size, bool IsElf)
+ {
+ UNUSED(DrvExtHdr);
+ UNUSED(IsElf);
+ Memory::MemMgr *mem = new Memory::MemMgr(nullptr, TaskManager->GetCurrentProcess()->memDirectory);
+ Fex *fex = (Fex *)mem->RequestPages(TO_PAGES(Size + 1));
+ memcpy(fex, (void *)DriverAddress, Size);
+ FexExtended *fexExtended = (FexExtended *)((uintptr_t)fex + EXTENDED_SECTION_ADDRESS);
+ debug("Driver allocated at %#lx-%#lx", fex, (uintptr_t)fex + Size);
+#ifdef DEBUG
+ uint8_t *result = md5File((uint8_t *)fex, Size);
+ debug("MD5: %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x",
+ result[0], result[1], result[2], result[3], result[4], result[5], result[6], result[7],
+ result[8], result[9], result[10], result[11], result[12], result[13], result[14], result[15]);
+ kfree(result);
+#endif
+ KernelAPI *KAPI = (KernelAPI *)mem->RequestPages(TO_PAGES(sizeof(KernelAPI) + 1));
+
+ if (CallDriverEntryPoint(fex, KAPI) != DriverCode::OK)
+ {
+ delete mem, mem = nullptr;
+ return DriverCode::DRIVER_RETURNED_ERROR;
+ }
+ debug("Starting driver %s (offset: %#lx)", fexExtended->Driver.Name, fex);
+
+ switch (fexExtended->Driver.Type)
+ {
+ case FexDriverType::FexDriverType_Generic:
+ return BindInterruptGeneric(mem, fex);
+ case FexDriverType::FexDriverType_Display:
+ return BindInterruptDisplay(mem, fex);
+ case FexDriverType::FexDriverType_Network:
+ return BindInterruptNetwork(mem, fex);
+ case FexDriverType::FexDriverType_Storage:
+ return BindInterruptStorage(mem, fex);
+ case FexDriverType::FexDriverType_FileSystem:
+ return BindInterruptFileSystem(mem, fex);
+ case FexDriverType::FexDriverType_Input:
+ return BindInterruptInput(mem, fex);
+ case FexDriverType::FexDriverType_Audio:
+ return BindInterruptAudio(mem, fex);
+ default:
+ {
+ warn("Unknown driver type: %d", fexExtended->Driver.Type);
+ delete mem, mem = nullptr;
+ return DriverCode::UNKNOWN_DRIVER_TYPE;
+ }
+ }
+
+ return DriverCode::OK;
+ }
+}
diff --git a/Kernel/Core/Driver/DriverBinding/BindPCI.cpp b/Kernel/Core/Driver/DriverBinding/BindPCI.cpp
new file mode 100644
index 00000000..c432885f
--- /dev/null
+++ b/Kernel/Core/Driver/DriverBinding/BindPCI.cpp
@@ -0,0 +1,201 @@
+/*
+ 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 .
+*/
+
+#include "../api.hpp"
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include "../../../kernel.h"
+#include "../../../DAPI.hpp"
+#include "../../../Fex.hpp"
+
+namespace Driver
+{
+ void Driver::MapPCIAddresses(PCI::PCIDeviceHeader *PCIDevice)
+ {
+ debug("Header Type: %d", PCIDevice->HeaderType);
+ switch (PCIDevice->HeaderType)
+ {
+ case 0: // PCI Header 0
+ {
+ uint32_t BAR[6] = {0};
+ size_t BARsSize[6] = {0};
+
+ BAR[0] = ((PCI::PCIHeader0 *)PCIDevice)->BAR0;
+ BAR[1] = ((PCI::PCIHeader0 *)PCIDevice)->BAR1;
+ BAR[2] = ((PCI::PCIHeader0 *)PCIDevice)->BAR2;
+ BAR[3] = ((PCI::PCIHeader0 *)PCIDevice)->BAR3;
+ BAR[4] = ((PCI::PCIHeader0 *)PCIDevice)->BAR4;
+ BAR[5] = ((PCI::PCIHeader0 *)PCIDevice)->BAR5;
+
+#ifdef DEBUG
+ uintptr_t BAR_Type = BAR[0] & 1;
+ uintptr_t BAR_IOBase = BAR[1] & (~3);
+ uintptr_t BAR_MemoryBase = BAR[0] & (~15);
+
+ debug("Type: %d; IOBase: %#lx; MemoryBase: %#lx", BAR_Type, BAR_IOBase, BAR_MemoryBase);
+#endif
+
+ /* BARs Size */
+ for (short i = 0; i < 6; i++)
+ {
+ if (BAR[i] == 0)
+ continue;
+
+ if ((BAR[i] & 1) == 0) // Memory Base
+ {
+ ((PCI::PCIHeader0 *)PCIDevice)->BAR0 = 0xFFFFFFFF;
+ size_t size = ((PCI::PCIHeader0 *)PCIDevice)->BAR0;
+ ((PCI::PCIHeader0 *)PCIDevice)->BAR0 = BAR[i];
+ BARsSize[i] = size & (~15);
+ BARsSize[i] = ~BARsSize[i] + 1;
+ BARsSize[i] = BARsSize[i] & 0xFFFFFFFF;
+ debug("BAR%d %#lx size: %d", i, BAR[i], BARsSize[i]);
+ }
+ else if ((BAR[i] & 1) == 1) // I/O Base
+ {
+ ((PCI::PCIHeader0 *)PCIDevice)->BAR1 = 0xFFFFFFFF;
+ size_t size = ((PCI::PCIHeader0 *)PCIDevice)->BAR1;
+ ((PCI::PCIHeader0 *)PCIDevice)->BAR1 = BAR[i];
+ BARsSize[i] = size & (~3);
+ BARsSize[i] = ~BARsSize[i] + 1;
+ BARsSize[i] = BARsSize[i] & 0xFFFF;
+ debug("BAR%d %#lx size: %d", i, BAR[i], BARsSize[i]);
+ }
+ }
+
+ /* Mapping the BARs */
+ for (short i = 0; i < 6; i++)
+ {
+ if (BAR[i] == 0)
+ continue;
+
+ if ((BAR[i] & 1) == 0) // Memory Base
+ {
+ uintptr_t BARBase = BAR[i] & (~15);
+ size_t BARSize = BARsSize[i];
+
+ debug("Mapping BAR%d %#lx-%#lx", i, BARBase, BARBase + BARSize);
+ Memory::Virtual().Map((void *)BARBase, (void *)BARBase, BARSize, Memory::PTFlag::RW | Memory::PTFlag::PWT);
+ }
+ else if ((BAR[i] & 1) == 1) // I/O Base
+ {
+ uintptr_t BARBase = BAR[i] & (~3);
+ size_t BARSize = BARsSize[i];
+
+ debug("Mapping BAR%d %#x-%#x", i, BARBase, BARBase + BARSize);
+ Memory::Virtual().Map((void *)BARBase, (void *)BARBase, BARSize, Memory::PTFlag::RW | Memory::PTFlag::PWT);
+ }
+ }
+ break;
+ }
+ case 1: // PCI Header 1 (PCI-to-PCI Bridge)
+ {
+ fixme("PCI Header 1 (PCI-to-PCI Bridge) not implemented yet");
+ break;
+ }
+ case 2: // PCI Header 2 (PCI-to-CardBus Bridge)
+ {
+ fixme("PCI Header 2 (PCI-to-CardBus Bridge) not implemented yet");
+ break;
+ }
+ default:
+ {
+ error("Unknown header type %d", PCIDevice->HeaderType);
+ return;
+ }
+ }
+ }
+
+ DriverCode Driver::DriverLoadBindPCI(void *DrvExtHdr, uintptr_t DriverAddress, size_t Size, bool IsElf)
+ {
+ UNUSED(IsElf);
+ for (unsigned long Vidx = 0; Vidx < sizeof(((FexExtended *)DrvExtHdr)->Driver.Bind.PCI.VendorID) / sizeof(((FexExtended *)DrvExtHdr)->Driver.Bind.PCI.VendorID[0]); Vidx++)
+ {
+ for (unsigned long Didx = 0; Didx < sizeof(((FexExtended *)DrvExtHdr)->Driver.Bind.PCI.DeviceID) / sizeof(((FexExtended *)DrvExtHdr)->Driver.Bind.PCI.DeviceID[0]); Didx++)
+ {
+ if (Vidx >= sizeof(((FexExtended *)DrvExtHdr)->Driver.Bind.PCI.VendorID) && Didx >= sizeof(((FexExtended *)DrvExtHdr)->Driver.Bind.PCI.DeviceID))
+ break;
+
+ if (((FexExtended *)DrvExtHdr)->Driver.Bind.PCI.VendorID[Vidx] == 0 || ((FexExtended *)DrvExtHdr)->Driver.Bind.PCI.DeviceID[Didx] == 0)
+ continue;
+
+ std::vector devices = PCIManager->FindPCIDevice(((FexExtended *)DrvExtHdr)->Driver.Bind.PCI.VendorID[Vidx], ((FexExtended *)DrvExtHdr)->Driver.Bind.PCI.DeviceID[Didx]);
+ if (devices.size() == 0)
+ continue;
+
+ foreach (auto PCIDevice in devices)
+ {
+ debug("[%ld] VendorID: %#x; DeviceID: %#x", devices.size(), PCIDevice->VendorID, PCIDevice->DeviceID);
+ Memory::MemMgr *mem = new Memory::MemMgr(nullptr, TaskManager->GetCurrentProcess()->memDirectory);
+ Fex *fex = (Fex *)mem->RequestPages(TO_PAGES(Size + 1));
+ memcpy(fex, (void *)DriverAddress, Size);
+ FexExtended *fexExtended = (FexExtended *)((uintptr_t)fex + EXTENDED_SECTION_ADDRESS);
+ debug("Driver allocated at %#lx-%#lx", fex, (uintptr_t)fex + Size);
+#ifdef DEBUG
+ uint8_t *result = md5File((uint8_t *)fex, Size);
+ debug("MD5: %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x",
+ result[0], result[1], result[2], result[3], result[4], result[5], result[6], result[7],
+ result[8], result[9], result[10], result[11], result[12], result[13], result[14], result[15]);
+ kfree(result);
+#endif
+ KernelAPI *KAPI = (KernelAPI *)mem->RequestPages(TO_PAGES(sizeof(KernelAPI) + 1));
+
+ if (CallDriverEntryPoint(fex, KAPI) != DriverCode::OK)
+ {
+ delete mem, mem = nullptr;
+ return DriverCode::DRIVER_RETURNED_ERROR;
+ }
+ debug("Starting driver %s", fexExtended->Driver.Name);
+
+ MapPCIAddresses(PCIDevice);
+
+ switch (fexExtended->Driver.Type)
+ {
+ case FexDriverType::FexDriverType_Generic:
+ return BindPCIGeneric(mem, fex, PCIDevice);
+ case FexDriverType::FexDriverType_Display:
+ return BindPCIDisplay(mem, fex, PCIDevice);
+ case FexDriverType::FexDriverType_Network:
+ return BindPCINetwork(mem, fex, PCIDevice);
+ case FexDriverType::FexDriverType_Storage:
+ return BindPCIStorage(mem, fex, PCIDevice);
+ case FexDriverType::FexDriverType_FileSystem:
+ return BindPCIFileSystem(mem, fex, PCIDevice);
+ case FexDriverType::FexDriverType_Input:
+ return BindPCIInput(mem, fex, PCIDevice);
+ case FexDriverType::FexDriverType_Audio:
+ return BindPCIAudio(mem, fex, PCIDevice);
+ default:
+ {
+ warn("Unknown driver type: %d", fexExtended->Driver.Type);
+ delete mem, mem = nullptr;
+ return DriverCode::UNKNOWN_DRIVER_TYPE;
+ }
+ }
+ }
+ }
+ }
+ return DriverCode::PCI_DEVICE_NOT_FOUND;
+ }
+}
diff --git a/Kernel/Core/Driver/DriverBinding/BindProcess.cpp b/Kernel/Core/Driver/DriverBinding/BindProcess.cpp
new file mode 100644
index 00000000..98cadbfe
--- /dev/null
+++ b/Kernel/Core/Driver/DriverBinding/BindProcess.cpp
@@ -0,0 +1,42 @@
+/*
+ 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 .
+*/
+
+#include "../api.hpp"
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include "../../../kernel.h"
+#include "../../../DAPI.hpp"
+#include "../../../Fex.hpp"
+
+namespace Driver
+{
+ DriverCode Driver::DriverLoadBindProcess(void *DrvExtHdr, uintptr_t DriverAddress, size_t Size, bool IsElf)
+ {
+ fixme("Process driver: %s", ((FexExtended *)DrvExtHdr)->Driver.Name);
+ UNUSED(Size);
+ UNUSED(DriverAddress);
+ UNUSED(IsElf);
+ return DriverCode::NOT_IMPLEMENTED;
+ }
+}
diff --git a/Kernel/Core/Driver/DriverBinding/Input/Audio.cpp b/Kernel/Core/Driver/DriverBinding/Input/Audio.cpp
new file mode 100644
index 00000000..659680a2
--- /dev/null
+++ b/Kernel/Core/Driver/DriverBinding/Input/Audio.cpp
@@ -0,0 +1,40 @@
+/*
+ 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 .
+*/
+
+#include "../../api.hpp"
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include "../../../../kernel.h"
+#include "../../../../DAPI.hpp"
+#include "../../../../Fex.hpp"
+
+namespace Driver
+{
+ DriverCode Driver::BindInputAudio(Memory::MemMgr *mem, void *fex)
+ {
+ UNUSED(mem);
+ UNUSED(fex);
+ return DriverCode::NOT_IMPLEMENTED;
+ }
+}
diff --git a/Kernel/Core/Driver/DriverBinding/Input/Display.cpp b/Kernel/Core/Driver/DriverBinding/Input/Display.cpp
new file mode 100644
index 00000000..7b4d6979
--- /dev/null
+++ b/Kernel/Core/Driver/DriverBinding/Input/Display.cpp
@@ -0,0 +1,40 @@
+/*
+ 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 .
+*/
+
+#include "../../api.hpp"
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include "../../../../kernel.h"
+#include "../../../../DAPI.hpp"
+#include "../../../../Fex.hpp"
+
+namespace Driver
+{
+ DriverCode Driver::BindInputDisplay(Memory::MemMgr *mem, void *fex)
+ {
+ UNUSED(mem);
+ UNUSED(fex);
+ return DriverCode::NOT_IMPLEMENTED;
+ }
+}
diff --git a/Kernel/Core/Driver/DriverBinding/Input/Filesystem.cpp b/Kernel/Core/Driver/DriverBinding/Input/Filesystem.cpp
new file mode 100644
index 00000000..140f038c
--- /dev/null
+++ b/Kernel/Core/Driver/DriverBinding/Input/Filesystem.cpp
@@ -0,0 +1,40 @@
+/*
+ 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 .
+*/
+
+#include "../../api.hpp"
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include "../../../../kernel.h"
+#include "../../../../DAPI.hpp"
+#include "../../../../Fex.hpp"
+
+namespace Driver
+{
+ DriverCode Driver::BindInputFileSystem(Memory::MemMgr *mem, void *fex)
+ {
+ UNUSED(mem);
+ UNUSED(fex);
+ return DriverCode::NOT_IMPLEMENTED;
+ }
+}
diff --git a/Kernel/Core/Driver/DriverBinding/Input/Generic.cpp b/Kernel/Core/Driver/DriverBinding/Input/Generic.cpp
new file mode 100644
index 00000000..5a17fea1
--- /dev/null
+++ b/Kernel/Core/Driver/DriverBinding/Input/Generic.cpp
@@ -0,0 +1,40 @@
+/*
+ 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 .
+*/
+
+#include "../../api.hpp"
+
+#include
+#include
+#include
+#include