diff --git a/.gdbinit b/.gdbinit new file mode 100644 index 0000000..21935f2 --- /dev/null +++ b/.gdbinit @@ -0,0 +1,91 @@ +# Usage: add-symbol-file-all [] +# remove-symbol-file-all [] +# +# Credit: https://stackoverflow.com/a/33087762/9352057 +# CC BY-SA 4.0 + +python +import subprocess +import re + +def relocatesections(filename, addr): + p = subprocess.Popen(["readelf", "-S", filename], stdout = subprocess.PIPE) + + sections = [] + textaddr = '0' + for line in p.stdout.readlines(): + line = line.decode("utf-8").strip() + if not line.startswith('[') or line.startswith('[Nr]'): + continue + + line = re.sub(r' +', ' ', line) + line = re.sub(r'\[ *(\d+)\]', '\g<1>', line) + fieldsvalue = line.split(' ') + fieldsname = ['number', 'name', 'type', 'addr', 'offset', 'size', 'entsize', 'flags', 'link', 'info', 'addralign'] + sec = dict(zip(fieldsname, fieldsvalue)) + + if sec['number'] == '0': + continue + + sections.append(sec) + + if sec['name'] == '.text': + textaddr = sec['addr'] + + return (textaddr, sections) + + +class AddSymbolFileAll(gdb.Command): + """The right version for add-symbol-file""" + + def __init__(self): + super(AddSymbolFileAll, self).__init__("add-symbol-file-all", gdb.COMMAND_USER) + self.dont_repeat() + + def invoke(self, arg, from_tty): + argv = gdb.string_to_argv(arg) + filename = argv[0] + + if len(argv) > 1: + offset = int(str(gdb.parse_and_eval(argv[1])), 0) + else: + offset = 0 + + (textaddr, sections) = relocatesections(filename, offset) + + cmd = "add-symbol-file %s 0x%08x" % (filename, int(textaddr, 16) + offset) + + for s in sections: + addr = int(s['addr'], 16) + if s['name'] == '.text' or addr == 0: + continue + + cmd += " -s %s 0x%08x" % (s['name'], addr + offset) + + gdb.execute(cmd) + +class RemoveSymbolFileAll(gdb.Command): + """The right version for remove-symbol-file""" + + def __init__(self): + super(RemoveSymbolFileAll, self).__init__("remove-symbol-file-all", gdb.COMMAND_USER) + self.dont_repeat() + + def invoke(self, arg, from_tty): + argv = gdb.string_to_argv(arg) + filename = argv[0] + + if len(argv) > 1: + offset = int(str(gdb.parse_and_eval(argv[1])), 0) + else: + offset = 0 + + (textaddr, _) = relocatesections(filename, offset) + + cmd = "remove-symbol-file -a 0x%08x" % (int(textaddr, 16) + offset) + gdb.execute(cmd) + + +AddSymbolFileAll() +RemoveSymbolFileAll() +end diff --git a/.gitignore b/.gitignore index 6ebb98d..ac5aa76 100644 --- a/.gitignore +++ b/.gitignore @@ -2,5 +2,5 @@ *.su *.gcno *.map -*.fsys +fennix.elf *.log diff --git a/.vscode/c_boilerplates.code-snippets b/.vscode/c_boilerplates.code-snippets index 972e73e..cd135d4 100644 --- a/.vscode/c_boilerplates.code-snippets +++ b/.vscode/c_boilerplates.code-snippets @@ -21,14 +21,14 @@ "\talong with Fennix Kernel. If not, see .", "*/", "", - "#ifndef __FENNIX_KERNEL_${2:header}_H__", - "#define __FENNIX_KERNEL_${2:header}_H__", + "#ifndef __FENNIX_KERNEL_${1:header}_H__", + "#define __FENNIX_KERNEL_${1:header}_H__", "", "#include ", "", "$0", "", - "#endif // !__FENNIX_KERNEL_${2:header}_H__", + "#endif // !__FENNIX_KERNEL_${1:header}_H__", "" ], "description": "Create kernel header." @@ -42,7 +42,7 @@ ], "description": "Create kernel documentation brief." }, - "For Iteratoion": { + "For Iteration": { "prefix": [ "foritr", ], @@ -77,5 +77,134 @@ "*/" ], "description": "Create kernel license." + }, + "Driver Code": { + "prefix": [ + "driver", + ], + "body": [ + "/*", + "\tThis file is part of Fennix Kernel.", + "", + "\tFennix Kernel is free software: you can redistribute it and/or", + "\tmodify it under the terms of the GNU General Public License as", + "\tpublished by the Free Software Foundation, either version 3 of", + "\tthe License, or (at your option) any later version.", + "", + "\tFennix Kernel is distributed in the hope that it will be useful,", + "\tbut WITHOUT ANY WARRANTY; without even the implied warranty of", + "\tMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the", + "\tGNU General Public License for more details.", + "", + "\tYou should have received a copy of the GNU General Public License", + "\talong with Fennix Kernel. If not, see .", + "*/", + "", + "#include \"${1:driver}.hpp\"", + "", + "#include ", + "", + "#include \"../../../kernel.h\"", + "", + "namespace Driver", + "{", + "\tint ${2:driver}::drvOpen(int Flags, mode_t Mode) { return 0; }", + "", + "\tint ${2:driver}::drvClose() { return 0; }", + "", + "\tsize_t ${2:driver}::drvRead(uint8_t *Buffer, size_t Size, off_t Offset) { return 0; }", + "", + "\tsize_t ${2:driver}::drvWrite(uint8_t *Buffer, size_t Size, off_t Offset) { return 0; }", + "", + "\tint ${2:driver}::drvIoctl(unsigned long Request, void *Argp) { return 0; }", + "", + "\tvoid ${2:driver}::OnInterruptReceived(CPU::TrapFrame *) {}", + "", + "\tvoid ${2:driver}::Panic() {}", + "", + "\t${2:driver}::${2:driver}(PCI::PCIDevice dev)", + "\t\t: Object(dev),", + "\t\t Interrupts::Handler(dev)", + "\t{", + "\t}", + "", + "\t${2:driver}::${2:driver}(int irq)", + "\t\t: Object(irq),", + "\t\t Interrupts::Handler(irq)", + "\t{", + "\t}", + "", + "\t${2:driver}::${2:driver}()", + "\t{", + "\t}", + "", + "\t${2:driver}::~${2:driver}()", + "\t{", + "\t\tif (GetError() != 0)", + "\t\t\treturn;", + "\t}", + "}", + "", + + ], + "description": "Kernel driver code template." + }, + "Driver Header": { + "prefix": [ + "driver", + ], + "body": [ + "/*", + "\tThis file is part of Fennix Kernel.", + "", + "\tFennix Kernel is free software: you can redistribute it and/or", + "\tmodify it under the terms of the GNU General Public License as", + "\tpublished by the Free Software Foundation, either version 3 of", + "\tthe License, or (at your option) any later version.", + "", + "\tFennix Kernel is distributed in the hope that it will be useful,", + "\tbut WITHOUT ANY WARRANTY; without even the implied warranty of", + "\tMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the", + "\tGNU General Public License for more details.", + "", + "\tYou should have received a copy of the GNU General Public License", + "\talong with Fennix Kernel. If not, see .", + "*/", + "", + "#pragma once", + "#include ", + "", + "namespace Driver", + "{", + "\tclass ${1:driver} : public Object, public Interrupts::Handler", + "\t{", + "\tprivate:", + "\t\tvoid OnInterruptReceived(CPU::TrapFrame *Frame) final;", + "\t\tvoid Panic(Driver::DriverContext *ctx) final;", + "", + "\tpublic:", + "\t\tint drvOpen(int Flags, mode_t Mode);", + "\t\tint drvClose();", + "\t\tsize_t drvRead(uint8_t *Buffer, size_t Size, off_t Offset);", + "\t\tsize_t drvWrite(uint8_t *Buffer, size_t Size, off_t Offset);", + "\t\tint drvIoctl(unsigned long Request, void *Argp);", + "", + "\t\tconst char *drvName() final { return \"${2:MyDriver}\"; }", + "\t\tconst char *drvDescription() final { return \"${3:MyDescription}\"; }", + "\t\tconst char *drvVersion() final { return \"${4:0.0.0}\"; }", + "\t\tconst char *drvAuthor() final { return \"${5:Author}\"; }", + "\t\tconst char *drvLicense() final { return \"${6:License}\"; }", + "\t\tDriverType drvType() final { return DriverType_${7:Generic}; }", + "", + "\t\t${1:driver}(PCI::PCIDevice dev);", + "\t\t${1:driver}(int irq);", + "\t\t${1:driver}();", + "\t\t~${1:driver}();", + "\t};", + "}", + "", + + ], + "description": "Kernel driver header template." } } \ No newline at end of file diff --git a/.vscode/c_cpp_properties.json b/.vscode/c_cpp_properties.json index 8fb6c52..f7afb05 100644 --- a/.vscode/c_cpp_properties.json +++ b/.vscode/c_cpp_properties.json @@ -19,6 +19,9 @@ "a86", "DEBUG=\"1\"" ], + "forcedInclude": [ + "${workspaceFolder}/.vscode/preinclude.h" + ], "compilerPath": "${workspaceFolder}/../tools/cross/bin/x86_64-fennix-gcc", "cStandard": "c17", "cppStandard": "c++20", @@ -34,7 +37,6 @@ "-mcmodel=kernel", "-fno-builtin", "-m64", - // Warnings "-Wall", "-Wextra", @@ -46,11 +48,9 @@ "-Wswitch-default", "-Wstrict-overflow=5", "-Wconversion", - // C++ flags "-fno-rtti", "-fno-exceptions", - // Linker flags "-T${workspaceFolder}/arch/amd64/linker.ld", "-Wl,-static,--no-dynamic-linker,-ztext", @@ -59,7 +59,6 @@ "-nolibc", "-zmax-page-size=0x1000", "-shared", - // Debug flags "-ggdb3", "-O0", @@ -68,7 +67,6 @@ "-fstack-usage", "-fstack-check", "-fsanitize=undefined", - // VSCode flags "-ffreestanding", "-nostdinc", @@ -112,7 +110,6 @@ "-msoft-float", "-fno-builtin", "-m32", - // Warnings "-Wall", "-Wextra", @@ -124,11 +121,9 @@ "-Wswitch-default", "-Wstrict-overflow=5", "-Wconversion", - // C++ flags "-fno-rtti", "-fno-exceptions", - // Linker flags "-T${workspaceFolder}/arch/i386/linker.ld", "-Wl,-static,--no-dynamic-linker,-ztext", @@ -137,7 +132,6 @@ "-nolibc", "-zmax-page-size=0x1000", "-shared", - // Debug flags "-ggdb3", "-O0", @@ -146,7 +140,6 @@ "-fstack-usage", "-fstack-check", "-fsanitize=undefined", - // VSCode flags "-ffreestanding", "-nostdinc", @@ -183,7 +176,6 @@ "-msoft-float", "-fPIC", "-Wstack-protector", - // Warnings "-Wall", "-Wextra", @@ -195,15 +187,12 @@ "-Wswitch-default", "-Wstrict-overflow=5", "-Wconversion", - // C++ flags "-fno-rtti", "-fno-exceptions", - // Linker flags "-T${workspaceFolder}/arch/aarch64/linker.ld", "-fPIC", - // Debug flags "-ggdb3", "-O0", @@ -212,7 +201,6 @@ "-fstack-usage", "-fstack-check", "-fsanitize=undefined", - // VSCode flags "-ffreestanding", "-nostdinc", diff --git a/.vscode/launch.json b/.vscode/launch.json index d638ce7..2b49733 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -5,7 +5,7 @@ "name": "Attach to a running VM instance", "type": "cppdbg", "request": "launch", - "program": "${workspaceFolder}/kernel.fsys", + "program": "${workspaceFolder}/fennix.elf", "cwd": "${workspaceFolder}", "args": [], "targetArchitecture": "x64", @@ -31,63 +31,20 @@ "description": "Make breakpoint pending on future shared library load." }, { - "text": "file ${workspaceFolder}/kernel.fsys", - "description": "Load binary." - } - ] - }, - { - "name": "Attach to VM w/userspace binaries", - "type": "cppdbg", - "request": "launch", - "program": "${workspaceFolder}/kernel.fsys", - "cwd": "${workspaceFolder}", - "args": [], - "targetArchitecture": "x64", - "MIMode": "gdb", - "miDebuggerPath": "${workspaceFolder}/../tools/cross/bin/x86_64-fennix-gdb", - "miDebuggerArgs": "", - "externalConsole": false, - "additionalSOLibSearchPath": "${workspaceFolder}", - "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 ${workspaceFolder}/kernel.fsys", + "text": "file ${workspaceFolder}/fennix.elf", "description": "Load binary." }, { - "text": "add-symbol-file ${workspaceFolder}/../initrd_tmp_data/bin/init", - "description": "Load /bin/init." - }, - { - "text": "add-symbol-file ${workspaceFolder}/../initrd_tmp_data/bin/utest", - "description": "Load /bin/utest." - }, - { - "text": "add-symbol-file ${workspaceFolder}/../initrd_tmp_data/usr/bin/doom", - "description": "Load /usr/bin/doom." - }, + "text": "source ${workspaceFolder}/.gdbinit" + } ], + "preLaunchTask": "launch-qemu" }, { "name": "Attach to VM w/utest", "type": "cppdbg", "request": "launch", - "program": "${workspaceFolder}/kernel.fsys", + "program": "${workspaceFolder}/fennix.elf", "cwd": "${workspaceFolder}", "args": [], "targetArchitecture": "x64", @@ -113,20 +70,25 @@ "description": "Make breakpoint pending on future shared library load." }, { - "text": "file ${workspaceFolder}/kernel.fsys", + "text": "file ${workspaceFolder}/fennix.elf", "description": "Load binary." }, { "text": "add-symbol-file ${workspaceFolder}/../initrd_tmp_data/bin/utest", - "description": "Load /bin/utest." + "description": "Load /bin/utest.", + "ignoreFailures": true }, + { + "text": "source ${workspaceFolder}/.gdbinit" + } ], + "preLaunchTask": "launch-qemu", }, { - "name": "Attach to VM w/doom", + "name": "Attach to VM w/utest_linux", "type": "cppdbg", "request": "launch", - "program": "${workspaceFolder}/kernel.fsys", + "program": "${workspaceFolder}/fennix.elf", "cwd": "${workspaceFolder}", "args": [], "targetArchitecture": "x64", @@ -152,14 +114,24 @@ "description": "Make breakpoint pending on future shared library load." }, { - "text": "file ${workspaceFolder}/kernel.fsys", + "text": "file ${workspaceFolder}/fennix.elf", "description": "Load binary." }, { - "text": "add-symbol-file ${workspaceFolder}/../initrd_tmp_data/usr/bin/doom", - "description": "Load /usr/bin/doom." + "text": "set debug-file-directory /usr/lib/debug", + "description": "Set debug-file-directory to /usr/lib/debug.", + "ignoreFailures": true }, + { + "text": "add-symbol-file ${workspaceFolder}/../initrd_tmp_data/bin/utest_linux", + "description": "Load /bin/utest_linux.", + "ignoreFailures": true + }, + { + "text": "source ${workspaceFolder}/.gdbinit" + } ], - } + "preLaunchTask": "launch-qemu", + }, ] } \ No newline at end of file diff --git a/.vscode/preinclude.h b/.vscode/preinclude.h new file mode 100644 index 0000000..b1940aa --- /dev/null +++ b/.vscode/preinclude.h @@ -0,0 +1,7 @@ +#undef __linux__ +#undef __WIN32__ +#undef __WIN64__ +#undef _WIN32 +#undef _WIN64 +#undef __APPLE__ +#undef __clang__ diff --git a/.vscode/tasks.json b/.vscode/tasks.json new file mode 100644 index 0000000..60e214e --- /dev/null +++ b/.vscode/tasks.json @@ -0,0 +1,26 @@ +{ + "version": "2.0.0", + "tasks": [ + { + "label": "launch-qemu", + "type": "shell", + "command": "make -j$(shell nproc) build && make -C ../ build_image && make -C ../ vscode_debug_only", + "isBackground": true, + "problemMatcher": [], + "group": { + "kind": "build", + "isDefault": true + }, + "presentation": { + "reveal": "always", + "panel": "shared" + }, + "options": { + "shell": { + "executable": "bash", + "args": ["-c"] + } + } + } + ] +} diff --git a/CREDITS.md b/CREDITS.md index 703a9a2..5fad282 100644 --- a/CREDITS.md +++ b/CREDITS.md @@ -8,6 +8,9 @@ License information can be found in the [LICENSES.md](LICENSES.md) file. - [OSDev Wiki](https://wiki.osdev.org/Main_Page) - [GCC x86 Built-in Functions](https://gcc.gnu.org/onlinedocs/gcc/x86-Built-in-Functions.html#x86-Built-in-Functions) - [GCC Common Function Attributes](https://gcc.gnu.org/onlinedocs/gcc/Common-Function-Attributes.html#Common-Function-Attributes) +- [LemonOS Project](https://github.com/LemonOSProject/LemonOS) +- [ToaruOS](https://github.com/klange/toaruos) +- [Various SIMD functions](https://wiki.osdev.org/User:01000101/optlib/) ## Font - [Tamsyn Font](http://www.fial.com/~scott/tamsyn-font/) @@ -56,7 +59,6 @@ License information can be found in the [LICENSES.md](LICENSES.md) file. ## Audio - [FFmpeg Audio Types](https://trac.ffmpeg.org/wiki/audio%20types) - [AC97 on OSDev](https://wiki.osdev.org/AC97) -- [LemonOS Project](https://github.com/LemonOSProject/LemonOS) - [AC97 Revision 2.3 Specification](https://inst.eecs.berkeley.edu//~cs150/Documents/ac97_r23.pdf) ## Intrinsics (x86) @@ -96,14 +98,19 @@ License information can be found in the [LICENSES.md](LICENSES.md) file. - [GCC libstdc++ Source](https://github.com/gcc-mirror/gcc/tree/master/libstdc%2B%2B-v3) - [Itanium C++ ABI](https://itanium-cxx-abi.github.io/cxx-abi/abi.html) -## Keyboard -- [Scan Codes](https://www.win.tue.nl/~aeb/linux/kbd/scancodes-11.html) -- [PS/2 Keyboard on OSDev](https://wiki.osdev.org/PS/2_Keyboard) - ## signal.h - [POSIX signal.h](https://pubs.opengroup.org/onlinepubs/009695399/basedefs/signal.h.html) - [Linux signal(7) Manual](https://man7.org/linux/man-pages/man7/signal.7.html) +## PS/2 +- [Scan Codes](https://www.win.tue.nl/~aeb/linux/kbd/scancodes-11.html) +- [PS/2 Keyboard on OSDev](https://wiki.osdev.org/PS2_Keyboard) +- [PS/2 Mouse on OSDev](https://wiki.osdev.org/PS2_Mouse) +- [Mouse Input on OSDev](https://wiki.osdev.org/Mouse_Input) +- [I/O Ports on OSDev](https://wiki.osdev.org/I/O_ports) +- [PS/2 Controller on OSDev](https://wiki.osdev.org/%228042%22_PS/2_Controller) +- [AIP on OSDev](https://wiki.osdev.org/Advanced_Integrated_Peripheral) + --- Special thanks to all contributors and the creators of the referenced projects and resources! diff --git a/Doxyfile b/Doxyfile index a514614..c90439b 100644 --- a/Doxyfile +++ b/Doxyfile @@ -44,7 +44,7 @@ PROJECT_NUMBER = 1.0.0 # for a project that appears at the top of each page and should give viewer a # quick idea about the purpose of the project. Keep the description short. -PROJECT_BRIEF = "Opeating System from scratch made in C and C++" +PROJECT_BRIEF = "Kernel Documentation" # With the PROJECT_LOGO tag one can specify a logo or an icon that is included # in the documentation. The maximum height of the logo should not exceed 55 @@ -864,7 +864,7 @@ WARN_LOGFILE = # spaces. See also FILE_PATTERNS and EXTENSION_MAPPING # Note: If this tag is empty the current directory is searched. -INPUT = Kernel tools/Doxygen_README.md +INPUT = Kernel tools/doxymds/kernel.md # This tag can be used to specify the character encoding of the source files # that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses @@ -1064,7 +1064,7 @@ FILTER_SOURCE_PATTERNS = # (index.html). This can be useful if you have a project on for instance GitHub # and want to reuse the introduction page also for the doxygen output. -USE_MDFILE_AS_MAINPAGE = tools/Doxygen_README.md +USE_MDFILE_AS_MAINPAGE = tools/doxymds/kernel.md #--------------------------------------------------------------------------- # Configuration options related to source browsing diff --git a/Fex.hpp b/Fex.hpp deleted file mode 100644 index 86c9fc6..0000000 --- a/Fex.hpp +++ /dev/null @@ -1,161 +0,0 @@ -/* - BSD 3-Clause License - - Copyright (c) 2023, EnderIce2 - All rights reserved. - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the copyright holder nor the names of its - contributors may be used to endorse or promote products derived from - this software without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ - -#ifndef __FENNIX_FILE_FEX_H__ -#define __FENNIX_FILE_FEX_H__ - -// TODO: EXPERIMENTAL - -/** - * @brief Fex file format (not finalized) - * - * @note Instead of HEAD, we can include everything in linker script like this: - * @example .header : { BYTE(0x46) BYTE(0x45) BYTE(0x58) BYTE(0x0) } for 'F' 'E' 'X' '\0' - * - */ - -/** @brief This may change */ -#define EXTENDED_SECTION_ADDRESS 0x20 - -enum FexFormatType -{ - FexFormatType_Unknown, - FexFormatType_Executable, - FexFormatType_Module - /* ... */ -}; - -enum FexOSType -{ - FexOSType_Unknown, - FexOSType_Fennix, - FexOSType_Linux - /* ... */ -}; - -enum FexModuleType -{ - FexModuleType_Unknown, - FexModuleType_Generic, - FexModuleType_Display, - FexModuleType_Network, - FexModuleType_Storage, - FexModuleType_FileSystem, - FexModuleType_Input, - FexModuleType_Audio, - FexModuleType_ACPI, - /* ... */ -}; - -enum FexDriverInputTypes -{ - FexDriverInputTypes_None = 0b00000000, - FexDriverInputTypes_Mouse = 0b00000001, - FexDriverInputTypes_Keyboard = 0b00000010, - /* ... */ -}; - -struct Fex -{ - char Magic[4]; - enum FexFormatType Type : 4; - enum FexOSType OS : 4; - int (*EntryPoint)(void *); -} __attribute__((packed)); - -union KernelCallback; -union CPURegisters; - -struct FexExtended -{ - struct - { - - } Executable; - - struct - { - char Name[64]; - enum FexModuleType Type : 4; - enum FexDriverInputTypes TypeFlags : 4; - char OverrideOnConflict; - int (*Callback)(union KernelCallback *); - int (*InterruptCallback)(union CPURegisters *); - - struct ModuleBind - { - int Type; - struct - { - unsigned char Vector[16]; - } Interrupt; - - struct - { - unsigned int ProcessId[16]; - } Process; - - struct - { - unsigned short VendorID[16]; - unsigned short DeviceID[16]; - unsigned short Class; - unsigned short SubClass; - unsigned short ProgIF; - } PCI; - - struct - { - char AttachToMouse; - char AttachToKeyboard; - } Input; - } Bind; - } Module; -} __attribute__((packed)); - -/** - * @brief Add file header - * - * @param FormatType FexFormatType - * @param OperatingSystem FexOSType - * @param Address EntryPoint to the start function - * - * @note Must include ".header : { *(.header .header.*) }" in linker script - */ -#define HEAD(FormatType, OperatingSystem, Address) \ - __attribute__((section(".header"))) struct Fex FexHeader = { \ - .Magic = {'F', 'E', 'X', '\0'}, \ - .Type = FormatType, \ - .OS = OperatingSystem, \ - .EntryPoint = Address} - -#endif // !__FENNIX_FILE_FEX_H__ diff --git a/LICENSES.md b/LICENSES.md index 88190c2..4031f84 100644 --- a/LICENSES.md +++ b/LICENSES.md @@ -39,6 +39,16 @@ Make sure to read and comply with these licenses before using or redistributing - **License:** Public Domain - **Location:** [https://raw.githubusercontent.com/blanham/liballoc/master/LICENSE](https://raw.githubusercontent.com/blanham/liballoc/master/LICENSE) -... +## rpmalloc + +- **License:** The MIT License (MIT) and Public Domain +- **Location:** [https://raw.githubusercontent.com/mjansson/rpmalloc/develop/LICENSE](https://raw.githubusercontent.com/mjansson/rpmalloc/develop/LICENSE) + +## ini.h + +- **License:** The MIT License (MIT) and Public Domain +- **Location:** [include/ini.h](include/ini.h) + +--- Please refer to the respective license files for the full text of each license. diff --git a/Makefile b/Makefile index 6a0e6bf..1d763ec 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,7 @@ # Config file include ../Makefile.conf -KERNEL_FILENAME = kernel.fsys +KERNEL_FILENAME = fennix.elf CC = ../$(COMPILER_PATH)/$(COMPILER_ARCH)gcc CPP = ../$(COMPILER_PATH)/$(COMPILER_ARCH)g++ diff --git a/TODO.md b/TODO.md index 9f714b4..495e83c 100644 --- a/TODO.md +++ b/TODO.md @@ -1,20 +1,24 @@ +# TODO + +--- + - [x] Optimize SMP. - [ ] Support IPv6. -- [ ] Endianess of the network stack (currently: [HOST](LSB)<=>[NETWORK](MSB)). Not sure if this is a standard or not. +- [ ] ~~Endianess of the network stack (currently: [HOST](LSB)<=>[NETWORK](MSB)). Not sure if this is a standard or not.~~ (???) - [ ] Support 32-bit applications (ELF, PE, etc). -- [ ] Do not map the entire memory. Map only the needed memory address at allocation time. +- [ ] ~~Do not map the entire memory. Map only the needed memory address at allocation time.~~ (we just copy the pages for userland, see `Fork()` inside [core/memory/page_table.cpp](core/memory/page_table.cpp)) - [ ] Implementation of logging (beside serial) with log rotation. - [x] Implement a better task manager. (replace struct P/TCB with classes) -- [ ] Rewrite virtual file system. (it's very bad, I don't know how I wrote it this bad) +- [ ] Rewrite virtual file system. - [ ] Colors in crash screen are not following the kernel color scheme. -- [x] Find a way to add intrinsics. +- [x] ~~Find a way to add intrinsics.~~ (not feasible, use inline assembly) - [ ] Rework PSF1 font loader. -- [x] The cleanup should be done by a thread (tasking). This is done to avoid a deadlock. +- [x] ~~The cleanup should be done by a thread (tasking). This is done to avoid a deadlock.~~ (not needed, everything is done by the scheduler) - [ ] Implement a better Display::SetBrightness() function. - [ ] Fix memcpy, memset and memcmp functions (they are not working properly with SIMD). -- [x] Fully support i386. +- [ ] Fully support i386. - [ ] Support Aarch64. -- [ ] SMP trampoline shouldn't be hardcoded at 0x2000. +- [ ] ~~SMP trampoline shouldn't be hardcoded at 0x2000.~~ (0x2000 is in the conventional memory, it's fine) - [ ] Rework the stack guard. - [x] Mutex implementation. - [ ] Update SMBIOS functions to support newer versions and actually use it. @@ -22,7 +26,23 @@ - [ ] Implement lazy allocation. (page faults) - [ ] Bootstrap should have a separate bss section + PHDR. - [ ] Reimplement the driver conflict detection. -- [ ] Elf loader shouldn't create a full copy of the elf binary. Copy only the needed sections. +- [x] Elf loader shouldn't create a full copy of the elf binary. Copy only the needed sections. - [ ] Use NX-bit. -- [ ] Fix std::string -- [ ] Rewrite PS/2 drivers. +- [ ] Fix std::string. +- [x] Rewrite PS/2 drivers. +- [ ] Improve signal handling. + +- [ ] Improve the way the kernel crashes. + - Add panic() function. + - Handle assertion failures. + +- [ ] Optimize screen printing. + - On real hardware it's very slow, a solution is dirty printing. + +- [ ] Thread ids should follow the POSIX standard. + - When a new process is created, the first thread should have the same id as the process id. + - If pid is 400, the first thread should have the id 400. The second thread should have the id 401, etc. + +- [ ] Optimize the scheduler + - Create a separate list for processes that are waiting for a resource or a signal, etc. + - Use all cores to schedule threads. diff --git a/arch/aarch64/bootstrap/boot.S b/arch/aarch64/bootstrap/boot.S index 8b88134..bcd2fc4 100644 --- a/arch/aarch64/bootstrap/boot.S +++ b/arch/aarch64/bootstrap/boot.S @@ -8,29 +8,29 @@ .extern arm64Entry memzero: - str xzr, [x0], #8 - subs x1, x1, #8 - b.gt memzero - ret + 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 + 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 + adr x0, _bss_start + adr x1, _bss_end + sub x1, x1, x0 + bl memzero + mov sp, #0x200000 + bl arm64Entry Halt: - wfe - b Halt + wfe + b Halt CPU_Loop: - b CPU_Loop + b CPU_Loop diff --git a/arch/aarch64/entry.cpp b/arch/aarch64/entry.cpp index 7b0fb75..d0ec97c 100644 --- a/arch/aarch64/entry.cpp +++ b/arch/aarch64/entry.cpp @@ -22,6 +22,6 @@ EXTERNC void arm64Entry(uint64_t dtb_ptr32, uint64_t x1, uint64_t x2, uint64_t x3) { - trace("Hello, World!"); - CPU::Halt(true); + trace("Hello, World!"); + CPU::Halt(true); } diff --git a/arch/amd64/cpu/apic.cpp b/arch/amd64/cpu/apic.cpp index c42299e..f83e1e2 100644 --- a/arch/amd64/cpu/apic.cpp +++ b/arch/amd64/cpu/apic.cpp @@ -33,7 +33,7 @@ using namespace CPU::x64; using namespace CPU::x86; /* -In constructor ‘APIC::APIC::APIC(int)’: +In constructor 'APIC::APIC::APIC(int)': warning: left shift count >= width of type | APICBaseAddress = BaseStruct.ApicBaseLo << 12u | BaseStruct.ApicBaseHi << 32u; | ~~~~~~~~~~~~~~~~~~~~~~^~~~~~ @@ -55,8 +55,8 @@ namespace APIC debug("APIC::Read(%#lx) [x2=%d]", Register, x2APICSupported ? 1 : 0); #endif - if (x2APICSupported) - assert(false); + if (unlikely(x2APICSupported)) + assert(!"x2APIC is not supported"); CPU::MemBar::Barrier(); uint32_t ret = *((volatile uint32_t *)((uintptr_t)APICBaseAddress + Register)); @@ -76,8 +76,8 @@ namespace APIC debug("APIC::Write(%#lx, %#lx) [x2=%d]", Register, Value, x2APICSupported ? 1 : 0); #endif - if (x2APICSupported) - assert(false); + if (unlikely(x2APICSupported)) + assert(!"x2APIC is not supported"); CPU::MemBar::Barrier(); *((volatile uint32_t *)(((uintptr_t)APICBaseAddress) + Register)) = Value; @@ -107,6 +107,8 @@ namespace APIC void APIC::EOI() { + Memory::SwapPT swap = + Memory::SwapPT(KernelPageTable, thisPageTable); if (this->x2APICSupported) wrmsr(MSR_X2APIC_EOI, 0); else @@ -396,20 +398,18 @@ namespace APIC APIC::~APIC() {} - void Timer::OnInterruptReceived(TrapFrame *Frame) { UNUSED(Frame); } + void Timer::OnInterruptReceived(CPU::TrapFrame *Frame) { UNUSED(Frame); } void Timer::OneShot(uint32_t Vector, uint64_t Miliseconds) { - SmartCriticalSection(APICLock); + /* FIXME: Sometimes APIC stops firing when debugging, why? */ LVTTimer timer{}; timer.VEC = uint8_t(Vector); timer.TMM = LVTTimerMode::OneShot; LVTTimerDivide Divider = DivideBy8; - if (unlikely(strcmp(CPU::Hypervisor(), x86_CPUID_VENDOR_TCG) != 0)) - Divider = DivideBy128; - + SmartCriticalSection(APICLock); if (this->lapic->x2APIC) { // wrmsr(MSR_X2APIC_DIV_CONF, Divider); <- gpf on real hardware diff --git a/arch/amd64/cpu/apic.hpp b/arch/amd64/cpu/apic.hpp index aaf2ca5..632da1c 100644 --- a/arch/amd64/cpu/apic.hpp +++ b/arch/amd64/cpu/apic.hpp @@ -373,7 +373,7 @@ namespace APIC private: APIC *lapic; uint64_t Ticks = 0; - void OnInterruptReceived(CPU::x64::TrapFrame *Frame); + void OnInterruptReceived(CPU::TrapFrame *Frame); public: uint64_t GetTicks() { return Ticks; } diff --git a/arch/amd64/cpu/gdt.cpp b/arch/amd64/cpu/gdt.cpp index 2d0ff14..b1e0abc 100644 --- a/arch/amd64/cpu/gdt.cpp +++ b/arch/amd64/cpu/gdt.cpp @@ -122,7 +122,7 @@ namespace GlobalDescriptorTable SafeFunction void Init(int Core) { - memcpy(&GDTEntries[Core], &GDTEntriesTemplate, sizeof(GlobalDescriptorTableEntries)); + GDTEntries[Core] = GDTEntriesTemplate; gdt[Core] = { .Limit = sizeof(GlobalDescriptorTableEntries) - 1, diff --git a/arch/amd64/cpu/idt.cpp b/arch/amd64/cpu/idt.cpp index 43cf63c..ba33430 100644 --- a/arch/amd64/cpu/idt.cpp +++ b/arch/amd64/cpu/idt.cpp @@ -25,7 +25,7 @@ #include "gdt.hpp" #include "../../../kernel.h" -/* conversion from ‘uint64_t’ {aka ‘long unsigned int’} to ‘unsigned char:2’ may change value */ +/* 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); @@ -532,11 +532,11 @@ namespace InterruptDescriptorTable } bool EnableISRs = true; -#ifdef DEBUG +// #ifdef DEBUG EnableISRs = !DebuggerIsAttached; if (!EnableISRs) KPrint("\eFFA500The debugger is attached, disabling all ISRs."); -#endif +// #endif /* ISR */ SetEntry(0x0, InterruptHandler_0x0, IST1, TRAP_GATE_64BIT, RING0, EnableISRs, GDT_KERNEL_CODE); @@ -553,7 +553,7 @@ namespace InterruptDescriptorTable SetEntry(0xb, InterruptHandler_0xb, IST1, TRAP_GATE_64BIT, RING0, (!DebuggerIsAttached), GDT_KERNEL_CODE); SetEntry(0xc, InterruptHandler_0xc, IST3, TRAP_GATE_64BIT, RING0, EnableISRs, GDT_KERNEL_CODE); SetEntry(0xd, InterruptHandler_0xd, IST3, TRAP_GATE_64BIT, RING0, EnableISRs, GDT_KERNEL_CODE); - SetEntry(0xe, InterruptHandler_0xe, IST3, TRAP_GATE_64BIT, RING0, EnableISRs, GDT_KERNEL_CODE); + SetEntry(0xe, InterruptHandler_0xe, IST3, TRAP_GATE_64BIT, RING0, EnableISRs /* FIXME: CoW? */, GDT_KERNEL_CODE); SetEntry(0xf, InterruptHandler_0xf, IST1, TRAP_GATE_64BIT, RING0, EnableISRs, GDT_KERNEL_CODE); SetEntry(0x10, InterruptHandler_0x10, IST1, TRAP_GATE_64BIT, RING0, EnableISRs, GDT_KERNEL_CODE); SetEntry(0x11, InterruptHandler_0x11, IST1, TRAP_GATE_64BIT, RING0, EnableISRs, GDT_KERNEL_CODE); diff --git a/arch/amd64/cpu/smp.cpp b/arch/amd64/cpu/smp.cpp index 5603ba3..6a83e88 100644 --- a/arch/amd64/cpu/smp.cpp +++ b/arch/amd64/cpu/smp.cpp @@ -57,6 +57,9 @@ SafeFunction CPUData *GetCurrentCPU() int CoreID = 0; if (CPUEnabled.load(std::memory_order_acquire) == true) { + Memory::SwapPT swap = + Memory::SwapPT(KernelPageTable, thisPageTable); + if (apic->x2APIC) CoreID = int(CPU::x64::rdmsr(CPU::x64::MSR_X2APIC_APICID)); else @@ -125,7 +128,8 @@ namespace SMP (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, + 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", diff --git a/arch/amd64/memory/vmm.cpp b/arch/amd64/memory/vmm.cpp index a7ab204..f51429d 100644 --- a/arch/amd64/memory/vmm.cpp +++ b/arch/amd64/memory/vmm.cpp @@ -29,7 +29,7 @@ namespace Memory Address &= 0xFFFFFFFFFFFFF000; PageMapIndexer Index = PageMapIndexer(Address); - PageMapLevel4 *PML4 = &this->Table->Entries[Index.PMLIndex]; + PageMapLevel4 *PML4 = &this->pTable->Entries[Index.PMLIndex]; PageDirectoryPointerTableEntryPtr *PDPTE = nullptr; PageDirectoryEntryPtr *PDE = nullptr; @@ -74,7 +74,7 @@ namespace Memory Address &= 0xFFFFFFFFFFFFF000; PageMapIndexer Index = PageMapIndexer(Address); - PageMapLevel4 *PML4 = &this->Table->Entries[Index.PMLIndex]; + PageMapLevel4 *PML4 = &this->pTable->Entries[Index.PMLIndex]; PageDirectoryPointerTableEntryPtr *PDPTE = nullptr; PageDirectoryEntryPtr *PDE = nullptr; @@ -119,7 +119,7 @@ namespace Memory Address &= 0xFFFFFFFFFFFFF000; PageMapIndexer Index = PageMapIndexer(Address); - PageMapLevel4 *PML4 = &this->Table->Entries[Index.PMLIndex]; + PageMapLevel4 *PML4 = &this->pTable->Entries[Index.PMLIndex]; PageDirectoryPointerTableEntryPtr *PDPTE = nullptr; PageDirectoryEntryPtr *PDE = nullptr; @@ -172,9 +172,11 @@ namespace Memory Address &= 0xFFFFFFFFFFFFF000; PageMapIndexer Index = PageMapIndexer(Address); - PageMapLevel4 *PML4 = &this->Table->Entries[Index.PMLIndex]; + PageMapLevel4 *PML4 = &this->pTable->Entries[Index.PMLIndex]; if (PML4->Present) return PML4; + + debug("PML4 not present for %#lx", VirtualAddress); return nullptr; } @@ -185,14 +187,19 @@ namespace Memory Address &= 0xFFFFFFFFFFFFF000; PageMapIndexer Index = PageMapIndexer(Address); - PageMapLevel4 *PML4 = &this->Table->Entries[Index.PMLIndex]; + PageMapLevel4 *PML4 = &this->pTable->Entries[Index.PMLIndex]; if (!PML4->Present) + { + debug("PML4 not present for %#lx", VirtualAddress); return nullptr; + } PageDirectoryPointerTableEntryPtr *PDPTEPtr = (PageDirectoryPointerTableEntryPtr *)((uintptr_t)PML4->Address << 12); PageDirectoryPointerTableEntry *PDPTE = &PDPTEPtr->Entries[Index.PDPTEIndex]; if (PDPTE->Present) return PDPTE; + + debug("PDPTE not present for %#lx", VirtualAddress); return nullptr; } @@ -203,19 +210,27 @@ namespace Memory Address &= 0xFFFFFFFFFFFFF000; PageMapIndexer Index = PageMapIndexer(Address); - PageMapLevel4 *PML4 = &this->Table->Entries[Index.PMLIndex]; + PageMapLevel4 *PML4 = &this->pTable->Entries[Index.PMLIndex]; if (!PML4->Present) + { + debug("PML4 not present for %#lx", VirtualAddress); return nullptr; + } PageDirectoryPointerTableEntryPtr *PDPTEPtr = (PageDirectoryPointerTableEntryPtr *)((uintptr_t)PML4->Address << 12); PageDirectoryPointerTableEntry *PDPTE = &PDPTEPtr->Entries[Index.PDPTEIndex]; if (!PDPTE->Present) + { + debug("PDPTE not present for %#lx", VirtualAddress); return nullptr; + } PageDirectoryEntryPtr *PDEPtr = (PageDirectoryEntryPtr *)(PDPTE->GetAddress() << 12); PageDirectoryEntry *PDE = &PDEPtr->Entries[Index.PDEIndex]; if (PDE->Present) return PDE; + + debug("PDE not present for %#lx", VirtualAddress); return nullptr; } @@ -226,31 +241,42 @@ namespace Memory Address &= 0xFFFFFFFFFFFFF000; PageMapIndexer Index = PageMapIndexer(Address); - PageMapLevel4 *PML4 = &this->Table->Entries[Index.PMLIndex]; + PageMapLevel4 *PML4 = &this->pTable->Entries[Index.PMLIndex]; if (!PML4->Present) + { + debug("PML4 not present for %#lx", VirtualAddress); return nullptr; + } PageDirectoryPointerTableEntryPtr *PDPTEPtr = (PageDirectoryPointerTableEntryPtr *)((uintptr_t)PML4->Address << 12); PageDirectoryPointerTableEntry *PDPTE = &PDPTEPtr->Entries[Index.PDPTEIndex]; if (!PDPTE->Present) + { + debug("PDPTE not present for %#lx", VirtualAddress); return nullptr; + } PageDirectoryEntryPtr *PDEPtr = (PageDirectoryEntryPtr *)(PDPTE->GetAddress() << 12); PageDirectoryEntry *PDE = &PDEPtr->Entries[Index.PDEIndex]; if (!PDE->Present) + { + debug("PDE not present for %#lx", VirtualAddress); return nullptr; + } PageTableEntryPtr *PTEPtr = (PageTableEntryPtr *)(PDE->GetAddress() << 12); PageTableEntry *PTE = &PTEPtr->Entries[Index.PTEIndex]; if (PTE->Present) return PTE; + + debug("PTE not present for %#lx", VirtualAddress); return nullptr; } void Virtual::Map(void *VirtualAddress, void *PhysicalAddress, uint64_t Flags, MapType Type) { SmartLock(this->MemoryLock); - if (unlikely(!this->Table)) + if (unlikely(!this->pTable)) { error("No page table"); return; @@ -262,7 +288,7 @@ namespace Memory // 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 = &this->Table->Entries[Index.PMLIndex]; + PageMapLevel4 *PML4 = &this->pTable->Entries[Index.PMLIndex]; PageDirectoryPointerTableEntryPtr *PDPTEPtr = nullptr; if (!PML4->Present) { @@ -323,7 +349,7 @@ namespace Memory PTE->Present = true; PTE->raw |= Flags; PTE->SetAddress((uintptr_t)PhysicalAddress >> 12); - CPU::x32::invlpg(VirtualAddress); + CPU::x64::invlpg(VirtualAddress); #ifdef DEBUG /* https://stackoverflow.com/a/3208376/9352057 */ @@ -346,14 +372,14 @@ namespace Memory void Virtual::Unmap(void *VirtualAddress, MapType Type) { SmartLock(this->MemoryLock); - if (!this->Table) + if (!this->pTable) { error("No page table"); return; } PageMapIndexer Index = PageMapIndexer((uintptr_t)VirtualAddress); - PageMapLevel4 *PML4 = &this->Table->Entries[Index.PMLIndex]; + PageMapLevel4 *PML4 = &this->pTable->Entries[Index.PMLIndex]; if (!PML4->Present) { warn("Page %#lx not present", PML4->GetAddress()); @@ -398,6 +424,6 @@ namespace Memory PTE.Present = false; PTEPtr->Entries[Index.PTEIndex] = PTE; - CPU::x32::invlpg(VirtualAddress); + CPU::x64::invlpg(VirtualAddress); } } diff --git a/modules/AdvancedMicroDevices/pcnet.hpp b/arch/amd64/tasking/signal_trampoline.s similarity index 63% rename from modules/AdvancedMicroDevices/pcnet.hpp rename to arch/amd64/tasking/signal_trampoline.s index c8fd420..94632a1 100644 --- a/modules/AdvancedMicroDevices/pcnet.hpp +++ b/arch/amd64/tasking/signal_trampoline.s @@ -15,24 +15,24 @@ along with Fennix Kernel. If not, see . */ -#ifndef __FENNIX_KERNEL_AMD_PCNET_H__ -#define __FENNIX_KERNEL_AMD_PCNET_H__ +.code64 -#include -#include "../../mapi.hpp" +.global _sig_native_trampoline_start +_sig_native_trampoline_start: + int $0x3 -namespace PCNET -{ - struct BARData - { - uint8_t Type; - uint16_t IOBase; - uint64_t MemoryBase; - }; +.global _sig_native_trampoline_end +_sig_native_trampoline_end: - int DriverEntry(void *); - int CallbackHandler(KernelCallback *); - int InterruptCallback(CPURegisters *); -} +.global _sig_linux_trampoline_start +_sig_linux_trampoline_start: + movq %rsp, %rbp + movq (%rbp), %rax + call %rax + mov %rbp, %rsp + /* rt_sigreturn = 15 */ + movq $15, %rax + syscall -#endif // !__FENNIX_KERNEL_AMD_PCNET_H__ +.global _sig_linux_trampoline_end +_sig_linux_trampoline_end: diff --git a/arch/i386/bootstrap/Multiboot/Paging/mb_pt.s b/arch/i386/bootstrap/Multiboot/Paging/mb_pt.s index 75fc017..2cb4c1d 100644 --- a/arch/i386/bootstrap/Multiboot/Paging/mb_pt.s +++ b/arch/i386/bootstrap/Multiboot/Paging/mb_pt.s @@ -23,29 +23,29 @@ KERNEL_PAGE_NUMBER = 768 /* KERNEL_VIRTUAL_BASE >> 22 */ .align 0x1000 .global BootPageTable BootPageTable: - .long 0x00000083 - .long 0x00400083 - .long 0x00800083 - .long 0x00C00083 - .long 0x01000083 - .long 0x01400083 - .long 0x01800083 - .long 0x01C00083 - .long 0x02000083 - .long 0x02400083 + .long 0x00000083 + .long 0x00400083 + .long 0x00800083 + .long 0x00C00083 + .long 0x01000083 + .long 0x01400083 + .long 0x01800083 + .long 0x01C00083 + .long 0x02000083 + .long 0x02400083 .rept (KERNEL_PAGE_NUMBER - 10) .long 0 .endr - .long 0x00000083 - .long 0x00400083 - .long 0x00800083 - .long 0x00C00083 - .long 0x01000083 - .long 0x01400083 - .long 0x01800083 - .long 0x01C00083 - .long 0x02000083 - .long 0x02400083 + .long 0x00000083 + .long 0x00400083 + .long 0x00800083 + .long 0x00C00083 + .long 0x01000083 + .long 0x01400083 + .long 0x01800083 + .long 0x01C00083 + .long 0x02000083 + .long 0x02400083 .rept (1024 - KERNEL_PAGE_NUMBER - 10) .long 0 .endr diff --git a/arch/i386/cpu/apic.cpp b/arch/i386/cpu/apic.cpp index dd17cfa..59a7b15 100644 --- a/arch/i386/cpu/apic.cpp +++ b/arch/i386/cpu/apic.cpp @@ -33,7 +33,7 @@ using namespace CPU::x32; using namespace CPU::x86; /* -In constructor ‘APIC::APIC::APIC(int)’: +In constructor 'APIC::APIC::APIC(int)': warning: left shift count >= width of type | APICBaseAddress = BaseStruct.ApicBaseLo << 12u | BaseStruct.ApicBaseHi << 32u; | ~~~~~~~~~~~~~~~~~~~~~~^~~~~~ @@ -358,7 +358,7 @@ namespace APIC APIC::~APIC() {} - void Timer::OnInterruptReceived(TrapFrame *Frame) { UNUSED(Frame); } + void Timer::OnInterruptReceived(CPU::TrapFrame *Frame) { UNUSED(Frame); } void Timer::OneShot(uint32_t Vector, uint64_t Miliseconds) { diff --git a/arch/i386/cpu/apic.hpp b/arch/i386/cpu/apic.hpp index 6f969d9..769858d 100644 --- a/arch/i386/cpu/apic.hpp +++ b/arch/i386/cpu/apic.hpp @@ -343,7 +343,7 @@ namespace APIC private: APIC *lapic; uint64_t Ticks = 0; - void OnInterruptReceived(CPU::x32::TrapFrame *Frame); + void OnInterruptReceived(CPU::TrapFrame *Frame); public: uint64_t GetTicks() { return Ticks; } diff --git a/arch/i386/cpu/idt.cpp b/arch/i386/cpu/idt.cpp index ad08cb3..b5d1f09 100644 --- a/arch/i386/cpu/idt.cpp +++ b/arch/i386/cpu/idt.cpp @@ -25,7 +25,7 @@ #include "gdt.hpp" #include "../../../kernel.h" -/* conversion from ‘uint64_t’ {aka ‘long unsigned int’} to ‘unsigned char:2’ may change value */ +/* 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); @@ -461,11 +461,11 @@ namespace InterruptDescriptorTable /* ISR */ bool EnableISRs = true; -#ifdef DEBUG +// #ifdef DEBUG EnableISRs = !DebuggerIsAttached; if (!EnableISRs) KPrint("\eFFA500The debugger is attached, disabling all ISRs."); -#endif +// #endif SetEntry(0x0, InterruptHandler_0x0, TRAP_GATE_32BIT, RING0, EnableISRs, GDT_KERNEL_CODE); SetEntry(0x1, InterruptHandler_0x1, TRAP_GATE_32BIT, RING0, EnableISRs, GDT_KERNEL_CODE); diff --git a/arch/i386/interrupts/8259PIC.cpp b/arch/i386/interrupts/8259PIC.cpp index ab2f540..90d441e 100644 --- a/arch/i386/interrupts/8259PIC.cpp +++ b/arch/i386/interrupts/8259PIC.cpp @@ -21,120 +21,120 @@ 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; + 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; + MasterMask = 0xFF; + SlaveMask = 0xFF; - // ICW1 - outb(MasterCommandPort, 0x11); - outb(SlaveCommandPort, 0x11); + // ICW1 + outb(MasterCommandPort, 0x11); + outb(SlaveCommandPort, 0x11); - // ICW2 - outb(MasterDataPort, MasterOffset); - outb(SlaveDataPort, SlaveOffset); + // ICW2 + outb(MasterDataPort, MasterOffset); + outb(SlaveDataPort, SlaveOffset); - // ICW3 - outb(MasterDataPort, 0x04); - outb(SlaveDataPort, 0x02); + // ICW3 + outb(MasterDataPort, 0x04); + outb(SlaveDataPort, 0x02); - // ICW4 - outb(MasterDataPort, 0x01); - outb(SlaveDataPort, 0x01); + // ICW4 + outb(MasterDataPort, 0x01); + outb(SlaveDataPort, 0x01); - // OCW1 - outb(MasterDataPort, MasterMask); - outb(SlaveDataPort, SlaveMask); - } + // OCW1 + outb(MasterDataPort, MasterMask); + outb(SlaveDataPort, SlaveMask); + } - PIC::~PIC() - { - outb(MasterDataPort, 0xFF); - outb(SlaveDataPort, 0xFF); - } + PIC::~PIC() + { + outb(MasterDataPort, 0xFF); + outb(SlaveDataPort, 0xFF); + } - void PIC::Mask(uint8_t IRQ) - { - uint16_t Port; - uint8_t Value; + void PIC::Mask(uint8_t IRQ) + { + uint16_t Port; + uint8_t Value; - if (IRQ < 8) - { - Port = MasterDataPort; - Value = (uint8_t)(MasterMask & ~(1 << IRQ)); - MasterMask = Value; - } - else - { - Port = SlaveDataPort; - Value = (uint8_t)(SlaveMask & ~(1 << (IRQ - 8))); - SlaveMask = Value; - } + if (IRQ < 8) + { + Port = MasterDataPort; + Value = (uint8_t)(MasterMask & ~(1 << IRQ)); + MasterMask = Value; + } + else + { + Port = SlaveDataPort; + Value = (uint8_t)(SlaveMask & ~(1 << (IRQ - 8))); + SlaveMask = Value; + } - outb(Port, Value); - } + outb(Port, Value); + } - void PIC::Unmask(uint8_t IRQ) - { - uint16_t Port; - uint8_t 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; - } + if (IRQ < 8) + { + Port = MasterDataPort; + Value = MasterMask | (1 << IRQ); + MasterMask = Value; + } + else + { + Port = SlaveDataPort; + Value = SlaveMask | (1 << (IRQ - 8)); + SlaveMask = Value; + } - outb(Port, Value); - } + outb(Port, Value); + } - void PIC::SendEOI(uint8_t IRQ) - { - if (IRQ >= 8) - outb(SlaveCommandPort, 0x20); + void PIC::SendEOI(uint8_t IRQ) + { + if (IRQ >= 8) + outb(SlaveCommandPort, 0x20); - outb(MasterCommandPort, 0x20); - } + outb(MasterCommandPort, 0x20); + } - PIT::PIT(uint16_t Port, uint16_t Frequency) - { - this->Port = Port; - this->Frequency = Frequency; - } + PIT::PIT(uint16_t Port, uint16_t Frequency) + { + this->Port = Port; + this->Frequency = Frequency; + } - PIT::~PIT() - { - } + PIT::~PIT() + { + } - void PIT::PrepareSleep(uint32_t Milliseconds) - { - uint16_t Divisor = (uint16_t)(1193182 / Frequency); - uint8_t Low = (uint8_t)(Divisor & 0xFF); - uint8_t High = (uint8_t)((Divisor >> 8) & 0xFF); + void PIT::PrepareSleep(uint32_t Milliseconds) + { + uint16_t Divisor = (uint16_t)(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); - } + 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); - } + void PIT::PerformSleep() + { + uint8_t Value = inb(Port + 0); + while (Value != 0) + Value = inb(Port + 0); + } } diff --git a/arch/i386/interrupts/pic.hpp b/arch/i386/interrupts/pic.hpp index f0d6013..512eacb 100644 --- a/arch/i386/interrupts/pic.hpp +++ b/arch/i386/interrupts/pic.hpp @@ -22,38 +22,38 @@ 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; + 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); - }; + 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; + 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(); - }; + public: + PIT(uint16_t Port, uint16_t Frequency); + ~PIT(); + void PrepareSleep(uint32_t Milliseconds); + void PerformSleep(); + }; } #endif // !__FENNIX_KERNEL_8259PIC_H__ diff --git a/arch/i386/linker.ld b/arch/i386/linker.ld index 7e8cb44..b4ed457 100644 --- a/arch/i386/linker.ld +++ b/arch/i386/linker.ld @@ -26,79 +26,79 @@ PF_X = 0x1; PHDRS { - bootstrap PT_LOAD FLAGS( PF_R | PF_W /*| PF_X*/ ); - text PT_LOAD FLAGS( PF_R | PF_X ); - data PT_LOAD FLAGS( PF_R | PF_W ); - rodata PT_LOAD FLAGS( PF_R ); - bss PT_LOAD FLAGS( PF_R | PF_W ); + bootstrap PT_LOAD FLAGS( PF_R | PF_W /*| PF_X*/ ); + text PT_LOAD FLAGS( PF_R | PF_X ); + data PT_LOAD FLAGS( PF_R | PF_W ); + rodata PT_LOAD FLAGS( PF_R ); + bss PT_LOAD FLAGS( PF_R | PF_W ); } KERNEL_VMA = 0xC0000000; SECTIONS { - . = 0x100000; - _bootstrap_start = .; - .bootstrap ALIGN(CONSTANT(MAXPAGESIZE)) : - { - *(.multiboot) - *(.multiboot2) - *(.bootstrap .bootstrap.*) - } :bootstrap - _bootstrap_end = ALIGN(CONSTANT(MAXPAGESIZE)); + . = 0x100000; + _bootstrap_start = .; + .bootstrap ALIGN(CONSTANT(MAXPAGESIZE)) : + { + *(.multiboot) + *(.multiboot2) + *(.bootstrap .bootstrap.*) + } :bootstrap + _bootstrap_end = ALIGN(CONSTANT(MAXPAGESIZE)); - . += KERNEL_VMA; + . += KERNEL_VMA; - _kernel_start = ALIGN(CONSTANT(MAXPAGESIZE)); - _kernel_text_start = ALIGN(CONSTANT(MAXPAGESIZE)); - .text ALIGN(CONSTANT(MAXPAGESIZE)) : AT(ADDR(.text) - KERNEL_VMA) - { - *(.text .text.*) - } :text - _kernel_text_end = ALIGN(CONSTANT(MAXPAGESIZE)); + _kernel_start = ALIGN(CONSTANT(MAXPAGESIZE)); + _kernel_text_start = ALIGN(CONSTANT(MAXPAGESIZE)); + .text ALIGN(CONSTANT(MAXPAGESIZE)) : AT(ADDR(.text) - KERNEL_VMA) + { + *(.text .text.*) + } :text + _kernel_text_end = ALIGN(CONSTANT(MAXPAGESIZE)); - _kernel_data_start = ALIGN(CONSTANT(MAXPAGESIZE)); - .data ALIGN(CONSTANT(MAXPAGESIZE)) : AT(ADDR(.data) - KERNEL_VMA) - { - *(.data .data.*) - } :data - _kernel_data_end = ALIGN(CONSTANT(MAXPAGESIZE)); + _kernel_data_start = ALIGN(CONSTANT(MAXPAGESIZE)); + .data ALIGN(CONSTANT(MAXPAGESIZE)) : AT(ADDR(.data) - KERNEL_VMA) + { + *(.data .data.*) + } :data + _kernel_data_end = ALIGN(CONSTANT(MAXPAGESIZE)); - _kernel_rodata_start = ALIGN(CONSTANT(MAXPAGESIZE)); - .rodata ALIGN(CONSTANT(MAXPAGESIZE)) : AT(ADDR(.rodata) - KERNEL_VMA) - { - *(.rodata .rodata.*) - } :rodata + _kernel_rodata_start = ALIGN(CONSTANT(MAXPAGESIZE)); + .rodata ALIGN(CONSTANT(MAXPAGESIZE)) : AT(ADDR(.rodata) - KERNEL_VMA) + { + *(.rodata .rodata.*) + } :rodata - .init_array ALIGN(CONSTANT(MAXPAGESIZE)) : 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 = .); - } :rodata + .init_array ALIGN(CONSTANT(MAXPAGESIZE)) : 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 = .); + } :rodata - .fini_array ALIGN(CONSTANT(MAXPAGESIZE)) : 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 = .); - } :rodata - _kernel_rodata_end = ALIGN(CONSTANT(MAXPAGESIZE)); + .fini_array ALIGN(CONSTANT(MAXPAGESIZE)) : 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 = .); + } :rodata + _kernel_rodata_end = ALIGN(CONSTANT(MAXPAGESIZE)); - _kernel_bss_start = ALIGN(CONSTANT(MAXPAGESIZE)); - .bss ALIGN(CONSTANT(MAXPAGESIZE)) : AT(ADDR(.bss) - KERNEL_VMA) - { - *(COMMON) - *(.bss .bss.*) - } :bss - _kernel_bss_end = ALIGN(CONSTANT(MAXPAGESIZE)); - _kernel_end = ALIGN(CONSTANT(MAXPAGESIZE)); + _kernel_bss_start = ALIGN(CONSTANT(MAXPAGESIZE)); + .bss ALIGN(CONSTANT(MAXPAGESIZE)) : AT(ADDR(.bss) - KERNEL_VMA) + { + *(COMMON) + *(.bss .bss.*) + } :bss + _kernel_bss_end = ALIGN(CONSTANT(MAXPAGESIZE)); + _kernel_end = ALIGN(CONSTANT(MAXPAGESIZE)); - /DISCARD/ : - { - *(.comment*) - *(.note*) - } + /DISCARD/ : + { + *(.comment*) + *(.note*) + } } diff --git a/arch/i386/memory/vmm.cpp b/arch/i386/memory/vmm.cpp index a286a37..ec7a5bd 100644 --- a/arch/i386/memory/vmm.cpp +++ b/arch/i386/memory/vmm.cpp @@ -22,205 +22,205 @@ namespace Memory { - bool Virtual::Check(void *VirtualAddress, PTFlag Flag, MapType Type) - { - // 0x1000 aligned - uintptr_t Address = (uintptr_t)VirtualAddress; - Address &= 0xFFFFF000; + bool Virtual::Check(void *VirtualAddress, PTFlag Flag, MapType Type) + { + // 0x1000 aligned + uintptr_t Address = (uintptr_t)VirtualAddress; + Address &= 0xFFFFF000; - PageMapIndexer Index = PageMapIndexer(Address); - PageDirectoryEntry *PDE = &this->Table->Entries[Index.PDEIndex]; - PageTableEntryPtr *PTE = nullptr; + PageMapIndexer Index = PageMapIndexer(Address); + PageDirectoryEntry *PDE = &this->Table->Entries[Index.PDEIndex]; + PageTableEntryPtr *PTE = nullptr; - if ((PDE->raw & Flag) > 0) - { - if (Type == MapType::FourMiB && PDE->PageSize) - return true; + if ((PDE->raw & Flag) > 0) + { + if (Type == MapType::FourMiB && PDE->PageSize) + return true; - PTE = (PageTableEntryPtr *)((uintptr_t)PDE->GetAddress() << 12); - if (PTE) - { - if ((PTE->Entries[Index.PTEIndex].Present)) - return true; - } - } - return false; - } + PTE = (PageTableEntryPtr *)((uintptr_t)PDE->GetAddress() << 12); + if (PTE) + { + if ((PTE->Entries[Index.PTEIndex].Present)) + return true; + } + } + return false; + } - void *Virtual::GetPhysical(void *VirtualAddress) - { - // 0x1000 aligned - uintptr_t Address = (uintptr_t)VirtualAddress; - Address &= 0xFFFFF000; + void *Virtual::GetPhysical(void *VirtualAddress) + { + // 0x1000 aligned + uintptr_t Address = (uintptr_t)VirtualAddress; + Address &= 0xFFFFF000; - PageMapIndexer Index = PageMapIndexer(Address); - PageDirectoryEntry *PDE = &this->Table->Entries[Index.PDEIndex]; - PageTableEntryPtr *PTE = nullptr; + PageMapIndexer Index = PageMapIndexer(Address); + PageDirectoryEntry *PDE = &this->Table->Entries[Index.PDEIndex]; + PageTableEntryPtr *PTE = nullptr; - if (PDE->Present) - { - if (PDE->PageSize) - return (void *)((uintptr_t)PDE->GetAddress() << 12); + if (PDE->Present) + { + if (PDE->PageSize) + return (void *)((uintptr_t)PDE->GetAddress() << 12); - PTE = (PageTableEntryPtr *)((uintptr_t)PDE->GetAddress() << 12); - if (PTE) - { - if (PTE->Entries[Index.PTEIndex].Present) - return (void *)((uintptr_t)PTE->Entries[Index.PTEIndex].GetAddress() << 12); - } - } - return nullptr; - } + PTE = (PageTableEntryPtr *)((uintptr_t)PDE->GetAddress() << 12); + if (PTE) + { + if (PTE->Entries[Index.PTEIndex].Present) + return (void *)((uintptr_t)PTE->Entries[Index.PTEIndex].GetAddress() << 12); + } + } + return nullptr; + } - Virtual::MapType Virtual::GetMapType(void *VirtualAddress) - { - // 0x1000 aligned - uintptr_t Address = (uintptr_t)VirtualAddress; - Address &= 0xFFFFF000; + Virtual::MapType Virtual::GetMapType(void *VirtualAddress) + { + // 0x1000 aligned + uintptr_t Address = (uintptr_t)VirtualAddress; + Address &= 0xFFFFF000; - PageMapIndexer Index = PageMapIndexer(Address); + PageMapIndexer Index = PageMapIndexer(Address); - PageDirectoryEntry *PDE = &this->Table->Entries[Index.PDEIndex]; - PageTableEntryPtr *PTE = nullptr; + PageDirectoryEntry *PDE = &this->Table->Entries[Index.PDEIndex]; + PageTableEntryPtr *PTE = nullptr; - if (PDE->Present) - { - if (PDE->PageSize) - return MapType::FourMiB; + if (PDE->Present) + { + if (PDE->PageSize) + return MapType::FourMiB; - PTE = (PageTableEntryPtr *)((uintptr_t)PDE->GetAddress() << 12); - if (PTE) - { - if (PTE->Entries[Index.PTEIndex].Present) - return MapType::FourKiB; - } - } - return MapType::NoMapType; - } + PTE = (PageTableEntryPtr *)((uintptr_t)PDE->GetAddress() << 12); + if (PTE) + { + if (PTE->Entries[Index.PTEIndex].Present) + return MapType::FourKiB; + } + } + return MapType::NoMapType; + } - PageDirectoryEntry *Virtual::GetPDE(void *VirtualAddress, MapType Type) - { - uintptr_t Address = (uintptr_t)VirtualAddress; - Address &= 0xFFFFF000; + PageDirectoryEntry *Virtual::GetPDE(void *VirtualAddress, MapType Type) + { + uintptr_t Address = (uintptr_t)VirtualAddress; + Address &= 0xFFFFF000; - PageMapIndexer Index = PageMapIndexer(Address); - PageDirectoryEntry *PDE = &this->Table->Entries[Index.PDEIndex]; - if (PDE->Present) - return PDE; - return nullptr; - } + PageMapIndexer Index = PageMapIndexer(Address); + PageDirectoryEntry *PDE = &this->Table->Entries[Index.PDEIndex]; + if (PDE->Present) + return PDE; + return nullptr; + } - PageTableEntry *Virtual::GetPTE(void *VirtualAddress, MapType Type) - { - uintptr_t Address = (uintptr_t)VirtualAddress; - Address &= 0xFFFFF000; + PageTableEntry *Virtual::GetPTE(void *VirtualAddress, MapType Type) + { + uintptr_t Address = (uintptr_t)VirtualAddress; + Address &= 0xFFFFF000; - PageMapIndexer Index = PageMapIndexer(Address); - PageDirectoryEntry *PDE = &this->Table->Entries[Index.PDEIndex]; - if (!PDE->Present) - return nullptr; + PageMapIndexer Index = PageMapIndexer(Address); + PageDirectoryEntry *PDE = &this->Table->Entries[Index.PDEIndex]; + if (!PDE->Present) + return nullptr; - PageTableEntryPtr *PTEPtr = (PageTableEntryPtr *)(PDE->GetAddress() << 12); - PageTableEntry *PTE = &PTEPtr->Entries[Index.PTEIndex]; - if (PTE->Present) - return PTE; - return nullptr; - } + PageTableEntryPtr *PTEPtr = (PageTableEntryPtr *)(PDE->GetAddress() << 12); + PageTableEntry *PTE = &PTEPtr->Entries[Index.PTEIndex]; + if (PTE->Present) + return PTE; + return nullptr; + } - void Virtual::Map(void *VirtualAddress, void *PhysicalAddress, uint64_t Flags, MapType Type) - { - SmartLock(this->MemoryLock); - if (unlikely(!this->Table)) - { - error("No page table"); - return; - } + void Virtual::Map(void *VirtualAddress, void *PhysicalAddress, uint64_t Flags, MapType Type) + { + SmartLock(this->MemoryLock); + if (unlikely(!this->Table)) + { + error("No page table"); + return; + } - Flags |= PTFlag::P; + Flags |= PTFlag::P; - 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; + 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; - PageDirectoryEntry *PDE = &this->Table->Entries[Index.PDEIndex]; - if (Type == MapType::FourMiB) - { - PDE->raw |= (uintptr_t)Flags; - PDE->PageSize = true; - PDE->SetAddress((uintptr_t)PhysicalAddress >> 12); - debug("Mapped 4MB page at %p to %p", VirtualAddress, PhysicalAddress); - return; - } + PageDirectoryEntry *PDE = &this->Table->Entries[Index.PDEIndex]; + if (Type == MapType::FourMiB) + { + PDE->raw |= (uintptr_t)Flags; + PDE->PageSize = true; + PDE->SetAddress((uintptr_t)PhysicalAddress >> 12); + debug("Mapped 4MB page at %p to %p", VirtualAddress, PhysicalAddress); + return; + } - PageTableEntryPtr *PTEPtr = nullptr; - if (!PDE->Present) - { - PTEPtr = (PageTableEntryPtr *)KernelAllocator.RequestPages(TO_PAGES(sizeof(PageTableEntryPtr) + 1)); - memset(PTEPtr, 0, sizeof(PageTableEntryPtr)); - PDE->Present = true; - PDE->SetAddress((uintptr_t)PTEPtr >> 12); - } - else - PTEPtr = (PageTableEntryPtr *)(PDE->GetAddress() << 12); - PDE->raw |= (uintptr_t)DirectoryFlags; + PageTableEntryPtr *PTEPtr = nullptr; + if (!PDE->Present) + { + PTEPtr = (PageTableEntryPtr *)KernelAllocator.RequestPages(TO_PAGES(sizeof(PageTableEntryPtr) + 1)); + memset(PTEPtr, 0, sizeof(PageTableEntryPtr)); + PDE->Present = true; + PDE->SetAddress((uintptr_t)PTEPtr >> 12); + } + else + PTEPtr = (PageTableEntryPtr *)(PDE->GetAddress() << 12); + PDE->raw |= (uintptr_t)DirectoryFlags; - PageTableEntry *PTE = &PTEPtr->Entries[Index.PTEIndex]; - PTE->Present = true; - PTE->raw |= (uintptr_t)Flags; - PTE->SetAddress((uintptr_t)PhysicalAddress >> 12); - CPU::x32::invlpg(VirtualAddress); + PageTableEntry *PTE = &PTEPtr->Entries[Index.PTEIndex]; + PTE->Present = true; + PTE->raw |= (uintptr_t)Flags; + PTE->SetAddress((uintptr_t)PhysicalAddress >> 12); + CPU::x32::invlpg(VirtualAddress); #ifdef DEBUG /* https://stackoverflow.com/a/3208376/9352057 */ #define BYTE_TO_BINARY_PATTERN "%c%c%c%c%c%c%c%c" #define BYTE_TO_BINARY(byte) \ - (byte & 0x80 ? '1' : '0'), \ - (byte & 0x40 ? '1' : '0'), \ - (byte & 0x20 ? '1' : '0'), \ - (byte & 0x10 ? '1' : '0'), \ - (byte & 0x08 ? '1' : '0'), \ - (byte & 0x04 ? '1' : '0'), \ - (byte & 0x02 ? '1' : '0'), \ - (byte & 0x01 ? '1' : '0') + (byte & 0x80 ? '1' : '0'), \ + (byte & 0x40 ? '1' : '0'), \ + (byte & 0x20 ? '1' : '0'), \ + (byte & 0x10 ? '1' : '0'), \ + (byte & 0x08 ? '1' : '0'), \ + (byte & 0x04 ? '1' : '0'), \ + (byte & 0x02 ? '1' : '0'), \ + (byte & 0x01 ? '1' : '0') - if (!this->Check(VirtualAddress, (PTFlag)Flags, Type)) // quick workaround just to see where it fails - warn("Failed to map v:%#lx p:%#lx with flags: " BYTE_TO_BINARY_PATTERN, VirtualAddress, PhysicalAddress, BYTE_TO_BINARY(Flags)); + if (!this->Check(VirtualAddress, (PTFlag)Flags, Type)) // quick workaround just to see where it fails + warn("Failed to map v:%#lx p:%#lx with flags: " BYTE_TO_BINARY_PATTERN, VirtualAddress, PhysicalAddress, BYTE_TO_BINARY(Flags)); #endif - } + } - void Virtual::Unmap(void *VirtualAddress, MapType Type) - { - SmartLock(this->MemoryLock); - if (!this->Table) - { - error("No page table"); - return; - } + void Virtual::Unmap(void *VirtualAddress, MapType Type) + { + SmartLock(this->MemoryLock); + if (!this->Table) + { + error("No page table"); + return; + } - PageMapIndexer Index = PageMapIndexer((uintptr_t)VirtualAddress); - PageDirectoryEntry *PDE = &this->Table->Entries[Index.PDEIndex]; - if (!PDE->Present) - { - warn("Page %#lx not present", PDE->GetAddress()); - return; - } + PageMapIndexer Index = PageMapIndexer((uintptr_t)VirtualAddress); + PageDirectoryEntry *PDE = &this->Table->Entries[Index.PDEIndex]; + if (!PDE->Present) + { + warn("Page %#lx not present", PDE->GetAddress()); + return; + } - if (Type == MapType::FourMiB && PDE->PageSize) - { - PDE->Present = false; - return; - } + if (Type == MapType::FourMiB && PDE->PageSize) + { + PDE->Present = false; + return; + } - PageTableEntryPtr *PTEPtr = (PageTableEntryPtr *)((uintptr_t)PDE->Address << 12); - PageTableEntry PTE = PTEPtr->Entries[Index.PTEIndex]; - if (!PTE.Present) - { - warn("Page %#lx not present", PTE.GetAddress()); - return; - } + PageTableEntryPtr *PTEPtr = (PageTableEntryPtr *)((uintptr_t)PDE->Address << 12); + PageTableEntry PTE = PTEPtr->Entries[Index.PTEIndex]; + if (!PTE.Present) + { + warn("Page %#lx not present", PTE.GetAddress()); + return; + } - PTE.Present = false; - PTEPtr->Entries[Index.PTEIndex] = PTE; - CPU::x32::invlpg(VirtualAddress); - } + PTE.Present = false; + PTEPtr->Entries[Index.PTEIndex] = PTE; + CPU::x32::invlpg(VirtualAddress); + } } diff --git a/boot_logo.cpp b/boot_logo.cpp deleted file mode 100644 index 0b04ddb..0000000 --- a/boot_logo.cpp +++ /dev/null @@ -1,181 +0,0 @@ -/* - This file is part of Fennix Kernel. - - Fennix Kernel is free software: you can redistribute it and/or - modify it under the terms of the GNU General Public License as - published by the Free Software Foundation, either version 3 of - the License, or (at your option) any later version. - - Fennix Kernel is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Fennix Kernel. If not, see . -*/ - -#include "kernel.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#define STB_IMAGE_IMPLEMENTATION -#define STBI_NO_STDIO -#define STBI_NO_LINEAR -#define STBI_NO_THREAD_LOCALS -#define STBI_NO_HDR -#define STBI_ONLY_TGA -#include - -#include "mapi.hpp" -#include "Fex.hpp" - -using vfs::RefNode; - -/* Files: 0.tga 1.tga ... 26.tga */ -uint8_t *Frames[27]; -uint32_t FrameSizes[27]; -size_t FrameCount = 1; - -void BootLogoAnimationThread() -{ - char BootAnimPath[16]; - while (FrameCount < 27) - { - sprintf(BootAnimPath, "/etc/boot/%ld.tga", FrameCount); - RefNode *frame = fs->Open(BootAnimPath); - if (!frame) - { - debug("Failed to load boot animation frame %s", BootAnimPath); - break; - } - - FrameSizes[FrameCount] = s_cst(uint32_t, frame->Size); - Frames[FrameCount] = new uint8_t[frame->Size]; - frame->read(Frames[FrameCount], frame->Size); - delete frame; - FrameCount++; - } - - uint32_t DispX = Display->GetBuffer(1)->Width; - uint32_t DispY = Display->GetBuffer(1)->Height; - - for (size_t i = 1; i < FrameCount; i++) - { - int x, y, channels; - - if (!stbi_info_from_memory((uint8_t *)Frames[i], FrameSizes[i], - &x, &y, &channels)) - continue; - - uint8_t *img = stbi_load_from_memory((uint8_t *)Frames[i], - FrameSizes[i], &x, &y, - &channels, STBI_rgb_alpha); - - if (img == NULL) - continue; - - int offsetX = DispX / 2 - x / 2; - int offsetY = DispY / 2 - y / 2; - - for (int i = 0; i < x * y; i++) - { - uint32_t pixel = ((uint32_t *)img)[i]; - int r = (pixel >> 16) & 0xFF; - int g = (pixel >> 8) & 0xFF; - int b = (pixel >> 0) & 0xFF; - int a = (pixel >> 24) & 0xFF; - - if (a != 0xFF) - { - r = (r * a) / 0xFF; - g = (g * a) / 0xFF; - b = (b * a) / 0xFF; - } - - Display->SetPixel((i % x) + offsetX, (i / x) + offsetY, - (r << 16) | (g << 8) | (b << 0), 1); - } - - free(img); - Display->SetBuffer(1); - TaskManager->Sleep(50); - } - - int brightness = 100; - while (brightness >= 0) - { - brightness -= 10; - Display->SetBrightness(brightness, 1); - Display->SetBuffer(1); - TaskManager->Sleep(5); - } -} - -void ExitLogoAnimationThread() -{ - Display->SetBrightness(100, 1); - Display->SetBuffer(1); - - /* Files: 26.tga 25.tga ... 1.tga */ - uint32_t DispX = Display->GetBuffer(1)->Width; - uint32_t DispY = Display->GetBuffer(1)->Height; - - for (size_t i = FrameCount - 1; i > 0; i--) - { - int x, y, channels; - - if (!stbi_info_from_memory((uint8_t *)Frames[i], FrameSizes[i], - &x, &y, &channels)) - continue; - - uint8_t *img = stbi_load_from_memory((uint8_t *)Frames[i], - FrameSizes[i], &x, &y, - &channels, STBI_rgb_alpha); - - if (img == NULL) - continue; - - int offsetX = DispX / 2 - x / 2; - int offsetY = DispY / 2 - y / 2; - - for (int i = 0; i < x * y; i++) - { - uint32_t pixel = ((uint32_t *)img)[i]; - int r = (pixel >> 16) & 0xFF; - int g = (pixel >> 8) & 0xFF; - int b = (pixel >> 0) & 0xFF; - int a = (pixel >> 24) & 0xFF; - - if (a != 0xFF) - { - r = (r * a) / 0xFF; - g = (g * a) / 0xFF; - b = (b * a) / 0xFF; - } - - Display->SetPixel((i % x) + offsetX, (i / x) + offsetY, - (r << 16) | (g << 8) | (b << 0), 1); - } - - free(img); - Display->SetBuffer(1); - TaskManager->Sleep(50); - } - - int brightness = 100; - while (brightness >= 0) - { - brightness -= 10; - Display->SetBrightness(brightness, 1); - Display->SetBuffer(1); - TaskManager->Sleep(5); - } -} diff --git a/core/acpi.cpp b/core/acpi.cpp index c6c7021..adda722 100644 --- a/core/acpi.cpp +++ b/core/acpi.cpp @@ -40,13 +40,23 @@ namespace ACPI #pragma GCC diagnostic pop - for (short i = 0; i < 4; i++) + size_t signLength = strlen(Signature); + for (size_t i = 0; i < signLength; i++) { if (SDTHdr->Signature[i] != Signature[i]) break; if (i == 3) { - trace("%s found at address %p", Signature, (uintptr_t)SDTHdr); +#ifdef DEBUG + KPrint("ACPI: %s [%s:%s] found at address %#lx", + Signature, + SDTHdr->OEMID, + SDTHdr->OEMTableID, + (uintptr_t)SDTHdr); +#endif + trace("%s found at address %#lx", Signature, (uintptr_t)SDTHdr); + + Tables[Signature] = SDTHdr; return SDTHdr; } } @@ -70,6 +80,9 @@ namespace ACPI WAET = (WAETHeader *)FindTable(Header, (char *)"WAET"); MADT = (MADTHeader *)FindTable(Header, (char *)"APIC"); HEST = (HESTHeader *)FindTable(Header, (char *)"HEST"); + SSDT = (SSDTHeader *)FindTable(Header, (char *)"SSDT"); + DBGP = (DBGPHeader *)FindTable(Header, (char *)"DBGP"); + DBG2 = (DBG2Header *)FindTable(Header, (char *)"DBG2"); FindTable(Header, (char *)"BERT"); FindTable(Header, (char *)"CPEP"); FindTable(Header, (char *)"DSDT"); @@ -86,7 +99,6 @@ namespace ACPI 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"); @@ -102,8 +114,8 @@ namespace ACPI FindTable(Header, (char *)"ASF!"); FindTable(Header, (char *)"BOOT"); FindTable(Header, (char *)"CSRT"); - FindTable(Header, (char *)"DBG2"); - FindTable(Header, (char *)"DBGP"); + FindTable(Header, (char *)"BDAT"); + FindTable(Header, (char *)"CDAT"); FindTable(Header, (char *)"DMAR"); FindTable(Header, (char *)"IBFT"); FindTable(Header, (char *)"IORT"); @@ -125,6 +137,28 @@ namespace ACPI FindTable(Header, (char *)"HMAT"); FindTable(Header, (char *)"CEDT"); FindTable(Header, (char *)"AEST"); + FindTable(Header, (char *)"AGDI"); + FindTable(Header, (char *)"APMT"); + FindTable(Header, (char *)"ETDT"); + FindTable(Header, (char *)"MPAM"); + FindTable(Header, (char *)"PDTT"); + FindTable(Header, (char *)"PPTT"); + FindTable(Header, (char *)"RAS2"); + FindTable(Header, (char *)"SDEI"); + FindTable(Header, (char *)"STAO"); + FindTable(Header, (char *)"XENV"); + FindTable(Header, (char *)"PHAT"); + FindTable(Header, (char *)"SVKL"); + FindTable(Header, (char *)"UUID"); + FindTable(Header, (char *)"CCEL"); + FindTable(Header, (char *)"WSMT"); + FindTable(Header, (char *)"PRMT"); + FindTable(Header, (char *)"NBFT"); + FindTable(Header, (char *)"RSD PTR"); + FindTable(Header, (char *)"TDX"); + FindTable(Header, (char *)"CXL"); + FindTable(Header, (char *)"DSD"); + FindTable(Header, (char *)"BSA"); } ACPI::ACPI() @@ -161,8 +195,9 @@ namespace ACPI if (FADT) { outb(s_cst(uint16_t, FADT->SMI_CommandPort), FADT->AcpiEnable); + /* TODO: Sleep for ~5 seconds before polling PM1a CB? */ while (!(inw(s_cst(uint16_t, FADT->PM1aControlBlock)) & 1)) - ; + CPU::Pause(); } } diff --git a/core/cpu.cpp b/core/cpu.cpp index c3b1f9b..623cb32 100644 --- a/core/cpu.cpp +++ b/core/cpu.cpp @@ -167,9 +167,9 @@ namespace CPU : "=r"(Flags)); return Flags & (1 << 9); #elif defined(aa64) - asmv("mrs %0, daif" + asmv("mrs %0, cpsr" : "=r"(Flags)); - return !(Flags & (1 << 2)); + return !(Flags & (1 << 7)); #endif } case Enable: @@ -177,7 +177,7 @@ namespace CPU #if defined(a86) asmv("sti"); #elif defined(aa64) - asmv("msr daifclr, #2"); + asmv("cpsie i"); #endif return true; } @@ -186,7 +186,7 @@ namespace CPU #if defined(a86) asmv("cli"); #elif defined(aa64) - asmv("msr daifset, #2"); + asmv("cpsid i"); #endif return true; } @@ -198,32 +198,39 @@ namespace CPU void *PageTable(void *PT) { + void *ret; #if defined(a64) + asmv("movq %%cr3, %0" + : "=r"(ret)); + if (PT) + { asmv("movq %0, %%cr3" : : "r"(PT)); - else - asmv("movq %%cr3, %0" - : "=r"(PT)); + } #elif defined(a32) + asmv("movl %%cr3, %0" + : "=r"(ret)); + if (PT) + { asmv("movl %0, %%cr3" : : "r"(PT)); - else - asmv("movl %%cr3, %0" - : "=r"(PT)); + } #elif defined(aa64) + asmv("mrs %0, ttbr0_el1" + : "=r"(ret)); + if (PT) + { asmv("msr ttbr0_el1, %0" : : "r"(PT)); - else - asmv("mrs %0, ttbr0_el1" - : "=r"(PT)); + } #endif - return PT; + return ret; } struct SupportedFeat @@ -378,7 +385,10 @@ namespace CPU if (!BSP++) trace("Features for BSP initialized."); if (SSEEnableAfter) + { SSEEnabled = true; + debug("SSE support enabled."); + } } uint64_t Counter() @@ -403,7 +413,8 @@ namespace CPU if (unlikely(!SSEEnabled)) return SIMD_NONE; - // return SIMD_SSE; +#warning "TODO: Proper SIMD support" + return SIMD_NONE; #if defined(a86) static uint64_t SIMDType = SIMD_NONE; @@ -415,13 +426,16 @@ namespace CPU { CPU::x86::AMD::CPUID0x00000001 cpuid; asmv("cpuid" - : "=a"(cpuid.EAX.raw), "=b"(cpuid.EBX.raw), "=c"(cpuid.ECX.raw), "=d"(cpuid.EDX.raw) + : "=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.SSSE3) + SIMDType |= SIMD_SSSE3; else if (cpuid.ECX.SSE3) SIMDType |= SIMD_SSE3; else if (cpuid.EDX.SSE2) @@ -434,6 +448,8 @@ namespace CPU debug("SSE4.2 is supported."); if (cpuid.ECX.SSE41) debug("SSE4.1 is supported."); + if (cpuid.ECX.SSSE3) + debug("SSSE3 is supported."); if (cpuid.ECX.SSE3) debug("SSE3 is supported."); if (cpuid.EDX.SSE2) @@ -455,6 +471,8 @@ namespace CPU SIMDType |= SIMD_SSE42; else if (cpuid.ECX.SSE4_1) SIMDType |= SIMD_SSE41; + else if (cpuid.ECX.SSSE3) + SIMDType |= SIMD_SSSE3; else if (cpuid.ECX.SSE3) SIMDType |= SIMD_SSE3; else if (cpuid.EDX.SSE2) @@ -467,6 +485,8 @@ namespace CPU debug("SSE4.2 is supported."); if (cpuid.ECX.SSE4_1) debug("SSE4.1 is supported."); + if (cpuid.ECX.SSSE3) + debug("SSSE3 is supported."); if (cpuid.ECX.SSE3) debug("SSE3 is supported."); if (cpuid.EDX.SSE2) @@ -499,6 +519,8 @@ namespace CPU return cpuid.ECX.SSE42; else if (Type == SIMD_SSE41) return cpuid.ECX.SSE41; + else if (Type == SIMD_SSSE3) + return cpuid.ECX.SSSE3; else if (Type == SIMD_SSE3) return cpuid.ECX.SSE3; else if (Type == SIMD_SSE2) @@ -517,6 +539,8 @@ namespace CPU return cpuid.ECX.SSE4_2; else if (Type == SIMD_SSE41) return cpuid.ECX.SSE4_1; + else if (Type == SIMD_SSSE3) + return cpuid.ECX.SSSE3; else if (Type == SIMD_SSE3) return cpuid.ECX.SSE3; else if (Type == SIMD_SSE2) diff --git a/core/crash/chfcts.hpp b/core/crash/chfcts.hpp index fa620ae..26aadcd 100644 --- a/core/crash/chfcts.hpp +++ b/core/crash/chfcts.hpp @@ -1,18 +1,18 @@ /* - This file is part of Fennix Kernel. + 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 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. + 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 . + 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__ @@ -29,22 +29,22 @@ typedef struct CPU::x64::TrapFrame CHArchTrapFrame; struct CRData { - CHArchTrapFrame *Frame; + 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; - CPU::x64::DR6 dr6; - CPU::x64::DR7 dr7; + 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; + CPU::x64::DR6 dr6; + CPU::x64::DR7 dr7; - long ID; - void *CPUData; - Tasking::PCB *Process; - Tasking::TCB *Thread; + long ID; + void *CPUData; + Tasking::PCB *Process; + Tasking::TCB *Thread; }; #elif defined(a32) @@ -52,251 +52,245 @@ typedef struct CPU::x32::TrapFrame CHArchTrapFrame; struct CRData { - CHArchTrapFrame *Frame; + CHArchTrapFrame *Frame; - CPU::x32::CR0 cr0; - CPU::x32::CR2 cr2; - CPU::x32::CR3 cr3; - CPU::x32::CR4 cr4; - CPU::x32::CR8 cr8; - uintptr_t dr0, dr1, dr2, dr3; - CPU::x32::DR6 dr6; - CPU::x32::DR7 dr7; + CPU::x32::CR0 cr0; + CPU::x32::CR2 cr2; + CPU::x32::CR3 cr3; + CPU::x32::CR4 cr4; + CPU::x32::CR8 cr8; + uintptr_t dr0, dr1, dr2, dr3; + CPU::x32::DR6 dr6; + CPU::x32::DR7 dr7; - long ID; - void *CPUData; - Tasking::PCB *Process; - Tasking::TCB *Thread; + long ID; + void *CPUData; + Tasking::PCB *Process; + Tasking::TCB *Thread; }; #elif defined(aa64) typedef struct CPU::aarch64::TrapFrame CHArchTrapFrame; struct CRData { - CHArchTrapFrame *Frame; + CHArchTrapFrame *Frame; - long ID; - void *CPUData; - Tasking::PCB *Process; - Tasking::TCB *Thread; + long ID; + void *CPUData; + 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_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_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_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_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, + 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; + extern int SBIdx; - class CrashKeyboardDriver : public Interrupts::Handler - { - private: - void PS2Wait(bool Read); + class CrashKeyboardDriver : public Interrupts::Handler + { + private: + void PS2Wait(bool Read); + void OnInterruptReceived(CPU::TrapFrame *Frame); -#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(); - }; + public: + CrashKeyboardDriver(); + ~CrashKeyboardDriver(); + }; - void TraceFrames(CRData data, int Count, SymbolResolver::Symbols *SymHandle, bool Kernel); + void TraceFrames(CRData data, int Count, SymbolResolver::Symbols *SymHandle, bool Kernel); - void ArrowInput(uint8_t key); - void UserInput(char *Input); + void ArrowInput(uint8_t key); + void UserInput(char *Input); - void DisplayMainScreen(CRData data); - void DisplayDetailsScreen(CRData data); - void DisplayStackFrameScreen(CRData data); - void DisplayTasksScreen(CRData data); - void DisplayConsoleScreen(CRData data); + void DisplayMainScreen(CRData data); + void DisplayDetailsScreen(CRData data); + void DisplayStackFrameScreen(CRData data); + void DisplayTasksScreen(CRData data); + void DisplayConsoleScreen(CRData data); } void DivideByZeroExceptionHandler(CHArchTrapFrame *Frame); diff --git a/core/crash/crash_details.cpp b/core/crash/crash_details.cpp index 9c7af0e..484f8f8 100644 --- a/core/crash/crash_details.cpp +++ b/core/crash/crash_details.cpp @@ -33,316 +33,316 @@ #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"}; + "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); + fixme("Divide by zero exception\n"); + UNUSED(Frame); } SafeFunction void DebugExceptionHandler(CHArchTrapFrame *Frame) { - CrashHandler::EHPrint("Kernel triggered debug exception.\n"); - UNUSED(Frame); + CrashHandler::EHPrint("Kernel triggered debug exception.\n"); + UNUSED(Frame); } SafeFunction void NonMaskableInterruptExceptionHandler(CHArchTrapFrame *Frame) { - fixme("NMI exception"); - UNUSED(Frame); + fixme("NMI exception"); + UNUSED(Frame); } SafeFunction void BreakpointExceptionHandler(CHArchTrapFrame *Frame) { - fixme("Breakpoint exception"); - UNUSED(Frame); + fixme("Breakpoint exception"); + UNUSED(Frame); } SafeFunction void OverflowExceptionHandler(CHArchTrapFrame *Frame) { - fixme("Overflow exception"); - UNUSED(Frame); + fixme("Overflow exception"); + UNUSED(Frame); } SafeFunction void BoundRangeExceptionHandler(CHArchTrapFrame *Frame) { - fixme("Bound range exception"); - UNUSED(Frame); + fixme("Bound range exception"); + UNUSED(Frame); } SafeFunction void InvalidOpcodeExceptionHandler(CHArchTrapFrame *Frame) { - CrashHandler::EHPrint("Kernel tried to execute an invalid opcode.\n"); - UNUSED(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); + fixme("Device not available exception"); + UNUSED(Frame); } SafeFunction void DoubleFaultExceptionHandler(CHArchTrapFrame *Frame) { - fixme("Double fault exception"); - UNUSED(Frame); + fixme("Double fault exception"); + UNUSED(Frame); } SafeFunction void CoprocessorSegmentOverrunExceptionHandler(CHArchTrapFrame *Frame) { - fixme("Coprocessor segment overrun exception"); - UNUSED(Frame); + fixme("Coprocessor segment overrun exception"); + UNUSED(Frame); } SafeFunction void InvalidTSSExceptionHandler(CHArchTrapFrame *Frame) { - fixme("Invalid TSS exception"); - UNUSED(Frame); + fixme("Invalid TSS exception"); + UNUSED(Frame); } SafeFunction void SegmentNotPresentExceptionHandler(CHArchTrapFrame *Frame) { - fixme("Segment not present exception"); - UNUSED(Frame); + fixme("Segment not present exception"); + UNUSED(Frame); } SafeFunction void StackFaultExceptionHandler(CHArchTrapFrame *Frame) { - CPU::x64::SelectorErrorCode SelCode = {.raw = Frame->ErrorCode}; + CPU::x64::SelectorErrorCode SelCode = {.raw = Frame->ErrorCode}; #if defined(a64) - CrashHandler::EHPrint("Stack segment fault at address %#lx\n", Frame->rip); + 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); + 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); + 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); + 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}; + 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); + 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); + 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]); + 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) + uintptr_t CheckPageFaultAddress = 0; + CheckPageFaultAddress = CrashHandler::PageFaultAddress; + if (CheckPageFaultAddress == 0) #ifdef a64 - CheckPageFaultAddress = Frame->rip; + CheckPageFaultAddress = Frame->rip; #elif defined(a32) - CheckPageFaultAddress = Frame->eip; + CheckPageFaultAddress = Frame->eip; #elif defined(aa64) - CheckPageFaultAddress = 0; + CheckPageFaultAddress = 0; #endif #if defined(a64) - Memory::Virtual vmm = Memory::Virtual(((Memory::PageTable *)CPU::x64::readcr3().raw)); + Memory::Virtual vmm(((Memory::PageTable *)CPU::x64::readcr3().raw)); #elif defined(a32) - Memory::Virtual vmm = Memory::Virtual(((Memory::PageTable *)CPU::x32::readcr3().raw)); + Memory::Virtual vmm(((Memory::PageTable *)CPU::x32::readcr3().raw)); #elif defined(aa64) - Memory::Virtual vmm = Memory::Virtual(); + Memory::Virtual vmm(); #warning "TODO: aa64" #endif - bool PageAvailable = vmm.Check((void *)CheckPageFaultAddress); - debug("Page available (Check(...)): %s. %s", - PageAvailable ? "Yes" : "No", - (params.P && !PageAvailable) ? "CR2 == Present; Check() != Present??????" : "CR2 confirms Check() result."); + bool PageAvailable = vmm.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 = vmm.Check((void *)CheckPageFaultAddress); - bool ReadWrite = vmm.Check((void *)CheckPageFaultAddress, Memory::PTFlag::RW); - bool User = vmm.Check((void *)CheckPageFaultAddress, Memory::PTFlag::US); - bool WriteThrough = vmm.Check((void *)CheckPageFaultAddress, Memory::PTFlag::PWT); - bool CacheDisabled = vmm.Check((void *)CheckPageFaultAddress, Memory::PTFlag::PCD); - bool Accessed = vmm.Check((void *)CheckPageFaultAddress, Memory::PTFlag::A); - bool Dirty = vmm.Check((void *)CheckPageFaultAddress, Memory::PTFlag::D); - bool Global = vmm.Check((void *)CheckPageFaultAddress, Memory::PTFlag::G); - /* ... */ + if (PageAvailable) + { + bool Present = vmm.Check((void *)CheckPageFaultAddress); + bool ReadWrite = vmm.Check((void *)CheckPageFaultAddress, Memory::PTFlag::RW); + bool User = vmm.Check((void *)CheckPageFaultAddress, Memory::PTFlag::US); + bool WriteThrough = vmm.Check((void *)CheckPageFaultAddress, Memory::PTFlag::PWT); + bool CacheDisabled = vmm.Check((void *)CheckPageFaultAddress, Memory::PTFlag::PCD); + bool Accessed = vmm.Check((void *)CheckPageFaultAddress, Memory::PTFlag::A); + bool Dirty = vmm.Check((void *)CheckPageFaultAddress, Memory::PTFlag::D); + bool Global = vmm.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"); + 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) - { + if (Present) + { #if defined(a64) - uintptr_t CheckPageFaultLinearAddress = (uintptr_t)CheckPageFaultAddress; - CheckPageFaultLinearAddress &= 0xFFFFFFFFFFFFF000; - debug("%#lx -> %#lx", CheckPageFaultAddress, CheckPageFaultLinearAddress); + 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::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::PageTable *)CPU::x64::readcr3().raw)->Entries[Index.PMLIndex]; + Memory::PageMapLevel4 PML4 = ((Memory::PageTable *)CPU::x64::readcr3().raw)->Entries[Index.PMLIndex]; #elif defined(a32) - Memory::PageMapLevel4 PML4 = ((Memory::PageTable *)CPU::x32::readcr3().raw)->Entries[Index.PMLIndex]; + Memory::PageMapLevel4 PML4 = ((Memory::PageTable *)CPU::x32::readcr3().raw)->Entries[Index.PMLIndex]; #elif defined(aa64) - Memory::PageMapLevel4 PML4 = {.raw = 0}; + 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); + 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, 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, 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 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); + 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 - } - } + } + } #endif } SafeFunction void x87FloatingPointExceptionHandler(CHArchTrapFrame *Frame) { - fixme("x87 floating point exception"); - UNUSED(Frame); + fixme("x87 floating point exception"); + UNUSED(Frame); } SafeFunction void AlignmentCheckExceptionHandler(CHArchTrapFrame *Frame) { - fixme("Alignment check exception"); - UNUSED(Frame); + fixme("Alignment check exception"); + UNUSED(Frame); } SafeFunction void MachineCheckExceptionHandler(CHArchTrapFrame *Frame) { - fixme("Machine check exception"); - UNUSED(Frame); + fixme("Machine check exception"); + UNUSED(Frame); } SafeFunction void SIMDFloatingPointExceptionHandler(CHArchTrapFrame *Frame) { - fixme("SIMD floating point exception"); - UNUSED(Frame); + fixme("SIMD floating point exception"); + UNUSED(Frame); } SafeFunction void VirtualizationExceptionHandler(CHArchTrapFrame *Frame) { - fixme("Virtualization exception"); - UNUSED(Frame); + fixme("Virtualization exception"); + UNUSED(Frame); } SafeFunction void SecurityExceptionHandler(CHArchTrapFrame *Frame) { - fixme("Security exception"); - UNUSED(Frame); + fixme("Security exception"); + UNUSED(Frame); } SafeFunction void UnknownExceptionHandler(CHArchTrapFrame *Frame) { - fixme("Unknown exception"); - UNUSED(Frame); + fixme("Unknown exception"); + UNUSED(Frame); } diff --git a/core/crash/crash_handler.cpp b/core/crash/crash_handler.cpp index 5c5e2a9..1724618 100644 --- a/core/crash/crash_handler.cpp +++ b/core/crash/crash_handler.cpp @@ -40,7 +40,6 @@ #endif #include "../../kernel.h" -#include "../../mapi.hpp" NewLock(UserInputLock); @@ -411,7 +410,7 @@ namespace CrashHandler #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])); + EHPrint("\e25CCC9%s", KernelSymbolTable->GetSymbol((uintptr_t)EHIntFrames[i])); else EHPrint("\eFF4CA9Outside Kernel"); #if defined(a86) @@ -726,7 +725,7 @@ namespace CrashHandler uint64_t ProgressLength = TotalMemLength; UniversalAsynchronousReceiverTransmitter::UART uart(port); Memory::Virtual vmm; - uint8_t *Address = reinterpret_cast(0x0); + uint8_t *Address = 0x0; int Progress = 0; for (size_t i = 0; i < TotalMemLength; i++) { @@ -806,33 +805,50 @@ namespace CrashHandler * 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); - // } + return; + if (SMP::CPUCores > 1) + { + APIC::InterruptCommandRegister icr{}; + bool x2APIC = ((APIC::APIC *)Interrupts::apic[0])->x2APIC; + + if (likely(x2APIC)) + { + icr.x2.VEC = s_cst(uint8_t, CPU::x86::IRQ31); + icr.x2.MT = APIC::Fixed; + icr.x2.L = APIC::Assert; + + for (int i = 1; i < SMP::CPUCores; i++) + { + icr.x2.DES = uint8_t(i); + ((APIC::APIC *)Interrupts::apic[i])->ICR(icr); + } + } + else + { + icr.VEC = s_cst(uint8_t, CPU::x86::IRQ31); + icr.MT = APIC::Fixed; + icr.L = APIC::Assert; + + for (int i = 1; i < SMP::CPUCores; i++) + { + icr.DES = uint8_t(i); + ((APIC::APIC *)Interrupts::apic[i])->ICR(icr); + } + } + CPU::Interrupts(CPU::Disable); + } #elif defined(aa64) #endif } - SafeFunction inline void Handle_x86_64(CHArchTrapFrame *Frame) + SafeFunction inline bool Handle_x86_64(CHArchTrapFrame *Frame) { #ifdef a64 + trace("Exception at %s", + KernelSymbolTable + ? KernelSymbolTable->GetSymbol(Frame->rip) + : "No symbol"); + for (size_t i = 0; i < INT_FRAMES_MAX; i++) EHIntFrames[i] = Interrupts::InterruptFrames[i]; PageFaultAddress = CPU::x64::readcr2().PFLA; @@ -844,14 +860,14 @@ namespace CrashHandler { debug("Exception in kernel mode (ip: %#lx cr2: %#lx (%s))", Frame->rip, PageFaultAddress, - KernelSymbolTable ? KernelSymbolTable->GetSymbolFromAddress(Frame->rip) + KernelSymbolTable ? KernelSymbolTable->GetSymbol(Frame->rip) : "No symbol"); } else { debug("Exception in kernel mode (ip: %#lx (%s))", Frame->rip, - KernelSymbolTable ? KernelSymbolTable->GetSymbolFromAddress(Frame->rip) + KernelSymbolTable ? KernelSymbolTable->GetSymbol(Frame->rip) : "No symbol"); } @@ -881,7 +897,7 @@ namespace CrashHandler debug("Exception in user mode (ip: %#lx cr2: %#lx (%s))", Frame->rip, PageFaultAddress, data->CurrentProcess->ELFSymbolTable - ? data->CurrentProcess->ELFSymbolTable->GetSymbolFromAddress(Frame->rip) + ? data->CurrentProcess->ELFSymbolTable->GetSymbol(Frame->rip) : "No symbol"); } else @@ -889,16 +905,18 @@ namespace CrashHandler debug("Exception in user mode (ip: %#lx (%s))", Frame->rip, data->CurrentProcess->ELFSymbolTable - ? data->CurrentProcess->ELFSymbolTable->GetSymbolFromAddress(Frame->rip) + ? data->CurrentProcess->ELFSymbolTable->GetSymbol(Frame->rip) : "No symbol"); } if (UserModeExceptionHandler(Frame)) - return; + return true; + else if (DebuggerIsAttached) + asmv("int $0x8"); if (unlikely(data->CurrentThread->Security.IsCritical)) { - debug("Critical thread \"%s\"(%d) died", + error("Critical thread \"%s\"(%d) died", data->CurrentThread->Name, data->CurrentThread->ID); if (TaskManager) @@ -906,26 +924,29 @@ namespace CrashHandler ForceUnlock = true; Display->CreateBuffer(0, 0, SBIdx); StopAllCores(); - return; + return false; } Tasking::TCB *tcb = data->CurrentThread; - Tasking::Task *ctx = tcb->GetContext(); - tcb->State = Tasking::Terminated; - tcb->ExitCode = Tasking::KILL_CRASH; CPU::Interrupts(CPU::Enable); while (true) { - ctx->Yield(); + tcb->GetContext()->Yield(); CPU::Halt(TaskManager->IsPanic()); } } #endif + return false; } - SafeFunction inline void Handle_x86_32(CHArchTrapFrame *Frame) + SafeFunction inline bool Handle_x86_32(CHArchTrapFrame *Frame) { #ifdef a32 + trace("Exception at %s", + KernelSymbolTable + ? KernelSymbolTable->GetSymbol(Frame->eip) + : "No symbol"); + for (size_t i = 0; i < INT_FRAMES_MAX; i++) EHIntFrames[i] = Interrupts::InterruptFrames[i]; PageFaultAddress = CPU::x32::readcr2().PFLA; @@ -938,7 +959,7 @@ namespace CrashHandler debug("Exception in kernel mode (ip: %#lx cr2: %#lx (%s))", Frame->eip, PageFaultAddress, data->CurrentProcess->ELFSymbolTable - ? data->CurrentProcess->ELFSymbolTable->GetSymbolFromAddress(Frame->eip) + ? data->CurrentProcess->ELFSymbolTable->GetSymbol(Frame->eip) : "No symbol"); } else @@ -946,12 +967,14 @@ namespace CrashHandler debug("Exception in kernel mode (ip: %#lx (%s))", Frame->eip, data->CurrentProcess->ELFSymbolTable - ? data->CurrentProcess->ELFSymbolTable->GetSymbolFromAddress(Frame->eip) + ? data->CurrentProcess->ELFSymbolTable->GetSymbol(Frame->eip) : "No symbol"); } if (UserModeExceptionHandler(Frame)) - return; + return true; + else if (DebuggerIsAttached) + asmv("int $0x8"); if (data->CurrentThread) { @@ -974,23 +997,25 @@ namespace CrashHandler { debug("Exception in user mode (ip: %#lx cr2: %#lx (%s))", Frame->eip, PageFaultAddress, - KernelSymbolTable ? KernelSymbolTable->GetSymbolFromAddress(Frame->eip) + KernelSymbolTable ? KernelSymbolTable->GetSymbol(Frame->eip) : "No symbol"); } else { debug("Exception in user mode (ip: %#lx (%s))", Frame->eip, - KernelSymbolTable ? KernelSymbolTable->GetSymbolFromAddress(Frame->eip) + KernelSymbolTable ? KernelSymbolTable->GetSymbol(Frame->eip) : "No symbol"); } if (UserModeExceptionHandler(Frame)) - return; + return true; + else if (DebuggerIsAttached) + asmv("int $0x8"); if (unlikely(data->CurrentThread->Security.IsCritical)) { - debug("Critical thread \"%s\"(%d) died", + error("Critical thread \"%s\"(%d) died", data->CurrentThread->Name, data->CurrentThread->ID); if (TaskManager) @@ -998,21 +1023,19 @@ namespace CrashHandler ForceUnlock = true; Display->CreateBuffer(0, 0, SBIdx); StopAllCores(); - return; + return false; } Tasking::TCB *tcb = data->CurrentThread; - Tasking::Task *ctx = tcb->GetContext(); - tcb->State = Tasking::Terminated; - tcb->ExitCode = Tasking::KILL_CRASH; CPU::Interrupts(CPU::Enable); while (true) { - ctx->Yield(); + tcb->GetContext()->Yield(); CPU::Halt(TaskManager->IsPanic()); } } #endif + return false; } SafeFunction inline void Print_x86_64(CHArchTrapFrame *Frame) @@ -1155,12 +1178,17 @@ namespace CrashHandler CHArchTrapFrame *Frame = (CHArchTrapFrame *)Data; SBIdx = 255; debug("-----------------------------------------------------------------------------------"); + debug("%ld MiB / %ld MiB (%ld MiB Reserved)", + TO_MiB(KernelAllocator.GetUsedMemory()), + TO_MiB(KernelAllocator.GetTotalMemory()), + TO_MiB(KernelAllocator.GetReservedMemory())); error("Exception: %#x", Frame->InterruptNumber); #if defined(a64) - Handle_x86_64(Frame); + if (Handle_x86_64(Frame)) #elif defined(a32) - Handle_x86_32(Frame); + if (Handle_x86_32(Frame)) #endif + return; if (ExceptionOccurred) { @@ -1180,8 +1208,8 @@ namespace CrashHandler ExceptionOccurred = true; - if (ModuleManager) - ModuleManager->Panic(); + if (DriverManager) + DriverManager->Panic(); debug("Reading control registers..."); crashdata.Frame = Frame; @@ -1397,6 +1425,7 @@ namespace CrashHandler DisplayTopOverlay(); DisplayMainScreen(crashdata); Display->SetBuffer(255); + Interrupts::RemoveAll(); kbd = new CrashKeyboardDriver; DisplayBottomOverlay(); Display->SetBuffer(255); diff --git a/core/crash/kb_drv.cpp b/core/crash/kb_drv.cpp index 97017db..5409f72 100644 --- a/core/crash/kb_drv.cpp +++ b/core/crash/kb_drv.cpp @@ -120,125 +120,109 @@ namespace CrashHandler #define WaitWrite PS2Wait(false) CPU::Interrupts(CPU::Disable); #if defined(a86) - // Disable devices + + /* Disable Port 1 */ WaitWrite; outb(0x64, 0xAD); + + /* Disable Port 2 */ WaitWrite; outb(0x64, 0xA7); - // Flush buffer + /* Flush */ WaitRead; inb(0x60); - // outb(0x64, 0xAE); - - // Configure devices - WaitWrite; - outb(0x64, 0x20); - WaitRead; - uint8_t cfg = inb(0x60); - bool DualChannel = cfg & 0b00100000; - if (DualChannel) - trace("Dual channel PS/2 controller detected."); - cfg |= 0b01000011; - WaitWrite; - outb(0x64, 0x60); - WaitWrite; - outb(0x60, cfg); - + /* Test PS/2 controller */ WaitWrite; outb(0x64, 0xAA); WaitRead; uint8_t test = inb(0x60); if (test != 0x55) { - error("PS/2 controller self test failed! (%#x)", test); - printf("PS/2 controller self test failed! (%#x)\n", test); - CPU::Stop(); + if (test == 0xFA) + warn("PS/2 controller acknowledged? (expected TEST_PASSED = 0x55)"); + else + { + error("PS/2 controller self test failed (%#x)", test); + // CPU::Stop(); + } } + /* Enable Port 1 */ + WaitWrite; + outb(0x64, 0xAE); + + /* Reset Port 1 */ + WaitWrite; + outb(0x64, 0xFF); /* This may break some keyboards? */ + + /* Test Port 1 */ + WaitWrite; + outb(0x64, 0xAB); + WaitRead; + test = inb(0x60); + + if (test != 0x00) + { + if (test == 0xFA) + warn("PS/2 keyboard acknowledged? (expected TEST_PASSED = 0x00)"); + else + { + error("PS/2 keyboard self test failed (%#x)", test); + // CPU::Stop(); + } + } + + /* Disable Port 1 */ + WaitWrite; + outb(0x64, 0xAD); + + /* Disable Port 2 */ + WaitWrite; + outb(0x64, 0xA7); + + /* Flush Port 1 */ + WaitRead; + inb(0x60); + + /* Read Controller Configuration */ + WaitWrite; + outb(0x64, 0x20); + WaitRead; + uint8_t cfg = inb(0x60); + + /* Enable Port 1 & Port 1 translation */ + cfg |= 0b01000001; + + /* Write Controller Configuration */ WaitWrite; outb(0x64, 0x60); WaitWrite; outb(0x60, cfg); - bool DCExists = false; - if (DualChannel) - { - WaitWrite; - outb(0x64, 0xAE); - WaitWrite; - outb(0x64, 0x20); - WaitRead; - cfg = inb(0x60); - DCExists = !(cfg & 0b00100000); - WaitWrite; - outb(0x64, 0xAD); - debug("DCExists: %d", DCExists); - } - - WaitWrite; - outb(0x64, 0xAB); - WaitRead; - test = inb(0x60); - if (test != 0x00) - { - error("PS/2 keyboard self test failed! (%#x)", test); - printf("PS/2 keyboard self test failed! (%#x)\n", test); - CPU::Stop(); - } - - if (DCExists) - { - WaitWrite; - outb(0x64, 0xA9); - WaitRead; - test = inb(0x60); - if (test != 0x00) - { - error("PS/2 mouse self test failed! (%#x)", test); - printf("PS/2 mouse self test failed! (%#x)\n", test); - CPU::Stop(); - } - } - - WaitWrite; + /* Enable Port 1 */ outb(0x64, 0xAE); - if (DCExists) - { - WaitWrite; - outb(0x64, 0xA8); - } - + /* Set scan code set 1 */ WaitWrite; - outb(0x60, 0xFF); + outb(0x60, 0xF0); + WaitWrite; + outb(0x60, 0x02); + + /* Check if we have scan code set 1 */ + WaitWrite; + outb(0x60, 0xF0); + WaitWrite; + outb(0x60, 0x00); + + /* Read scan code set */ WaitRead; - test = inb(0x60); - if (test == 0xFC) + uint8_t scs = inb(0x60); + if (scs != 0x41) { - error("PS/2 keyboard reset failed! (%#x)", test); - printf("PS/2 keyboard reset failed! (%#x)\n", test); - CPU::Stop(); + warn("PS/2 keyboard scan code set 1 not supported (%#x)", scs); } - - WaitWrite; - outb(0x60, 0xD4); - WaitWrite; - outb(0x60, 0xFF); - WaitRead; - test = inb(0x60); - if (test == 0xFC) - { - error("PS/2 mouse reset failed! (%#x)", test); - printf("PS/2 mouse reset failed! (%#x)\n", test); - CPU::Stop(); - } - - // outb(0x60, 0xF4); - - // outb(0x21, 0xFD); - // outb(0xA1, 0xFF); #endif // defined(a86) CPU::Interrupts(CPU::Enable); @@ -246,19 +230,13 @@ namespace CrashHandler CrashKeyboardDriver::~CrashKeyboardDriver() { - error("CrashKeyboardDriver::~CrashKeyboardDriver() called!"); + 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 + SafeFunction void CrashKeyboardDriver::OnInterruptReceived(CPU::TrapFrame *Frame) { #if defined(a86) UNUSED(Frame); diff --git a/core/crash/screens/console.cpp b/core/crash/screens/console.cpp index 403a02d..339c564 100644 --- a/core/crash/screens/console.cpp +++ b/core/crash/screens/console.cpp @@ -34,9 +34,9 @@ namespace CrashHandler { - SafeFunction void DisplayConsoleScreen(CRData data) - { - EHPrint("TODO"); - UNUSED(data); - } + SafeFunction void DisplayConsoleScreen(CRData data) + { + EHPrint("TODO"); + UNUSED(data); + } } \ No newline at end of file diff --git a/core/crash/screens/details.cpp b/core/crash/screens/details.cpp index 322df1c..317839b 100644 --- a/core/crash/screens/details.cpp +++ b/core/crash/screens/details.cpp @@ -34,232 +34,232 @@ 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; + 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("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.load(), cpu->CurrentThread.load()); - EHPrint("Arch Specific Data: %#lx\n", cpu->Data); - EHPrint("Checksum: 0x%X\n", cpu->Checksum); - } + CPUData *cpu = (CPUData *)data.CPUData; + if (cpu) + { + EHPrint("\eE46CEBCPU Data Address: %#lx\n", cpu); + 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.load(), cpu->CurrentThread.load()); + EHPrint("Arch Specific Data: %#lx\n", cpu->Data); + EHPrint("Checksum: 0x%X\n", cpu->Checksum); + } - asmv("mov %%ds, %0" - : "=r"(ds)); + asmv("mov %%ds, %0" + : "=r"(ds)); #elif defined(a32) - asmv("mov %%ds, %0" - : "=r"(ds)); + asmv("mov %%ds, %0" + : "=r"(ds)); #elif defined(aa64) #endif #if defined(a64) - EHPrint("\e7981FCFS=%#lx GS=%#lx SS=%#lx CS=%#lx DS=%#lx\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=%#lx R9=%#lx R10=%#lx R11=%#lx\n", data.Frame->r8, data.Frame->r9, data.Frame->r10, data.Frame->r11); - EHPrint("R12=%#lx R13=%#lx R14=%#lx R15=%#lx\n", data.Frame->r12, data.Frame->r13, data.Frame->r14, data.Frame->r15); - EHPrint("RAX=%#lx RBX=%#lx RCX=%#lx RDX=%#lx\n", data.Frame->rax, data.Frame->rbx, data.Frame->rcx, data.Frame->rdx); - EHPrint("RSI=%#lx RDI=%#lx RBP=%#lx RSP=%#lx\n", data.Frame->rsi, data.Frame->rdi, data.Frame->rbp, data.Frame->rsp); - EHPrint("RIP=%#lx RFL=%#lx INT=%#lx ERR=%#lx EFER=%#lx\n", data.Frame->rip, data.Frame->rflags.raw, data.Frame->InterruptNumber, data.Frame->ErrorCode, data.efer.raw); + EHPrint("\e7981FCFS=%#lx GS=%#lx SS=%#lx CS=%#lx DS=%#lx\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=%#lx R9=%#lx R10=%#lx R11=%#lx\n", data.Frame->r8, data.Frame->r9, data.Frame->r10, data.Frame->r11); + EHPrint("R12=%#lx R13=%#lx R14=%#lx R15=%#lx\n", data.Frame->r12, data.Frame->r13, data.Frame->r14, data.Frame->r15); + EHPrint("RAX=%#lx RBX=%#lx RCX=%#lx RDX=%#lx\n", data.Frame->rax, data.Frame->rbx, data.Frame->rcx, data.Frame->rdx); + EHPrint("RSI=%#lx RDI=%#lx RBP=%#lx RSP=%#lx\n", data.Frame->rsi, data.Frame->rdi, data.Frame->rbp, data.Frame->rsp); + EHPrint("RIP=%#lx RFL=%#lx INT=%#lx ERR=%#lx EFER=%#lx\n", data.Frame->rip, data.Frame->rflags.raw, data.Frame->InterruptNumber, data.Frame->ErrorCode, data.efer.raw); #elif defined(a32) - EHPrint("\e7981FCFS=%#x GS=%#x CS=%#x DS=%#x\n", - CPU::x32::rdmsr(CPU::x32::MSR_FS_BASE), CPU::x32::rdmsr(CPU::x32::MSR_GS_BASE), - data.Frame->cs, ds); - EHPrint("EAX=%#x EBX=%#x ECX=%#x EDX=%#x\n", data.Frame->eax, data.Frame->ebx, data.Frame->ecx, data.Frame->edx); - EHPrint("ESI=%#x EDI=%#x EBP=%#x ESP=%#x\n", data.Frame->esi, data.Frame->edi, data.Frame->ebp, data.Frame->esp); - EHPrint("EIP=%#x EFL=%#x INT=%#x ERR=%#x\n", data.Frame->eip, data.Frame->eflags.raw, data.Frame->InterruptNumber, data.Frame->ErrorCode); + EHPrint("\e7981FCFS=%#x GS=%#x CS=%#x DS=%#x\n", + CPU::x32::rdmsr(CPU::x32::MSR_FS_BASE), CPU::x32::rdmsr(CPU::x32::MSR_GS_BASE), + data.Frame->cs, ds); + EHPrint("EAX=%#x EBX=%#x ECX=%#x EDX=%#x\n", data.Frame->eax, data.Frame->ebx, data.Frame->ecx, data.Frame->edx); + EHPrint("ESI=%#x EDI=%#x EBP=%#x ESP=%#x\n", data.Frame->esi, data.Frame->edi, data.Frame->ebp, data.Frame->esp); + EHPrint("EIP=%#x EFL=%#x INT=%#x ERR=%#x\n", data.Frame->eip, data.Frame->eflags.raw, data.Frame->InterruptNumber, data.Frame->ErrorCode); #elif defined(aa64) #endif #if defined(a86) - EHPrint("CR0=%#lx CR2=%#lx CR3=%#lx CR4=%#lx CR8=%#lx\n", data.cr0.raw, data.cr2.raw, data.cr3.raw, data.cr4.raw, data.cr8.raw); - EHPrint("DR0=%#lx DR1=%#lx DR2=%#lx DR3=%#lx DR6=%#lx DR7=%#lx\n", data.dr0, data.dr1, data.dr2, data.dr3, data.dr6, data.dr7.raw); + EHPrint("CR0=%#lx CR2=%#lx CR3=%#lx CR4=%#lx CR8=%#lx\n", data.cr0.raw, data.cr2.raw, data.cr3.raw, data.cr4.raw, data.cr8.raw); + EHPrint("DR0=%#lx DR1=%#lx DR2=%#lx DR3=%#lx DR6=%#lx DR7=%#lx\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", - 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"); + 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", + 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"); - EHPrint("\eFCBD79CR2: PFLA: %#lx\n", - data.cr2.PFLA); + EHPrint("\eFCBD79CR2: PFLA: %#lx\n", + data.cr2.PFLA); - EHPrint("\e79FC84CR3: PWT:%s PCD:%s PDBR:%#lx\n", - data.cr3.PWT ? "True " : "False", data.cr3.PCD ? "True " : "False", data.cr3.PDBR); + EHPrint("\e79FC84CR3: PWT:%s PCD:%s PDBR:%#lx\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", - 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"); - EHPrint("\e79FCF5CR8: TPL:%d\n", data.cr8.TPL); + 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", + 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"); + 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", - 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); + 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", + 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); #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", - 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); + 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", + 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); #elif defined(aa64) #endif #if defined(a86) - EHPrint("\eA0A0A0DR6: B0:%s B1:%s B2:%s B3:%s\n BD:%s BS:%s BT:%s\n", - data.dr6.B0 ? "True " : "False", data.dr6.B1 ? "True " : "False", data.dr6.B2 ? "True " : "False", data.dr6.B3 ? "True " : "False", - data.dr6.BD ? "True " : "False", data.dr6.BS ? "True " : "False", data.dr6.BT ? "True " : "False"); + EHPrint("\eA0A0A0DR6: B0:%s B1:%s B2:%s B3:%s\n BD:%s BS:%s BT:%s\n", + data.dr6.B0 ? "True " : "False", data.dr6.B1 ? "True " : "False", data.dr6.B2 ? "True " : "False", data.dr6.B3 ? "True " : "False", + data.dr6.BD ? "True " : "False", data.dr6.BS ? "True " : "False", data.dr6.BT ? "True " : "False"); - EHPrint("\eA0F0F0DR7: L0:%s G0:%s L1:%s G1:%s\n L2:%s G2:%s L3:%s G3:%s\n LE:%s GE:%s GD:%s\n R/W0:%s LEN0:%s R/W1:%s LEN1:%s\n R/W2:%s LEN2:%s R/W3:%s LEN3:%s\n", - data.dr7.L0 ? "True " : "False", data.dr7.G0 ? "True " : "False", data.dr7.L1 ? "True " : "False", data.dr7.G1 ? "True " : "False", - data.dr7.L2 ? "True " : "False", data.dr7.G2 ? "True " : "False", data.dr7.L3 ? "True " : "False", data.dr7.G3 ? "True " : "False", - data.dr7.LE ? "True " : "False", data.dr7.GE ? "True " : "False", data.dr7.GD ? "True " : "False", data.dr7.RW0 ? "True " : "False", - data.dr7.LEN0 ? "True " : "False", data.dr7.RW1 ? "True " : "False", data.dr7.LEN1 ? "True " : "False", data.dr7.RW2 ? "True " : "False", - data.dr7.LEN2 ? "True " : "False", data.dr7.RW3 ? "True " : "False", data.dr7.LEN3 ? "True " : "False"); + EHPrint("\eA0F0F0DR7: L0:%s G0:%s L1:%s G1:%s\n L2:%s G2:%s L3:%s G3:%s\n LE:%s GE:%s GD:%s\n R/W0:%s LEN0:%s R/W1:%s LEN1:%s\n R/W2:%s LEN2:%s R/W3:%s LEN3:%s\n", + data.dr7.L0 ? "True " : "False", data.dr7.G0 ? "True " : "False", data.dr7.L1 ? "True " : "False", data.dr7.G1 ? "True " : "False", + data.dr7.L2 ? "True " : "False", data.dr7.G2 ? "True " : "False", data.dr7.L3 ? "True " : "False", data.dr7.G3 ? "True " : "False", + data.dr7.LE ? "True " : "False", data.dr7.GE ? "True " : "False", data.dr7.GD ? "True " : "False", data.dr7.RW0 ? "True " : "False", + data.dr7.LEN0 ? "True " : "False", data.dr7.RW1 ? "True " : "False", data.dr7.LEN1 ? "True " : "False", data.dr7.RW2 ? "True " : "False", + data.dr7.LEN2 ? "True " : "False", data.dr7.RW3 ? "True " : "False", data.dr7.LEN3 ? "True " : "False"); #ifdef a64 - EHPrint("\e009FF0EFER: SCE:%s LME:%s LMA:%s NXE:%s\n SVME:%s LMSLE:%s FFXSR:%s TCE:%s\n\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"); + EHPrint("\e009FF0EFER: SCE:%s LME:%s LMA:%s NXE:%s\n SVME:%s LMSLE:%s FFXSR:%s TCE:%s\n\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"); #endif // a64 #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; - } - } - } + 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/core/crash/screens/main.cpp b/core/crash/screens/main.cpp index 4c9ca5f..cb55650 100644 --- a/core/crash/screens/main.cpp +++ b/core/crash/screens/main.cpp @@ -33,358 +33,358 @@ #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"}; + "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; + SafeFunction void DisplayMainScreen(CRData data) + { + CHArchTrapFrame *Frame = data.Frame; - /* + /* _______ ___ ___ _______ _______ _______ _______ ______ ______ _______ _______ _______ _______ _____ | __| | | __|_ _| ___| | | | | __ \ _ | __| | | ___| \ |__ |\ /|__ | | | | ___| | | ---| < |__ | | ___| -- | |_______| |___| |_______| |___| |_______|__|_|__| |______|___|__|___|___|_______|___|___|_______|_____/ - */ - EHPrint("\eFF5500 _______ ___ ___ _______ _______ _______ _______ ______ ______ _______ _______ _______ _______ _____ \n"); - EHPrint("| __| | | __|_ _| ___| | | | | __ \\ _ | __| | | ___| \\ \n"); - EHPrint("|__ |\\ /|__ | | | | ___| | | ---| < |__ | | ___| -- |\n"); - EHPrint("|_______| |___| |_______| |___| |_______|__|_|__| |______|___|__|___|___|_______|___|___|_______|_____/ \n\eFAFAFA"); + */ + 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/accessible.\n"); + 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/accessible.\n"); - CPU::x64::PageFaultErrorCode params = {.raw = (uint32_t)Frame->ErrorCode}; + CPU::x64::PageFaultErrorCode params = {.raw = (uint32_t)Frame->ErrorCode}; #if defined(a64) - EHPrint("At \e8888FF%#lx \eFAFAFAby \e8888FF%#lx\eFAFAFA\n", PageFaultAddress, Frame->rip); + 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); + 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; - } - } + 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); + 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); + EHPrint("The exception happened at \e8888FF%#lx\eFAFAFA\n", Frame->eip); #elif defined(aa64) #endif - } + } } diff --git a/core/crash/screens/stack_frame.cpp b/core/crash/screens/stack_frame.cpp index 80599f8..b1c28f0 100644 --- a/core/crash/screens/stack_frame.cpp +++ b/core/crash/screens/stack_frame.cpp @@ -35,65 +35,44 @@ 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-"); + 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 *pSt = data.Process->ELFSymbolTable; + debug("pSt = %#lx", pSt); + if (!pSt || !pSt->SymTableExists) + EHPrint("\n\eFF0000< No symbol table available. >\n"); + else + TraceFrames(data, 10, pSt, 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) + 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) + 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) + 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"); - } - } + EHPrint("\e25CCC9%s", + KernelSymbolTable->GetSymbol((uintptr_t)EHIntFrames[i])); + else + EHPrint("\eFF4CA9Outside Kernel"); + } + } + } } diff --git a/core/crash/screens/tasks.cpp b/core/crash/screens/tasks.cpp index 83a4ad3..c0860f2 100644 --- a/core/crash/screens/tasks.cpp +++ b/core/crash/screens/tasks.cpp @@ -1,18 +1,18 @@ /* - This file is part of Fennix Kernel. + 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 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. + 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 . + You should have received a copy of the GNU General Public License + along with Fennix Kernel. If not, see . */ #include "../../crashhandler.hpp" @@ -34,64 +34,66 @@ namespace CrashHandler { - SafeFunction void DisplayTasksScreen(CRData data) - { - const char *StatusColor[9] = { - "FF0000", // Unknown - "AAFF00", // Ready - "00AA00", // Running - "FFAA00", // Sleeping - "FFAA00", // Blocked - "FFAA00", // Stopped - "FFAA00", // Waiting + SafeFunction void DisplayTasksScreen(CRData data) + { + const char *StatusColor[] = { + "FF0000", // Unknown + "AAFF00", // Ready + "00AA00", // Running + "FFAA00", // Sleeping + "FFAA00", // Blocked + "FFAA00", // Stopped + "FFAA00", // Waiting - "FF0088", // Zombie - "FF0000", // Terminated - }; + "FF00FF", // Core dump + "FF0088", // Zombie + "FF0000", // Terminated + }; - const char *StatusString[9] = { - "Unknown", // Unknown - "Ready", // Ready - "Running", // Running - "Sleeping", // Sleeping - "Blocked", // Blocked - "Stopped", // Stopped - "Waiting", // Waiting + const char *StatusString[] = { + "Unknown", // Unknown + "Ready", // Ready + "Running", // Running + "Sleeping", // Sleeping + "Blocked", // Blocked + "Stopped", // Stopped + "Waiting", // Waiting - "Zombie", // Zombie - "Terminated", // Terminated - }; + "CoreDump", // Core dump + "Zombie", // Zombie + "Terminated", // Terminated + }; - if (TaskManager) - { - std::vector Plist = TaskManager->GetProcessList(); + if (TaskManager) + { + std::list Plist = TaskManager->GetProcessList(); - if (data.Thread) + 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); + 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); + 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->State.load()], Process->Name, - Process->ID, StatusString[Process->State.load()], - Process->PageTable); + 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->State.load()], Process->Name, + Process->ID, StatusString[Process->State.load()], + Process->PageTable); - foreach (auto Thread in Process->Threads) - EHPrint("\e%s -> \eFAFAFA%s\eCCCCCC(%ld) \e00AAAA%s\eFAFAFA Stack:\e00AAAA%#lx\n", - StatusColor[Thread->State.load()], Thread->Name, - Thread->ID, StatusString[Thread->State.load()], - Thread->Stack); - } - } - else - EHPrint("\eFAFAFATaskManager is not initialized!\n"); - } + foreach (auto Thread in Process->Threads) + EHPrint("\e%s -> \eFAFAFA%s\eCCCCCC(%ld) \e00AAAA%s\eFAFAFA Stack:\e00AAAA%#lx\n", + StatusColor[Thread->State.load()], Thread->Name, + Thread->ID, StatusString[Thread->State.load()], + Thread->Stack); + } + } + else + EHPrint("\eFAFAFATaskManager is not initialized!\n"); + } } diff --git a/core/crash/stack_frame.cpp b/core/crash/stack_frame.cpp index 8cecea8..76796ac 100644 --- a/core/crash/stack_frame.cpp +++ b/core/crash/stack_frame.cpp @@ -32,117 +32,144 @@ #include "../../kernel.h" +#define AddrToStr(addr) SymHandle->GetSymbol(addr) + namespace CrashHandler { - struct StackFrame - { - struct StackFrame *rbp; - uintptr_t rip; - }; + 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; - } + SafeFunction void TraceFrames(CRData data, int Count, + SymbolResolver::Symbols *SymHandle, + bool Kernel) + { + Memory::Virtual vmm; - if (!Memory::Virtual().Check(SymHandle)) - { - EHPrint("Invalid symbol handle: %p\n", SymHandle); - return; - } + if (!vmm.Check(data.Frame)) + { + EHPrint("Invalid frame pointer: %p\n", data.Frame); + 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; - } + if (!vmm.Check(SymHandle)) + { + EHPrint("Invalid symbol handle: %p\n", SymHandle); + return; + } - debug("\nStack tracing... %p %d %p %d", data.Frame, Count, frames, Kernel); - EHPrint("\e7981FC\nStack Trace:\n"); - if (!frames || !frames->rip || !frames->rbp) - { + bool TriedRetryBP = false; + struct StackFrame *frames = nullptr; + RetryBP: #if defined(a64) - EHPrint("\e2565CC%p", (void *)data.Frame->rip); + if (TriedRetryBP == false) + frames = (struct StackFrame *)data.Frame->rbp; #elif defined(a32) - EHPrint("\e2565CC%p", (void *)data.Frame->eip); + if (TriedRetryBP == false) + frames = (struct StackFrame *)data.Frame->ebp; #elif defined(aa64) #endif - EHPrint("\e7925CC-"); + if (!vmm.Check((void *)frames)) + { + if (TriedRetryBP == false) + { + Memory::Virtual vma(data.Process->PageTable); + debug("Invalid frame pointer: %p", frames); + frames = (struct StackFrame *)data.Process->PageTable->Get((void *)frames); + debug("Physical frame pointer: %p", frames); + TriedRetryBP = true; + goto RetryBP; + } #if defined(a64) - EHPrint("\eAA25CC%s", SymHandle->GetSymbolFromAddress(data.Frame->rip)); + EHPrint("Invalid rbp pointer: %p\n", data.Frame->rbp); #elif defined(a32) - EHPrint("\eAA25CC%s", SymHandle->GetSymbolFromAddress(data.Frame->eip)); + EHPrint("Invalid ebp pointer: %p\n", data.Frame->ebp); #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"); + return; + } - if (!Memory::Virtual().Check(frames->rbp)) - return; - frames = frames->rbp; - } - } - EHPrint("\n"); - } + debug("Stack 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", AddrToStr(data.Frame->rip)); +#elif defined(a32) + EHPrint("\eAA25CC%s", AddrToStr(data.Frame->eip)); +#elif defined(aa64) +#endif + EHPrint("\e7981FC <- Exception"); + EHPrint("\eFF0000\n< No stack trace available. >\n"); + } + else + { +#if defined(a64) + debug("Exception in function %s(%p)", + AddrToStr(data.Frame->rip), + data.Frame->rip); + EHPrint("\e2565CC%p", (void *)data.Frame->rip); + EHPrint("\e7925CC-"); + if ((data.Frame->rip >= 0xFFFFFFFF80000000 && + data.Frame->rip <= (uintptr_t)&_kernel_end) || + Kernel == false) + { + EHPrint("\eAA25CC%s", AddrToStr(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 == false) + { + EHPrint("\eAA25CC%s", AddrToStr(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 == false) +#elif defined(a32) + if ((frames->rip >= 0xC0000000 && + frames->rip <= (uintptr_t)&_kernel_end) || + Kernel == false) +#elif defined(aa64) + if ((frames->rip >= 0xFFFFFFFF80000000 && + frames->rip <= (uintptr_t)&_kernel_end) || + Kernel == false) +#endif + EHPrint("\e25CCC9%s", AddrToStr(frames->rip)); + else + EHPrint("\eFF4CA9Outside Kernel"); + + if (!vmm.Check(frames->rbp)) + return; + frames = frames->rbp; + } + } + EHPrint("\n"); + } } diff --git a/core/crash/user_handler.cpp b/core/crash/user_handler.cpp index 886beb8..046677b 100644 --- a/core/crash/user_handler.cpp +++ b/core/crash/user_handler.cpp @@ -34,8 +34,12 @@ SafeFunction bool UserModeExceptionHandler(CHArchTrapFrame *Frame) { - thisThread->State = Tasking::TaskState::Waiting; CPUData *CurCPU = GetCurrentCPU(); + Tasking::PCB *CurProc = CurCPU->CurrentProcess; + Tasking::TCB *CurThread = CurCPU->CurrentThread; + debug("Current process %s(%d) and thread %s(%d)", + CurProc->Name, CurProc->ID, CurThread->Name, CurThread->ID); + CurThread->SetState(Tasking::Waiting); #ifdef DEBUG { @@ -153,37 +157,59 @@ SafeFunction bool UserModeExceptionHandler(CHArchTrapFrame *Frame) { bool Handled = false; - Handled = CurCPU->CurrentProcess->vma->HandleCoW(CrashHandler::PageFaultAddress); + Handled = CurProc->vma->HandleCoW(CrashHandler::PageFaultAddress); if (!Handled) - Handled = CurCPU->CurrentThread->Stack->Expand(CrashHandler::PageFaultAddress); + Handled = CurThread->Stack->Expand(CrashHandler::PageFaultAddress); if (Handled) { debug("Page fault handled"); - thisThread->State = Tasking::TaskState::Ready; + CurThread->SetState(Tasking::Ready); return true; } + CurProc->Signals->SendSignal(SIGSEGV, + {Tasking::KILL_CRASH}); + break; + } + case CPU::x86::Debug: + case CPU::x86::Breakpoint: + { + CurProc->Signals->SendSignal(SIGTRAP, + {Tasking::KILL_CRASH}); break; } case CPU::x86::DivideByZero: - case CPU::x86::Debug: - case CPU::x86::NonMaskableInterrupt: - case CPU::x86::Breakpoint: case CPU::x86::Overflow: case CPU::x86::BoundRange: + case CPU::x86::x87FloatingPoint: + case CPU::x86::SIMDFloatingPoint: + { + CurProc->Signals->SendSignal(SIGFPE, + {Tasking::KILL_CRASH}); + break; + } case CPU::x86::InvalidOpcode: + case CPU::x86::GeneralProtectionFault: + { + CurProc->Signals->SendSignal(SIGILL, + {Tasking::KILL_CRASH}); + break; + } case CPU::x86::DeviceNotAvailable: + { + CurProc->Signals->SendSignal(SIGBUS, + {Tasking::KILL_CRASH}); + break; + } + case CPU::x86::NonMaskableInterrupt: case CPU::x86::DoubleFault: case CPU::x86::CoprocessorSegmentOverrun: case CPU::x86::InvalidTSS: case CPU::x86::SegmentNotPresent: case CPU::x86::StackSegmentFault: - case CPU::x86::GeneralProtectionFault: - case CPU::x86::x87FloatingPoint: case CPU::x86::AlignmentCheck: case CPU::x86::MachineCheck: - case CPU::x86::SIMDFloatingPoint: case CPU::x86::Virtualization: case CPU::x86::Security: default: diff --git a/core/crashhandler.hpp b/core/crashhandler.hpp index 66dabfb..60456cb 100644 --- a/core/crashhandler.hpp +++ b/core/crashhandler.hpp @@ -25,11 +25,11 @@ namespace CrashHandler { - extern uintptr_t PageFaultAddress; - extern void *EHIntFrames[INT_FRAMES_MAX]; + extern uintptr_t PageFaultAddress; + extern void *EHIntFrames[INT_FRAMES_MAX]; - void EHPrint(const char *Format, ...); - void Handle(void *Data); + void EHPrint(const char *Format, ...); + void Handle(void *Data); } #endif // !__FENNIX_KERNEL_CRASH_HANDLER_H__ diff --git a/core/debugger.cpp b/core/debugger.cpp index e7df117..8c6d0e1 100644 --- a/core/debugger.cpp +++ b/core/debugger.cpp @@ -21,11 +21,13 @@ #include #include +#include "../kernel.h" + NewLock(DebuggerLock); extern bool serialports[8]; -static inline NIF void uart_wrapper(char c, void *unused) +EXTERNC NIF void uart_wrapper(char c, void *unused) { static int once = 0; if (unlikely(!once++)) diff --git a/core/disk.cpp b/core/disk.cpp index aa0b69e..dd003ae 100644 --- a/core/disk.cpp +++ b/core/disk.cpp @@ -21,18 +21,17 @@ #include #include "../kernel.h" -#include "../mapi.hpp" -#include "../Fex.hpp" namespace Disk { void Manager::FetchDisks(unsigned long modUniqueID) { - KernelCallback callback{}; - callback.Reason = QueryReason; - ModuleManager->IOCB(modUniqueID, &callback); - this->AvailablePorts = callback.DiskCallback.Fetch.Ports; - this->BytesPerSector = callback.DiskCallback.Fetch.BytesPerSector; + /* KernelCallback */ + // KernelCallback callback{}; + // callback.Reason = QueryReason; + // DriverManager->IOCB(modUniqueID, &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) @@ -49,15 +48,16 @@ namespace Disk drive->MechanicalDisk = true; memset(RWBuffer, 0, this->BytesPerSector); - callback.Reason = ReceiveReason; - callback.DiskCallback.RW = { - .Sector = 0, - .SectorCount = 2, - .Port = ItrPort, - .Buffer = RWBuffer, - .Write = false, - }; - ModuleManager->IOCB(modUniqueID, &callback); + /* KernelCallback */ + // callback.Reason = ReceiveReason; + // callback.DiskCallback.RW = { + // .Sector = 0, + // .SectorCount = 2, + // .Port = ItrPort, + // .Buffer = RWBuffer, + // .Write = false, + // }; + // DriverManager->IOCB(modUniqueID, &callback); memcpy(&drive->Table, RWBuffer, sizeof(PartitionTable)); /* @@ -72,15 +72,16 @@ namespace Disk 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, - }; - ModuleManager->IOCB(modUniqueID, &callback); + /* KernelCallback */ + // callback.Reason = ReceiveReason; + // callback.DiskCallback.RW = { + // .Sector = 2 + Block, + // .SectorCount = 1, + // .Port = ItrPort, + // .Buffer = RWBuffer, + // .Write = false, + // }; + // DriverManager->IOCB(modUniqueID, &callback); for (uint32_t e = 0; e < Entries; e++) { diff --git a/core/driver/api.cpp b/core/driver/api.cpp new file mode 100644 index 0000000..787a119 --- /dev/null +++ b/core/driver/api.cpp @@ -0,0 +1,939 @@ +/* + 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 "../../kernel.h" +#include "../../driver.h" + +// #define DEBUG_API + +#ifdef DEBUG_API +#define dbg_api(Format, ...) function(Format, ##__VA_ARGS__) +#else +#define dbg_api(Format, ...) +#endif + +using enum PCI::PCICommands; + +#define VMWARE_MAGIC 0x564D5868 /* hXMV */ +#define VMWARE_PORT 0x5658 +#define CMD_GETVERSION 0xA + +namespace Driver +{ + int RegisterFunction(dev_t MajorID, void *Function, __driverRegFunc Type) + { + dbg_api("%d, %#lx, %d", MajorID, (uintptr_t)Function, Type); + + std::unordered_map &Drivers = + DriverManager->GetDrivers(); + + auto itr = Drivers.find(MajorID); + if (itr == Drivers.end()) + return -EINVAL; + + DriverObject *drv = &itr->second; + + switch (Type) + { + case _drf_Entry: + drv->Entry = (int (*)())Function; + debug("Entry %#lx for %s", (uintptr_t)Function, drv->Path); + break; + case _drf_Final: + drv->Final = (int (*)())Function; + debug("Finalize %#lx for %s", (uintptr_t)Function, drv->Path); + break; + case _drf_Panic: + drv->Panic = (int (*)())Function; + debug("Panic %#lx for %s", (uintptr_t)Function, drv->Path); + break; + case _drf_Probe: + drv->Probe = (int (*)())Function; + debug("Probe %#lx for %s", (uintptr_t)Function, drv->Path); + break; + default: + assert(!"Invalid driver function type"); + } + return 0; + } + + int GetDriverInfo(dev_t MajorID, const char *Name, const char *Description, const char *Author, const char *Version, const char *License) + { + dbg_api("%d, %s, %s, %s, %s, %s", MajorID, Name, Description, Author, Version, License); + + std::unordered_map &Drivers = + DriverManager->GetDrivers(); + + auto itr = Drivers.find(MajorID); + if (itr == Drivers.end()) + return -EINVAL; + + DriverObject *drv = &itr->second; + + strncpy(drv->Name, Name, sizeof(drv->Name)); + strncpy(drv->Description, Description, sizeof(drv->Description)); + strncpy(drv->Author, Author, sizeof(drv->Author)); + strncpy(drv->Version, Version, sizeof(drv->Version)); + strncpy(drv->License, License, sizeof(drv->License)); + return 0; + } + + /* --------- */ + + int RegisterInterruptHandler(dev_t MajorID, uint8_t IRQ, void *Handler) + { + dbg_api("%d, %d, %#lx", MajorID, IRQ, Handler); + + std::unordered_map &Drivers = + DriverManager->GetDrivers(); + + auto itr = Drivers.find(MajorID); + if (itr == Drivers.end()) + return -EINVAL; + + DriverObject *drv = &itr->second; + + if (drv->InterruptHandlers->contains(IRQ)) + return -EEXIST; + + Interrupts::AddHandler((void (*)(CPU::TrapFrame *))Handler, IRQ); + drv->InterruptHandlers->insert(std::pair(IRQ, Handler)); + return 0; + } + + int OverrideInterruptHandler(dev_t MajorID, uint8_t IRQ, void *Handler) + { + dbg_api("%d, %d, %#lx", MajorID, IRQ, Handler); + + debug("Overriding IRQ %d with %#lx", IRQ, Handler); + + std::unordered_map &Drivers = + DriverManager->GetDrivers(); + + foreach (auto &var in Drivers) + { + DriverObject *drv = &var.second; + + foreach (auto &ih in * drv->InterruptHandlers) + { + if (ih.first == IRQ) + { + debug("Removing IRQ %d: %#lx for %s", IRQ, (uintptr_t)ih.second, drv->Path); + Interrupts::RemoveHandler((void (*)(CPU::TrapFrame *))ih.second, IRQ); + drv->InterruptHandlers->erase(IRQ); + break; + } + } + } + + return RegisterInterruptHandler(MajorID, IRQ, Handler); + } + + int UnregisterInterruptHandler(dev_t MajorID, uint8_t IRQ, void *Handler) + { + dbg_api("%d, %d, %#lx", MajorID, IRQ, Handler); + + std::unordered_map &Drivers = + DriverManager->GetDrivers(); + + auto itr = Drivers.find(MajorID); + if (itr == Drivers.end()) + return -EINVAL; + + DriverObject *drv = &itr->second; + Interrupts::RemoveHandler((void (*)(CPU::TrapFrame *))Handler, IRQ); + drv->InterruptHandlers->erase(IRQ); + return 0; + } + + int UnregisterAllInterruptHandlers(dev_t MajorID, void *Handler) + { + dbg_api("%d, %#lx", MajorID, Handler); + + std::unordered_map &Drivers = + DriverManager->GetDrivers(); + + auto itr = Drivers.find(MajorID); + if (itr == Drivers.end()) + return -EINVAL; + + DriverObject *drv = &itr->second; + foreach (auto &i in * drv->InterruptHandlers) + { + Interrupts::RemoveHandler((void (*)(CPU::TrapFrame *))Handler, i.first); + debug("Removed IRQ %d: %#lx for %s", i.first, (uintptr_t)Handler, drv->Path); + } + drv->InterruptHandlers->clear(); + return 0; + } + + /* --------- */ + + dev_t RegisterInputDevice(dev_t MajorID, DeviceDriverType Type) + { + dbg_api("%d, %d", MajorID, Type); + + switch (Type) + { + case ddt_Keyboard: + return DriverManager->InputKeyboardDev->Register(MajorID); + case ddt_Mouse: + return DriverManager->InputMouseDev->Register(MajorID); + /* ... */ + default: + assert(!"Invalid input device type"); + } + } + + int UnregisterInputDevice(dev_t MajorID, dev_t MinorID, DeviceDriverType Type) + { + dbg_api("%d, %d, %d", MajorID, MinorID, Type); + + switch (Type) + { + case ddt_Keyboard: + return DriverManager->InputKeyboardDev->Unregister(MajorID, MinorID); + case ddt_Mouse: + return DriverManager->InputMouseDev->Unregister(MajorID, MinorID); + /* ... */ + default: + assert(!"Invalid input device type"); + } + } + + int ReportKeyboardEvent(dev_t MajorID, dev_t MinorID, uint8_t ScanCode) + { + dbg_api("%d, %d, %d", MajorID, MinorID, ScanCode); + + return DriverManager->InputKeyboardDev->ReportKeyEvent(MajorID, MinorID, ScanCode); + } + + int ReportRelativeMouseEvent(dev_t MajorID, dev_t MinorID, __MouseButtons Button, int X, int Y, int8_t Z) + { + dbg_api("%d, %d, %d, %d, %d, %d", MajorID, MinorID, Button, X, Y, Z); + + return DriverManager->InputMouseDev->ReportMouseEvent(MajorID, MinorID, + Button.LeftButton, Button.RightButton, Button.MiddleButton, + Button.Button4, Button.Button5, Button.Button6, Button.Button7, Button.Button8, + X, Y, Z, true); + } + + int ReportAbsoluteMouseEvent(dev_t MajorID, dev_t MinorID, __MouseButtons Button, uintptr_t X, uintptr_t Y, int8_t Z) + { + dbg_api("%d, %d, %d, %d, %d, %d", MajorID, MinorID, Button, X, Y, Z); + + return DriverManager->InputMouseDev->ReportMouseEvent(MajorID, MinorID, + Button.LeftButton, Button.RightButton, Button.MiddleButton, + Button.Button4, Button.Button5, Button.Button6, Button.Button7, Button.Button8, + X, Y, Z, false); + } + + /* --------- */ + + dev_t RegisterBlockDevice(dev_t MajorID, DeviceDriverType Type, void *Open, void *Close, void *Read, void *Write, void *Ioctl) + { + dbg_api("%d, %d, %#lx, %#lx, %#lx, %#lx, %#lx", MajorID, Type, Open, Close, Read, Write, Ioctl); + + switch (Type) + { + case ddt_SATA: + { + dev_t ret = DriverManager->BlockSATADev->Register(MajorID); + DriverManager->BlockSATADev->NewBlock(MajorID, ret, + (SlaveDeviceFile::drvOpen_t)Open, + (SlaveDeviceFile::drvClose_t)Close, + (SlaveDeviceFile::drvRead_t)Read, + (SlaveDeviceFile::drvWrite_t)Write, + (SlaveDeviceFile::drvIoctl_t)Ioctl); + return ret; + } + case ddt_ATA: + { + dev_t ret = DriverManager->BlockHDDev->Register(MajorID); + DriverManager->BlockHDDev->NewBlock(MajorID, ret, + (SlaveDeviceFile::drvOpen_t)Open, + (SlaveDeviceFile::drvClose_t)Close, + (SlaveDeviceFile::drvRead_t)Read, + (SlaveDeviceFile::drvWrite_t)Write, + (SlaveDeviceFile::drvIoctl_t)Ioctl); + return ret; + } + case ddt_NVMe: + { + dev_t ret = DriverManager->BlockNVMeDev->Register(MajorID); + DriverManager->BlockNVMeDev->NewBlock(MajorID, ret, + (SlaveDeviceFile::drvOpen_t)Open, + (SlaveDeviceFile::drvClose_t)Close, + (SlaveDeviceFile::drvRead_t)Read, + (SlaveDeviceFile::drvWrite_t)Write, + (SlaveDeviceFile::drvIoctl_t)Ioctl); + return ret; + } + /* ... */ + default: + assert(!"Invalid storage device type"); + } + } + + int UnregisterBlockDevice(dev_t MajorID, dev_t MinorID, DeviceDriverType Type) + { + dbg_api("%d, %d, %d", MajorID, MinorID, Type); + + switch (Type) + { + case ddt_SATA: + return DriverManager->BlockSATADev->Unregister(MajorID, MinorID); + case ddt_ATA: + return DriverManager->BlockHDDev->Unregister(MajorID, MinorID); + case ddt_NVMe: + return DriverManager->BlockNVMeDev->Unregister(MajorID, MinorID); + /* ... */ + default: + assert(!"Invalid storage device type"); + } + } + + /* --------- */ + + dev_t RegisterAudioDevice(dev_t MajorID, DeviceDriverType Type, void *Open, void *Close, void *Read, void *Write, void *Ioctl) + { + dbg_api("%d, %d, %#lx, %#lx, %#lx, %#lx, %#lx", MajorID, Type, Open, Close, Read, Write, Ioctl); + + switch (Type) + { + case ddt_Audio: + { + dev_t ret = DriverManager->AudioDev->Register(MajorID); + DriverManager->AudioDev->NewAudio(MajorID, ret, + (SlaveDeviceFile::drvOpen_t)Open, + (SlaveDeviceFile::drvClose_t)Close, + (SlaveDeviceFile::drvRead_t)Read, + (SlaveDeviceFile::drvWrite_t)Write, + (SlaveDeviceFile::drvIoctl_t)Ioctl); + return ret; + } + /* ... */ + default: + assert(!"Invalid audio device type"); + } + } + + int UnregisterAudioDevice(dev_t MajorID, dev_t MinorID, DeviceDriverType Type) + { + dbg_api("%d, %d, %d", MajorID, MinorID, Type); + + switch (Type) + { + case ddt_Audio: + return DriverManager->AudioDev->Unregister(MajorID, MinorID); + /* ... */ + default: + assert(!"Invalid audio device type"); + } + } + + /* --------- */ + + dev_t RegisterNetDevice(dev_t MajorID, DeviceDriverType Type, void *Open, void *Close, void *Read, void *Write, void *Ioctl) + { + dbg_api("%d, %d, %#lx, %#lx, %#lx, %#lx, %#lx", MajorID, Type, Open, Close, Read, Write, Ioctl); + + switch (Type) + { + case ddt_Network: + { + dev_t ret = DriverManager->NetDev->Register(MajorID); + DriverManager->NetDev->NewNet(MajorID, ret, + (SlaveDeviceFile::drvOpen_t)Open, + (SlaveDeviceFile::drvClose_t)Close, + (SlaveDeviceFile::drvRead_t)Read, + (SlaveDeviceFile::drvWrite_t)Write, + (SlaveDeviceFile::drvIoctl_t)Ioctl); + return ret; + } + /* ... */ + default: + assert(!"Invalid audio device type"); + } + } + + int UnregisterNetDevice(dev_t MajorID, dev_t MinorID, DeviceDriverType Type) + { + dbg_api("%d, %d, %d", MajorID, MinorID, Type); + + switch (Type) + { + case ddt_Network: + return DriverManager->NetDev->Unregister(MajorID, MinorID); + /* ... */ + default: + assert(!"Invalid audio device type"); + } + } + + int ReportNetworkPacket(dev_t MajorID, dev_t MinorID, void *Buffer, size_t Size) + { + dbg_api("%d, %d, %#lx, %d", MajorID, MinorID, Buffer, Size); + + return DriverManager->NetDev->ReportNetworkPacket(MajorID, MinorID, Buffer, Size); + } + + /* --------- */ + + void d_KPrint(dev_t MajorID, const char *Format, va_list args) + { + dbg_api("%d %s, %#lx", MajorID, Format, args); + + _KPrint(Format, args); + } + + void KernelLog(dev_t MajorID, const char *Format, va_list args) + { + dbg_api("%d, %s, %#lx", MajorID, Format, args); + + fctprintf(uart_wrapper, nullptr, "DRVER| %ld: ", MajorID); + vfctprintf(uart_wrapper, nullptr, Format, args); + uart_wrapper('\n', nullptr); + } + + /* --------- */ + + void *RequestPages(dev_t MajorID, size_t Pages) + { + dbg_api("%d, %d", MajorID, Pages); + + std::unordered_map &Drivers = + DriverManager->GetDrivers(); + auto itr = Drivers.find(MajorID); + assert(itr != Drivers.end()); + + return itr->second.vma->RequestPages(Pages); + } + + void FreePages(dev_t MajorID, void *Pointer, size_t Pages) + { + dbg_api("%d, %#lx, %d", MajorID, Pointer, Pages); + + std::unordered_map &Drivers = + DriverManager->GetDrivers(); + + auto itr = Drivers.find(MajorID); + assert(itr != Drivers.end()); + + itr->second.vma->FreePages(Pointer, Pages); + } + + /* --------- */ + + void AppendMapFlag(dev_t MajorID, void *Address, PageMapFlags Flag) + { + dbg_api("%d, %#lx, %d", MajorID, Address, Flag); + + Memory::Virtual vmm(KernelPageTable); + vmm.GetPTE(Address)->raw |= Flag; + } + + void RemoveMapFlag(dev_t MajorID, void *Address, PageMapFlags Flag) + { + dbg_api("%d, %#lx, %d", MajorID, Address, Flag); + + Memory::Virtual vmm(KernelPageTable); + vmm.GetPTE(Address)->raw &= ~Flag; + } + + void MapPages(dev_t MajorID, void *PhysicalAddress, void *VirtualAddress, size_t Pages, uint32_t Flags) + { + dbg_api("%d, %#lx, %#lx, %d, %d", MajorID, PhysicalAddress, VirtualAddress, Pages, Flags); + + Memory::Virtual vmm(KernelPageTable); + vmm.Map(VirtualAddress, PhysicalAddress, Pages, Flags); + } + + void UnmapPages(dev_t MajorID, void *VirtualAddress, size_t Pages) + { + dbg_api("%d, %#lx, %d", MajorID, VirtualAddress, Pages); + + Memory::Virtual vmm(KernelPageTable); + vmm.Unmap(VirtualAddress, Pages); + } + + /* --------- */ + + pid_t CreateKernelProcess(dev_t MajorID, const char *Name) + { + dbg_api("%d, %s", MajorID, Name); + + Tasking::PCB *pcb = TaskManager->CreateProcess(nullptr, + Name, Tasking::System, + nullptr, true, 0, 0); + + return pcb->ID; + } + + pid_t CreateKernelThread(dev_t MajorID, pid_t pId, const char *Name, void *EntryPoint, void *Argument) + { + dbg_api("%d, %d, %s, %#lx, %#lx", MajorID, pId, Name, EntryPoint, Argument); + + Tasking::PCB *parent = TaskManager->GetProcessByID(pId); + if (!parent) + return -EINVAL; + + CriticalSection cs; + Tasking::TCB *tcb = TaskManager->CreateThread(parent, (Tasking::IP)EntryPoint); + if (Argument) + tcb->SYSV_ABI_Call((uintptr_t)Argument); + tcb->Rename(Name); + return tcb->ID; + } + + int KillProcess(dev_t MajorID, pid_t pId, int ExitCode) + { + dbg_api("%d, %d, %d", MajorID, pId, ExitCode); + + Tasking::PCB *pcb = TaskManager->GetProcessByID(pId); + if (!pcb) + return -EINVAL; + TaskManager->KillProcess(pcb, (Tasking::KillCode)ExitCode); + return 0; + } + + int KillThread(dev_t MajorID, pid_t tId, int ExitCode) + { + dbg_api("%d, %d, %d", MajorID, tId, ExitCode); + + Tasking::TCB *tcb = TaskManager->GetThreadByID(tId); + if (!tcb) + return -EINVAL; + TaskManager->KillThread(tcb, (Tasking::KillCode)ExitCode); + return 0; + } + + void Yield(dev_t MajorID) + { + dbg_api("%d", MajorID); + + TaskManager->Yield(); + } + + void Sleep(dev_t MajorID, uint64_t Milliseconds) + { + dbg_api("%d, %d", MajorID, Milliseconds); + + TaskManager->Sleep(Milliseconds); + } + + /* --------- */ + + __PCIArray *GetPCIDevices(dev_t MajorID, uint16_t _Vendors[], uint16_t _Devices[]) + { + dbg_api("%d, %#lx, %#lx", MajorID, _Vendors, _Devices); + + std::unordered_map &Drivers = + DriverManager->GetDrivers(); + + auto itr = Drivers.find(MajorID); + if (itr == Drivers.end()) + return nullptr; + + std::list VendorIDs; + for (int i = 0; _Vendors[i] != 0x0; i++) + VendorIDs.push_back(_Vendors[i]); + + std::list DeviceIDs; + for (int i = 0; _Devices[i] != 0x0; i++) + DeviceIDs.push_back(_Devices[i]); + + std::list Devices = PCIManager->FindPCIDevice(VendorIDs, DeviceIDs); + if (Devices.empty()) + return nullptr; + + Memory::VirtualMemoryArea *vma = itr->second.vma; + __PCIArray *head = nullptr; + __PCIArray *array = nullptr; + + foreach (auto &dev in Devices) + { + /* TODO: optimize memory allocation */ + PCI::PCIDevice *dptr = (PCI::PCIDevice *)vma->RequestPages(TO_PAGES(sizeof(PCI::PCIDevice))); + memcpy(dptr, &dev, sizeof(PCI::PCIDevice)); + + __PCIArray *newArray = (__PCIArray *)vma->RequestPages(TO_PAGES(sizeof(__PCIArray))); + + if (unlikely(head == nullptr)) + { + head = newArray; + array = head; + } + else + { + array->Next = newArray; + array = newArray; + } + + array->Device = dptr; + array->Next = nullptr; + + debug("Found %02x.%02x.%02x: %04x:%04x", + dev.Bus, dev.Device, dev.Function, + dev.Header->VendorID, dev.Header->DeviceID); + } + + return head; + } + + void InitializePCI(dev_t MajorID, void *_Header) + { + dbg_api("%d, %#lx", MajorID, _Header); + + PCI::PCIDeviceHeader *Header = (PCI::PCIDeviceHeader *)_Header; + + debug("Header Type: %d", Header->HeaderType); + switch (Header->HeaderType) + { + case 128: + warn("Unknown header type %d! Guessing PCI Header 0", + Header->HeaderType); + [[fallthrough]]; + case 0: /* PCI Header 0 */ + { + PCI::PCIHeader0 *hdr0 = (PCI::PCIHeader0 *)Header; + + uint32_t BAR[6]; + size_t BARsSize[6]; + + BAR[0] = hdr0->BAR0; + BAR[1] = hdr0->BAR1; + BAR[2] = hdr0->BAR2; + BAR[3] = hdr0->BAR3; + BAR[4] = hdr0->BAR4; + BAR[5] = hdr0->BAR5; + + debug("Type: %d; IOBase: %#lx; MemoryBase: %#lx", + BAR[0] & 1, BAR[1] & (~3), BAR[0] & (~15)); + + /* BARs Size */ + for (short i = 0; i < 6; i++) + { + if (BAR[i] == 0) + continue; + + size_t size; + if ((BAR[i] & 1) == 0) /* Memory Base */ + { + hdr0->BAR0 = 0xFFFFFFFF; + size = hdr0->BAR0; + hdr0->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 */ + { + hdr0->BAR1 = 0xFFFFFFFF; + size = hdr0->BAR1; + hdr0->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]); + } + } + + Memory::Virtual vmm(KernelPageTable); + + /* 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); + + if (BARSize == 0) + { + warn("BAR%d size is zero!", i); + BARSize++; + } + + vmm.Map((void *)BARBase, (void *)BARBase, + BARSize, Memory::RW | Memory::PWT | Memory::PCD); + } + 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); + + if (BARSize == 0) + { + warn("BAR%d size is zero!", i); + BARSize++; + } + + vmm.Map((void *)BARBase, (void *)BARBase, + BARSize, Memory::RW | Memory::PWT | Memory::PCD); + } + } + 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", Header->HeaderType); + break; + } + } + + Header->Command |= PCI_COMMAND_MASTER | + PCI_COMMAND_IO | + PCI_COMMAND_MEMORY; + Header->Command &= ~PCI_COMMAND_INTX_DISABLE; + } + + uint32_t GetBAR(dev_t MajorID, uint8_t i, void *_Header) + { + dbg_api("%d, %d, %#lx", MajorID, i, _Header); + + PCI::PCIDeviceHeader *Header = (PCI::PCIDeviceHeader *)_Header; + + switch (Header->HeaderType) + { + case 128: + warn("Unknown header type %d! Guessing PCI Header 0", + Header->HeaderType); + [[fallthrough]]; + case 0: /* PCI Header 0 */ + { + PCI::PCIHeader0 *hdr0 = + (PCI::PCIHeader0 *)Header; + switch (i) + { + case 0: + return hdr0->BAR0; + case 1: + return hdr0->BAR1; + case 2: + return hdr0->BAR2; + case 3: + return hdr0->BAR3; + case 4: + return hdr0->BAR4; + case 5: + return hdr0->BAR5; + default: + assert(!"Invalid BAR index"); + } + } + case 1: /* PCI Header 1 (PCI-to-PCI Bridge) */ + { + PCI::PCIHeader1 *hdr1 = + (PCI::PCIHeader1 *)Header; + switch (i) + { + case 0: + return hdr1->BAR0; + case 1: + return hdr1->BAR1; + default: + assert(!"Invalid BAR index"); + } + } + case 2: /* PCI Header 2 (PCI-to-CardBus Bridge) */ + { + assert(!"PCI-to-CardBus Bridge not supported"); + } + default: + assert(!"Invalid PCI header type"); + } + } + + /* --------- */ + + void *api__memcpy(dev_t MajorID, void *Destination, const void *Source, size_t Length) + { + dbg_api("%d, %#lx, %#lx, %d", MajorID, Destination, Source, Length); + + return memcpy(Destination, Source, Length); + } + + void *api__memset(dev_t MajorID, void *Destination, int Value, size_t Length) + { + dbg_api("%d, %#lx, %d, %d", MajorID, Destination, Value, Length); + + return memset(Destination, Value, Length); + } + + void *api__memmove(dev_t MajorID, void *Destination, const void *Source, size_t Length) + { + dbg_api("%d, %#lx, %#lx, %d", MajorID, Destination, Source, Length); + + return memmove(Destination, Source, Length); + } + + int api__memcmp(dev_t MajorID, const void *Left, const void *Right, size_t Length) + { + dbg_api("%d, %#lx, %#lx, %d", MajorID, Left, Right, Length); + + return memcmp(Left, Right, Length); + } + + size_t api__strlen(dev_t MajorID, const char *String) + { + dbg_api("%d, %s", MajorID, String); + + return strlen(String); + } + + char *api__strcpy(dev_t MajorID, char *Destination, const char *Source) + { + dbg_api("%d, %#lx, %s", MajorID, Destination, Source); + + return strcpy(Destination, Source); + } + + char *api__strcat(dev_t MajorID, char *Destination, const char *Source) + { + dbg_api("%d, %#lx, %s", MajorID, Destination, Source); + + return strcat(Destination, Source); + } + + int api__strcmp(dev_t MajorID, const char *Left, const char *Right) + { + dbg_api("%d, %s, %s", MajorID, Left, Right); + + return strcmp(Left, Right); + } + + int api__strncmp(dev_t MajorID, const char *Left, const char *Right, size_t Length) + { + dbg_api("%d, %s, %s, %d", MajorID, Left, Right, Length); + + return strncmp(Left, Right, Length); + } + + char *api__strchr(dev_t MajorID, const char *String, int Character) + { + dbg_api("%d, %s, %d", MajorID, String, Character); + + return strchr(String, Character); + } + + char *api__strrchr(dev_t MajorID, const char *String, int Character) + { + dbg_api("%d, %s, %d", MajorID, String, Character); + + stub; + return nullptr; + // return strrchr(String, Character); + } + + char *api__strstr(dev_t MajorID, const char *Haystack, const char *Needle) + { + dbg_api("%d, %s, %s", MajorID, Haystack, Needle); + + return strstr(Haystack, Needle); + } + + /* --------- */ + + void PopulateDriverAPI(void *API) + { + __driverAPI *api = (__driverAPI *)API; + + api->RegisterFunction = RegisterFunction; + api->GetDriverInfo = GetDriverInfo; + + api->RegisterInterruptHandler = RegisterInterruptHandler; + api->OverrideInterruptHandler = OverrideInterruptHandler; + api->UnregisterInterruptHandler = UnregisterInterruptHandler; + api->UnregisterAllInterruptHandlers = UnregisterAllInterruptHandlers; + + api->RegisterInputDevice = RegisterInputDevice; + api->UnregisterInputDevice = UnregisterInputDevice; + api->ReportKeyboardEvent = ReportKeyboardEvent; + api->ReportRelativeMouseEvent = ReportRelativeMouseEvent; + api->ReportAbsoluteMouseEvent = ReportAbsoluteMouseEvent; + + api->RegisterBlockDevice = RegisterBlockDevice; + api->UnregisterBlockDevice = UnregisterBlockDevice; + + api->RegisterAudioDevice = RegisterAudioDevice; + api->UnregisterAudioDevice = UnregisterAudioDevice; + + api->RegisterNetDevice = RegisterNetDevice; + api->UnregisterNetDevice = UnregisterNetDevice; + api->ReportNetworkPacket = ReportNetworkPacket; + + api->KPrint = d_KPrint; + api->KernelLog = KernelLog; + + api->RequestPages = RequestPages; + api->FreePages = FreePages; + + api->AppendMapFlag = AppendMapFlag; + api->RemoveMapFlag = RemoveMapFlag; + api->MapPages = MapPages; + api->UnmapPages = UnmapPages; + + api->CreateKernelProcess = CreateKernelProcess; + api->CreateKernelThread = CreateKernelThread; + api->KillProcess = KillProcess; + api->KillThread = KillThread; + api->Yield = Yield; + api->Sleep = Sleep; + + api->GetPCIDevices = GetPCIDevices; + api->InitializePCI = InitializePCI; + api->GetBAR = GetBAR; + + api->memcpy = api__memcpy; + api->memset = api__memset; + api->memmove = api__memmove; + api->memcmp = api__memcmp; + api->strlen = api__strlen; + api->strcpy = api__strcpy; + api->strcat = api__strcat; + api->strcmp = api__strcmp; + api->strncmp = api__strncmp; + api->strchr = api__strchr; + api->strrchr = api__strrchr; + api->strstr = api__strstr; + } +} diff --git a/core/driver/devfile/master.cpp b/core/driver/devfile/master.cpp new file mode 100644 index 0000000..19138fc --- /dev/null +++ b/core/driver/devfile/master.cpp @@ -0,0 +1,325 @@ +/* + 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 "../../../driver.h" + +using namespace vfs; + +namespace Driver +{ + int MasterDeviceFile::open(int Flags, mode_t Mode) + { + switch (this->DeviceType) + { + default: + if (this->SlavesMap.empty()) + return -ENOSYS; + Slaves slave = this->SlavesMap.begin()->second; + return slave->begin()->second->open(Flags, Mode); + } + } + + int MasterDeviceFile::close() + { + switch (this->DeviceType) + { + default: + if (this->SlavesMap.empty()) + return -ENOSYS; + Slaves slave = this->SlavesMap.begin()->second; + return slave->begin()->second->close(); + } + } + + size_t MasterDeviceFile::read(uint8_t *Buffer, + size_t Size, + off_t Offset) + { + switch (this->DeviceType) + { + case ddt_Keyboard: + { + while (KeyQueue.empty()) + TaskManager->Yield(); + + /* Request scancode */ + if (Size == 2 && Buffer[1] == 0x00) + { + if (RawKeyQueue.empty()) + return 0; + + Buffer[0] = RawKeyQueue.front(); + RawKeyQueue.pop_front(); + return 1; + } + + Buffer[0] = KeyQueue.front(); + KeyQueue.pop_front(); + return 1; + } + default: + if (this->SlavesMap.empty()) + return 0; + Slaves slave = this->SlavesMap.begin()->second; + return slave->begin()->second->read(Buffer, Size, Offset); + } + } + + size_t MasterDeviceFile::write(uint8_t *Buffer, + size_t Size, + off_t Offset) + { + switch (this->DeviceType) + { + default: + if (this->SlavesMap.empty()) + return 0; + Slaves slave = this->SlavesMap.begin()->second; + return slave->begin()->second->write(Buffer, Size, Offset); + } + } + + int MasterDeviceFile::ioctl(unsigned long Request, + void *Argp) + { + switch (this->DeviceType) + { + default: + if (this->SlavesMap.empty()) + return -ENOSYS; + Slaves slave = this->SlavesMap.begin()->second; + return slave->begin()->second->ioctl(Request, Argp); + } + } + + void MasterDeviceFile::ClearBuffers() + { + this->RawKeyQueue.clear(); + this->KeyQueue.clear(); + /* ... */ + + foreach (auto &sm in this->SlavesMap) + { + Slaves slave = sm.second; + foreach (auto &sdf in *slave) + sdf.second->ClearBuffers(); + } + } + + int MasterDeviceFile::ReportKeyEvent(maj_t ID, min_t MinorID, uint8_t ScanCode) + { + debug("New key event: %02x", ScanCode); + if (this->SlavesMap.find(ID) == this->SlavesMap.end()) + return -EINVAL; + + std::unordered_map *slave = this->SlavesMap[ID]; + if ((*slave).find(MinorID) == (*slave).end()) + return -EINVAL; + + /* We are master, keep a copy of the scancode and + converted key */ + + if (RawKeyQueue.size() > 16) + RawKeyQueue.pop_front(); + RawKeyQueue.push_back(ScanCode); + + if (KeyQueue.size() > 16) + KeyQueue.pop_front(); + + switch (ScanCode & ~KEY_PRESSED) + { + case KEY_LEFT_SHIFT: + case KEY_RIGHT_SHIFT: + { + if (ScanCode & KEY_PRESSED) + UpperCase = true; + else + UpperCase = false; + break; + } + case KEY_CAPS_LOCK: + { + if (ScanCode & KEY_PRESSED) + CapsLock = !CapsLock; + break; + } + default: + break; + } + KeyQueue.push_back(GetScanCode(ScanCode, UpperCase || CapsLock)); + + SlaveDeviceFile *sdf = (*slave)[MinorID]; + return sdf->ReportKeyEvent(ScanCode); + } + + int MasterDeviceFile::ReportMouseEvent(maj_t ID, min_t MinorID, + bool LeftButton, bool RightButton, bool MiddleButton, + bool Button4, bool Button5, bool Button6, bool Button7, bool Button8, + uintptr_t X, uintptr_t Y, int8_t Z, bool Relative) + { + return -ENOSYS; + } + + int MasterDeviceFile::ReportNetworkPacket(maj_t ID, min_t MinorID, void *Buffer, size_t Size) + { + /* TODO: Buffer must be allocated by the kernel */ + return -ENOSYS; + } + + int MasterDeviceFile::NewBlock(maj_t ID, min_t MinorID, drvOpen_t Open, drvClose_t Close, + drvRead_t Read, drvWrite_t Write, drvIoctl_t Ioctl) + { + assert(this->SlavesMap.find(ID) != this->SlavesMap.end()); + Slaves slave = this->SlavesMap[ID]; + assert((*slave).find(MinorID) != (*slave).end()); + SlaveDeviceFile *sdf = (*slave)[MinorID]; + sdf->Open = Open; + sdf->Close = Close; + sdf->Read = Read; + sdf->Write = Write; + sdf->Ioctl = Ioctl; + return 0; + } + + int MasterDeviceFile::NewAudio(maj_t ID, min_t MinorID, drvOpen_t Open, drvClose_t Close, + drvRead_t Read, drvWrite_t Write, drvIoctl_t Ioctl) + { + assert(this->SlavesMap.find(ID) != this->SlavesMap.end()); + Slaves slave = this->SlavesMap[ID]; + assert((*slave).find(MinorID) != (*slave).end()); + SlaveDeviceFile *sdf = (*slave)[MinorID]; + sdf->Open = Open; + sdf->Close = Close; + sdf->Read = Read; + sdf->Write = Write; + sdf->Ioctl = Ioctl; + return 0; + } + + int MasterDeviceFile::NewNet(maj_t ID, min_t MinorID, drvOpen_t Open, drvClose_t Close, + drvRead_t Read, drvWrite_t Write, drvIoctl_t Ioctl) + { + assert(this->SlavesMap.find(ID) != this->SlavesMap.end()); + Slaves slave = this->SlavesMap[ID]; + assert((*slave).find(MinorID) != (*slave).end()); + SlaveDeviceFile *sdf = (*slave)[MinorID]; + sdf->Open = Open; + sdf->Close = Close; + sdf->Read = Read; + sdf->Write = Write; + sdf->Ioctl = Ioctl; + return 0; + } + + dev_t MasterDeviceFile::Register(maj_t ID) + { + debug("Registering slave device %d", ID); + Slaves slave; + if (this->SlavesMap.find(ID) != this->SlavesMap.end()) + slave = this->SlavesMap[ID]; + else + slave = new std::unordered_map(); + + char name[24]; + sprintf(name, "%s%ld", this->SlaveName, this->SlaveIDCounter); + SlaveDeviceFile *sdf = new SlaveDeviceFile(name, + this->SlaveParent, + this->DeviceType, + this->Type); + + sdf->DeviceMajor = ID; + sdf->DeviceMinor = this->SlaveIDCounter; + + (*slave)[this->SlaveIDCounter] = sdf; + this->SlavesMap[ID] = slave; + return this->SlaveIDCounter++; + } + + int MasterDeviceFile::Unregister(maj_t ID, min_t MinorID) + { + debug("Unregistering slave device %d:%d", ID, MinorID); + if (this->SlavesMap.find(ID) == this->SlavesMap.end()) + return -EINVAL; + + std::unordered_map *slave = this->SlavesMap[ID]; + if ((*slave).find(MinorID) == (*slave).end()) + return -EINVAL; + + SlaveDeviceFile *sdf = (*slave)[MinorID]; + delete sdf; + slave->erase(MinorID); + if (slave->empty()) + { + delete slave; + this->SlavesMap.erase(ID); + } + return 0; + } + + MasterDeviceFile::MasterDeviceFile(const char *MasterName, + const char *_SlaveName, + Node *Parent, + int Type) + : Node(Parent, MasterName, NodeType::FILE) + { + strncpy(this->SlaveName, _SlaveName, sizeof(this->Name)); + this->DeviceType = Type; + this->SlaveParent = Parent; + + switch (Type) + { + case ddt_Keyboard: + case ddt_Mouse: + case ddt_Joystick: + case ddt_Gamepad: + case ddt_Touchpad: + case ddt_Touchscreen: + this->Type = NodeType::CHARDEVICE; + break; + case ddt_SATA: + case ddt_ATA: + case ddt_NVMe: + this->Type = NodeType::BLOCKDEVICE; + break; + default: + break; + } + } + + MasterDeviceFile::~MasterDeviceFile() + { + foreach (auto &sm in this->SlavesMap) + { + Slaves slave = sm.second; + foreach (auto &sdf in *slave) + delete sdf.second; + delete slave; + } + this->SlavesMap.clear(); + } +} diff --git a/core/driver/devfile/slave.cpp b/core/driver/devfile/slave.cpp new file mode 100644 index 0000000..f1e79db --- /dev/null +++ b/core/driver/devfile/slave.cpp @@ -0,0 +1,131 @@ +/* + 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 "../../../driver.h" + +using namespace vfs; + +namespace Driver +{ + int SlaveDeviceFile::open(int Flags, mode_t Mode) + { + switch (this->DeviceType) + { + default: + if (this->Open) + return this->Open(this->DeviceMajor, this->DeviceMinor, + Flags, Mode); + return -ENOSYS; + } + } + + int SlaveDeviceFile::close() + { + switch (this->DeviceType) + { + default: + if (this->Close) + return this->Close(this->DeviceMajor, this->DeviceMinor); + return -ENOSYS; + } + } + + size_t SlaveDeviceFile::read(uint8_t *Buffer, + size_t Size, + off_t Offset) + { + switch (this->DeviceType) + { + case ddt_Keyboard: + { + while (KeyQueue.empty()) + TaskManager->Yield(); + + Buffer[0] = KeyQueue.front(); + KeyQueue.pop_front(); + return 1; + } + default: + if (this->Read) + return this->Read(this->DeviceMajor, this->DeviceMinor, + Buffer, Size, Offset); + return 0; + } + } + + size_t SlaveDeviceFile::write(uint8_t *Buffer, + size_t Size, + off_t Offset) + { + switch (this->DeviceType) + { + default: + if (this->Write) + return this->Write(this->DeviceMajor, this->DeviceMinor, + Buffer, Size, Offset); + return 0; + } + } + + int SlaveDeviceFile::ioctl(unsigned long Request, + void *Argp) + { + switch (this->DeviceType) + { + default: + if (this->Ioctl) + return this->Ioctl(this->DeviceMajor, this->DeviceMinor, + Request, Argp); + return -ENOSYS; + } + } + + void SlaveDeviceFile::ClearBuffers() + { + KeyQueue.clear(); + /* ... */ + } + + int SlaveDeviceFile::ReportKeyEvent(uint8_t ScanCode) + { + if (KeyQueue.size() > 16) + KeyQueue.pop_front(); + KeyQueue.push_back(ScanCode); + return 0; + } + + SlaveDeviceFile::SlaveDeviceFile(const char *Name, vfs::Node *Parent, int Type, vfs::NodeType NType) + : Node(Parent, Name, NType) + { + this->DeviceType = Type; + } + + SlaveDeviceFile::~SlaveDeviceFile() + { + } +} diff --git a/core/driver/driver.cpp b/core/driver/driver.cpp new file mode 100644 index 0000000..32b819d --- /dev/null +++ b/core/driver/driver.cpp @@ -0,0 +1,582 @@ +/* + 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 "../../driver.h" + +using namespace vfs; + +namespace Driver +{ + void Manager::LoadAllDrivers() + { + foreach (auto &var in Drivers) + { + DriverObject *Drv = &var.second; + size_t dapiPgs = TO_PAGES(sizeof(__driverAPI)); + __driverAPI *dApi = (__driverAPI *)Drv->vma->RequestPages(dapiPgs); + debug("Driver API at %#lx-%#lx", dApi, dApi + sizeof(__driverAPI)); + + fixme("api version"); + dApi->APIVersion.Major = 0; + dApi->APIVersion.Minor = 0; + dApi->APIVersion.Patch = 0; + + dApi->MajorID = var.first; + dApi->Base = Drv->BaseAddress; + PopulateDriverAPI(dApi); + + debug("Calling driver %s at %#lx", Drv->Path, Drv->EntryPoint); + int (*DrvInit)(__driverAPI *) = (int (*)(__driverAPI *))Drv->EntryPoint; + Drv->ErrorCode = DrvInit(dApi); + if (Drv->ErrorCode < 0) + { + KPrint("FATAL: _start() failed for %s: %s", + Drv->Name, strerror(Drv->ErrorCode)); + error("Failed to load driver %s: %s", + Drv->Path, strerror(Drv->ErrorCode)); + + Drv->vma->FreeAllPages(); + continue; + } + + KPrint("Loading driver %s", Drv->Name); + + debug("Calling Probe()=%#lx on driver %s", + Drv->Probe, Drv->Path); + Drv->ErrorCode = Drv->Probe(); + if (Drv->ErrorCode < 0) + { + KPrint("Probe() failed for %s: %s", + Drv->Name, strerror(Drv->ErrorCode)); + error("Failed to probe driver %s: %s", + Drv->Path, strerror(Drv->ErrorCode)); + + Drv->vma->FreeAllPages(); + continue; + } + + debug("Calling driver Entry()=%#lx function on driver %s", + Drv->Entry, Drv->Path); + Drv->ErrorCode = Drv->Entry(); + if (Drv->ErrorCode < 0) + { + KPrint("Entry() failed for %s: %s", + Drv->Name, strerror(Drv->ErrorCode)); + error("Failed to initialize driver %s: %s", + Drv->Path, strerror(Drv->ErrorCode)); + + Drv->vma->FreeAllPages(); + continue; + } + + debug("Loaded driver %s", Drv->Path); + Drv->Initialized = true; + } + + InputMouseDev->ClearBuffers(); + InputKeyboardDev->ClearBuffers(); + + BlockSATADev->ClearBuffers(); + BlockHDDev->ClearBuffers(); + BlockNVMeDev->ClearBuffers(); + + AudioDev->ClearBuffers(); + + NetDev->ClearBuffers(); + /* ... */ + } + + void Manager::UnloadAllDrivers() + { + foreach (auto &var in Drivers) + { + DriverObject *Drv = &var.second; + if (!Drv->Initialized) + continue; + + debug("Unloading driver %s", Drv->Name); + int err = Drv->Final(); + if (err < 0) + { + warn("Failed to unload driver %s: %s", + Drv->Name, strerror(err)); + } + + if (!Drv->InterruptHandlers->empty()) + { + foreach (auto &rInt in * Drv->InterruptHandlers) + { + Interrupts::RemoveHandler((void (*)(CPU::TrapFrame *))rInt.second); + } + Drv->InterruptHandlers->clear(); + } + + delete Drv->vma, Drv->vma = nullptr; + delete Drv->InterruptHandlers, Drv->InterruptHandlers = nullptr; + } + Drivers.clear(); + } + + void Manager::Panic() + { + Memory::Virtual vmm; + foreach (auto Driver in Drivers) + { + if (!Driver.second.Initialized) + continue; + + trace("Panic on driver %s", Driver.second.Name); + debug("%#lx", Driver.second.Panic); + + /* Crash while probing? */ + if (Driver.second.Panic && vmm.Check((void *)Driver.second.Panic)) + Driver.second.Panic(); + else + error("No panic function for driver %s", + Driver.second.Name); + } + } + + int Manager::LoadDriverFile(uintptr_t &EntryPoint, + uintptr_t &BaseAddress, + Memory::VirtualMemoryArea *dVma, + RefNode *rDrv) + { + Elf64_Ehdr ELFHeader; + rDrv->seek(0, SEEK_SET); + rDrv->read((uint8_t *)&ELFHeader, sizeof(Elf64_Ehdr)); + if (ELFHeader.e_type != ET_DYN) + { + error("Driver %s is not a shared object", rDrv->node->FullPath); + return -ENOEXEC; + } + + trace("Loading driver %s in memory", rDrv->node->Name); + + BaseAddress = 0; + { + Elf64_Phdr ProgramBreakHeader{}; + Elf64_Phdr ProgramHeader; + + size_t SegmentsSize = 0; + for (Elf64_Half i = 0; i < ELFHeader.e_phnum; i++) + { + rDrv->seek(ELFHeader.e_phoff + (i * sizeof(Elf64_Phdr)), SEEK_SET); + rDrv->read((uint8_t *)&ProgramHeader, sizeof(Elf64_Phdr)); + + if (ProgramHeader.p_type == PT_LOAD || + ProgramHeader.p_type == PT_DYNAMIC) + { + if (SegmentsSize < ProgramHeader.p_vaddr + ProgramHeader.p_memsz) + { + SegmentsSize = ProgramHeader.p_vaddr + ProgramHeader.p_memsz; + ProgramBreakHeader = ProgramHeader; + } + } + } + debug("SegmentsSize: %#lx", SegmentsSize); + + /* TODO: Check if this is correct and/or it needs more + complex calculations & allocations */ + void *SegmentsAddress = dVma->RequestPages(TO_PAGES(SegmentsSize) + 1, true); + BaseAddress = (uintptr_t)SegmentsAddress; + debug("BaseAddress: %#lx, End: %#lx (%#lx)", BaseAddress, + BaseAddress + FROM_PAGES(TO_PAGES(SegmentsSize)), + SegmentsSize); + + for (Elf64_Half i = 0; i < ELFHeader.e_phnum; i++) + { + rDrv->seek(ELFHeader.e_phoff + (i * sizeof(Elf64_Phdr)), SEEK_SET); + rDrv->read((uint8_t *)&ProgramHeader, sizeof(Elf64_Phdr)); + + switch (ProgramHeader.p_type) + { + case PT_LOAD: + { + /* Because this is ET_DYN, we can load the segments + anywhere we want. */ + uintptr_t SegmentDestination = BaseAddress + ProgramHeader.p_vaddr; + + if (ProgramHeader.p_memsz == 0) + continue; + + debug("Copying PT_LOAD to %#lx-%#lx (%ld file bytes, %ld mem bytes)", + SegmentDestination, SegmentDestination + ProgramHeader.p_memsz, + ProgramHeader.p_filesz, ProgramHeader.p_memsz); + + if (ProgramHeader.p_filesz > 0) + { + rDrv->seek(ProgramHeader.p_offset, SEEK_SET); + rDrv->read((uint8_t *)SegmentDestination, ProgramHeader.p_filesz); + } + + if (ProgramHeader.p_memsz - ProgramHeader.p_filesz > 0) + { + void *zAddr = (void *)(SegmentDestination + ProgramHeader.p_filesz); + memset(zAddr, 0, ProgramHeader.p_memsz - ProgramHeader.p_filesz); + } + break; + } + case PT_DYNAMIC: + { + /* PT_DYNAMIC contains the dynamic linking information for the + executable or shared library. */ + + uintptr_t DynamicSegmentDestination = BaseAddress + ProgramHeader.p_vaddr; + + if (ProgramHeader.p_memsz == 0) + continue; + + debug("Copying PT_DYNAMIC to %#lx-%#lx (%ld file bytes, %ld mem bytes)", + DynamicSegmentDestination, DynamicSegmentDestination + ProgramHeader.p_memsz, + ProgramHeader.p_filesz, ProgramHeader.p_memsz); + + if (ProgramHeader.p_filesz > 0) + { + rDrv->seek(ProgramHeader.p_offset, SEEK_SET); + rDrv->read((uint8_t *)DynamicSegmentDestination, ProgramHeader.p_filesz); + } + + if (ProgramHeader.p_memsz - ProgramHeader.p_filesz > 0) + { + void *zAddr = (void *)(DynamicSegmentDestination + ProgramHeader.p_filesz); + memset(zAddr, 0, ProgramHeader.p_memsz - ProgramHeader.p_filesz); + } + break; + } + default: + { + fixme("Unhandled program header type: %#lx", + ProgramHeader.p_type); + break; + } + } + } + } + + Elf64_Phdr ProgramHeader; + for (Elf64_Half i = 0; i < ELFHeader.e_phnum; i++) + { + rDrv->seek(ELFHeader.e_phoff + (i * sizeof(Elf64_Phdr)), SEEK_SET); + rDrv->read((uint8_t *)&ProgramHeader, sizeof(Elf64_Phdr)); + + if (ProgramHeader.p_type == PT_DYNAMIC) + { + Elf64_Dyn *Dynamic = (Elf64_Dyn *)(BaseAddress + ProgramHeader.p_vaddr); + Elf64_Dyn *RelaSize = nullptr; + Elf64_Dyn *PltRelSize = nullptr; + + while (Dynamic->d_tag != DT_NULL) + { + switch (Dynamic->d_tag) + { + case DT_RELASZ: + RelaSize = Dynamic; + debug("RELA Size: %d", RelaSize->d_un.d_val / sizeof(Elf64_Rela)); + + break; + case DT_PLTRELSZ: + PltRelSize = Dynamic; + debug("PLTRELSZ: %d", PltRelSize->d_un.d_val / sizeof(Elf64_Rela)); + + break; + default: + break; + } + + Dynamic++; + } + Dynamic = (Elf64_Dyn *)(BaseAddress + ProgramHeader.p_vaddr); + + while (Dynamic->d_tag != DT_NULL) + { + switch (Dynamic->d_tag) + { + case DT_RELA: /* .rela.dyn */ + { + if (!RelaSize) + { + error("DT_RELASZ is not set"); + break; + } + + Elf64_Rela *Rela = (Elf64_Rela *)(BaseAddress + Dynamic->d_un.d_ptr); + for (size_t i = 0; i < (RelaSize->d_un.d_val / sizeof(Elf64_Rela)); i++) + { + Elf64_Rela *r = &Rela[i]; + uintptr_t *RelocationAddress = (uintptr_t *)(BaseAddress + r->r_offset); + uintptr_t RelocationTarget = 0; + + switch (ELF64_R_TYPE(r->r_info)) + { + case R_X86_64_GLOB_DAT: + case R_X86_64_JUMP_SLOT: + { + RelocationTarget = BaseAddress; + break; + } + case R_X86_64_RELATIVE: + case R_X86_64_64: + { + RelocationTarget = BaseAddress + r->r_addend; + break; + } + default: + { + fixme("Unhandled relocation type: %#lx", + ELF64_R_TYPE(r->r_info)); + break; + } + } + + *RelocationAddress = RelocationTarget; + + debug("Relocated %#lx to %#lx", + r->r_offset, *RelocationAddress); + } + break; + } + case DT_PLTREL: + { + if (Dynamic->d_un.d_val != DT_RELA) + error("DT_PLTREL is not DT_RELA"); + break; + } + case DT_JMPREL: /* .rela.plt */ + { + if (!PltRelSize) + { + error("DT_PLTRELSZ is not set"); + break; + } + + int fd = fopen(rDrv->node->FullPath, "r"); + + std::vector SymTab = Execute::ELFGetDynamicTag_x86_64(fd, DT_SYMTAB); + std::vector StrTab = Execute::ELFGetDynamicTag_x86_64(fd, DT_STRTAB); + Elf64_Sym *_SymTab = (Elf64_Sym *)((uintptr_t)BaseAddress + SymTab[0].d_un.d_ptr); + char *DynStr = (char *)((uintptr_t)BaseAddress + StrTab[0].d_un.d_ptr); + UNUSED(DynStr); + fclose(fd); + + Elf64_Rela *Rela = (Elf64_Rela *)(BaseAddress + Dynamic->d_un.d_ptr); + for (size_t i = 0; i < (PltRelSize->d_un.d_val / sizeof(Elf64_Rela)); i++) + { + Elf64_Rela *r = &Rela[i]; + uintptr_t *RelocationAddress = (uintptr_t *)(BaseAddress + r->r_offset); + uintptr_t RelocationTarget = 0; + + switch (ELF64_R_TYPE(r->r_info)) + { + case R_X86_64_JUMP_SLOT: + { + Elf64_Xword SymIndex = ELF64_R_SYM(r->r_info); + Elf64_Sym *Sym = _SymTab + SymIndex; + +#ifdef DEBUG + const char *SymbolName = DynStr + Sym->st_name; + debug("Symbol %s at %#lx", SymbolName, Sym->st_value); +#endif + + RelocationTarget = BaseAddress + Sym->st_value; + break; + } + default: + { + fixme("Unhandled relocation type: %#lx", + ELF64_R_TYPE(r->r_info)); + break; + } + } + + *RelocationAddress = RelocationTarget; + + debug("Relocated %#lx to %#lx", + r->r_offset, *RelocationAddress); + } + break; + } + case DT_SYMTAB: + { + fixme("DT_SYMTAB"); + break; + int fd = fopen(rDrv->node->FullPath, "r"); + + std::vector SymTab = Execute::ELFGetDynamicTag_x86_64(fd, DT_SYMTAB); + std::vector StrTab = Execute::ELFGetDynamicTag_x86_64(fd, DT_STRTAB); + Elf64_Sym *_SymTab = (Elf64_Sym *)((uintptr_t)BaseAddress + SymTab[0].d_un.d_ptr); + char *DynStr = (char *)((uintptr_t)BaseAddress + StrTab[0].d_un.d_ptr); + UNUSED(DynStr); + fclose(fd); + + size_t symtabEntrySize = 0; + Elf64_Dyn *entrySizeDyn = Dynamic; + while (entrySizeDyn->d_tag != DT_NULL) + { + if (entrySizeDyn->d_tag == DT_SYMENT) + { + symtabEntrySize = entrySizeDyn->d_un.d_val; + break; + } + entrySizeDyn++; + } + + if (symtabEntrySize == 0) + { + fixme("No information about symbol entry size"); + break; + } + + size_t numSymbols = Dynamic->d_un.d_val / symtabEntrySize; + + for (size_t i = 0; i < numSymbols; i++) + { + Elf64_Sym *s = &_SymTab[i]; + if (s->st_name == 0) + continue; + +#ifdef DEBUG + const char *SymbolName = (const char *)(DynStr + s->st_name); + debug("%d: Symbol %s at %#lx", i, SymbolName, s->st_value); +#endif + /** TODO: search for symbols and link */ + /** good use but it will not work only + * if we specify to default visibility but + * this will create more issues :/ */ + // if (strcmp(SymbolName, "DriverProbe") == 0) + // { + // Drivers[MajorIDCounter].Probe = (int (*)())(BaseAddress + s->st_value); + // debug("Found probe function at %#lx", Drivers[MajorIDCounter].Probe); + // } + } + break; + } + default: + { + fixme("Unhandled dynamic tag: %#lx", + Dynamic->d_tag); + break; + } + } + Dynamic++; + } + } + } + + EntryPoint = ELFHeader.e_entry; + EntryPoint += BaseAddress; + + debug("Driver %s has entry point %#lx and base %#lx", + rDrv->node->FullPath, EntryPoint, BaseAddress); + + /* FIXME: Do not add to the KernelSymbolTable! */ + // Memory::SmartHeap sh(rDrv->Size); + // rDrv->seek(0, SEEK_SET); + // rDrv->read((uint8_t *)sh.Get(), rDrv->Size); + // KernelSymbolTable->AppendSymbols((uintptr_t)sh.Get(), BaseAddress); + return 0; + } + + Manager::Manager() + { + debug("Initializing driver manager"); + const char *DriverDirectory = Config.DriverDirectory; + RefNode *rn = fs->Open(DriverDirectory); + if (!rn) + { + error("Failed to open driver directory %s", DriverDirectory); + KPrint("Failed to open driver directory %s", DriverDirectory); + return; + } + + foreach (auto drvNode in rn->node->Children) + { + if (drvNode->Type != vfs::FILE) + continue; + + if (Execute::GetBinaryType(drvNode->FullPath) != Execute::BinTypeELF) + { + error("Driver %s is not an ELF binary", drvNode->FullPath); + continue; + } + + RefNode *rDrv = drvNode->CreateReference(); + + Memory::VirtualMemoryArea *dVma = + new Memory::VirtualMemoryArea(thisProcess->PageTable); + + uintptr_t EntryPoint, BaseAddress; + int err = this->LoadDriverFile(EntryPoint, BaseAddress, dVma, rDrv); + debug("err = %d (%s)", err, strerror(err)); + if (err != 0) + { + error("Failed to load driver %s: %s", + drvNode->FullPath, strerror(err)); + + delete rDrv; + delete dVma; + continue; + } + delete rDrv; + + Drivers[MajorIDCounter++] = { + .BaseAddress = BaseAddress, + .EntryPoint = EntryPoint, + .vma = dVma, + .Path = drvNode->FullPath, + .InterruptHandlers = new std::unordered_map}; + + dev_t countr = MajorIDCounter - 1; + const char *drvName; + size_t drvNameLen; + cwk_path_get_basename(drvNode->FullPath, &drvName, &drvNameLen); + strncpy(Drivers[countr].Name, drvName, sizeof(Drivers[countr].Name)); + } + + delete rn; + + InputMouseDev = new MasterDeviceFile("mice", "mouse", DevFS, ddt_Mouse); + InputKeyboardDev = new MasterDeviceFile("key", "kbd", DevFS, ddt_Keyboard); + + BlockSATADev = new MasterDeviceFile("sd", "sd", DevFS, ddt_SATA); + BlockHDDev = new MasterDeviceFile("hd", "hd", DevFS, ddt_ATA); + BlockNVMeDev = new MasterDeviceFile("nvme", "nvme", DevFS, ddt_NVMe); + + AudioDev = new MasterDeviceFile("audio", "snd", DevFS, ddt_Audio); + + NetDev = new MasterDeviceFile("network", "net", DevFS, ddt_Network); + } + + Manager::~Manager() + { + debug("Unloading drivers"); + UnloadAllDrivers(); + delete InputMouseDev; + delete InputKeyboardDev; + } +} diff --git a/core/driver/scancode.cpp b/core/driver/scancode.cpp new file mode 100644 index 0000000..c87eeab --- /dev/null +++ b/core/driver/scancode.cpp @@ -0,0 +1,369 @@ +/* + 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 "../../driver.h" + +static char ScanCodeConversionTableLower[] = { + [KEY_1] = '1', + [KEY_2] = '2', + [KEY_3] = '3', + [KEY_4] = '4', + [KEY_5] = '5', + [KEY_6] = '6', + [KEY_7] = '7', + [KEY_8] = '8', + [KEY_9] = '9', + [KEY_0] = '0', + + [KEY_Q] = 'q', + [KEY_W] = 'w', + [KEY_E] = 'e', + [KEY_R] = 'r', + [KEY_T] = 't', + [KEY_Y] = 'y', + [KEY_U] = 'u', + [KEY_I] = 'i', + [KEY_O] = 'o', + [KEY_P] = 'p', + [KEY_A] = 'a', + [KEY_S] = 's', + [KEY_D] = 'd', + [KEY_F] = 'f', + [KEY_G] = 'g', + [KEY_H] = 'h', + [KEY_J] = 'j', + [KEY_K] = 'k', + [KEY_L] = 'l', + [KEY_Z] = 'z', + [KEY_X] = 'x', + [KEY_C] = 'c', + [KEY_V] = 'v', + [KEY_B] = 'b', + [KEY_N] = 'n', + [KEY_M] = 'm', + + [KEY_F1] = 0x00, + [KEY_F2] = 0x00, + [KEY_F3] = 0x00, + [KEY_F4] = 0x00, + [KEY_F5] = 0x00, + [KEY_F6] = 0x00, + [KEY_F7] = 0x00, + [KEY_F8] = 0x00, + [KEY_F9] = 0x00, + [KEY_F10] = 0x00, + [KEY_F11] = 0x00, + [KEY_F12] = 0x00, + + [KEYPAD_7] = '7', + [KEYPAD_8] = '8', + [KEYPAD_9] = '9', + [KEYPAD_MINUS] = '-', + [KEYPAD_4] = '4', + [KEYPAD_5] = '5', + [KEYPAD_6] = '6', + [KEYPAD_PLUS] = '+', + [KEYPAD_1] = '1', + [KEYPAD_2] = '2', + [KEYPAD_3] = '3', + [KEYPAD_0] = '0', + [KEYPAD_PERIOD] = '.', + [KEYPAD_RETURN] = '\n', + [KEYPAD_ASTERISK] = '*', + [KEYPAD_SLASH] = '/', + + [KEY_LEFT_CTRL] = 0x00, + [KEY_RIGHT_CTRL] = 0x00, + [KEY_LEFT_SHIFT] = 0x00, + [KEY_RIGHT_SHIFT] = 0x00, + [KEY_LEFT_ALT] = 0x00, + [KEY_RIGHT_ALT] = 0x00, + [KEY_ESCAPE] = '\e', + [KEY_MINUS] = '-', + [KEY_EQUAL] = '=', + [KEY_BACKSPACE] = '\b', + [KEY_TAB] = '\t', + [KEY_LEFT_BRACKET] = '[', + [KEY_RIGHT_BRACKET] = ']', + [KEY_RETURN] = '\n', + [KEY_SEMICOLON] = ';', + [KEY_APOSTROPHE] = '\'', + [KEY_BACK_TICK] = '`', + [KEY_BACKSLASH] = '\\', + [KEY_COMMA] = ',', + [KEY_PERIOD] = '.', + [KEY_SLASH] = '/', + [KEY_SPACE] = ' ', + [KEY_CAPS_LOCK] = 0x00, + [KEY_NUM_LOCK] = 0x00, + [KEY_SCROLL_LOCK] = 0x00, + [KEY_PRINT_SCREEN] = 0x00, + + [KEY_HOME] = 0x00, + [KEY_UP_ARROW] = 0x00, + [KEY_LEFT_ARROW] = 0x00, + [KEY_RIGHT_ARROW] = 0x00, + [KEY_DOWN_ARROW] = 0x00, + [KEY_PAGE_UP] = 0x00, + [KEY_PAGE_DOWN] = 0x00, + [KEY_END] = 0x00, + [KEY_INSERT] = 0x00, + [KEY_DELETE] = 0x00, + [KEY_LEFT_GUI] = 0x00, + [KEY_RIGHT_GUI] = 0x00, + [KEY_APPS] = 0x00, + + [KEY_MULTIMEDIA_PREV_TRACK] = 0x00, + [KEY_MULTIMEDIA_NEXT_TRACK] = 0x00, + [KEY_MULTIMEDIA_MUTE] = 0x00, + [KEY_MULTIMEDIA_CALCULATOR] = 0x00, + [KEY_MULTIMEDIA_PLAY] = 0x00, + [KEY_MULTIMEDIA_STOP] = 0x00, + [KEY_MULTIMEDIA_VOL_DOWN] = 0x00, + [KEY_MULTIMEDIA_VOL_UP] = 0x00, + [KEY_MULTIMEDIA_WWW_HOME] = 0x00, + [KEY_MULTIMEDIA_WWW_SEARCH] = 0x00, + [KEY_MULTIMEDIA_WWW_FAVORITES] = 0x00, + [KEY_MULTIMEDIA_WWW_REFRESH] = 0x00, + [KEY_MULTIMEDIA_WWW_STOP] = 0x00, + [KEY_MULTIMEDIA_WWW_FORWARD] = 0x00, + [KEY_MULTIMEDIA_WWW_BACK] = 0x00, + [KEY_MULTIMEDIA_MY_COMPUTER] = 0x00, + [KEY_MULTIMEDIA_EMAIL] = 0x00, + [KEY_MULTIMEDIA_MEDIA_SELECT] = 0x00, + + [KEY_ACPI_POWER] = 0x00, + [KEY_ACPI_SLEEP] = 0x00, + [KEY_ACPI_WAKE] = 0x00}; + +static char ScanCodeConversionTableUpper[] = { + [KEY_1] = '!', + [KEY_2] = '@', + [KEY_3] = '#', + [KEY_4] = '$', + [KEY_5] = '%', + [KEY_6] = '^', + [KEY_7] = '&', + [KEY_8] = '*', + [KEY_9] = '(', + [KEY_0] = ')', + + [KEY_Q] = 'Q', + [KEY_W] = 'W', + [KEY_E] = 'E', + [KEY_R] = 'R', + [KEY_T] = 'T', + [KEY_Y] = 'Y', + [KEY_U] = 'U', + [KEY_I] = 'I', + [KEY_O] = 'O', + [KEY_P] = 'P', + [KEY_A] = 'A', + [KEY_S] = 'S', + [KEY_D] = 'D', + [KEY_F] = 'F', + [KEY_G] = 'G', + [KEY_H] = 'H', + [KEY_J] = 'J', + [KEY_K] = 'K', + [KEY_L] = 'L', + [KEY_Z] = 'Z', + [KEY_X] = 'X', + [KEY_C] = 'C', + [KEY_V] = 'V', + [KEY_B] = 'B', + [KEY_N] = 'N', + [KEY_M] = 'M', + + [KEY_F1] = 0x00, + [KEY_F2] = 0x00, + [KEY_F3] = 0x00, + [KEY_F4] = 0x00, + [KEY_F5] = 0x00, + [KEY_F6] = 0x00, + [KEY_F7] = 0x00, + [KEY_F8] = 0x00, + [KEY_F9] = 0x00, + [KEY_F10] = 0x00, + [KEY_F11] = 0x00, + [KEY_F12] = 0x00, + + [KEYPAD_7] = '7', + [KEYPAD_8] = '8', + [KEYPAD_9] = '9', + [KEYPAD_MINUS] = '-', + [KEYPAD_4] = '4', + [KEYPAD_5] = '5', + [KEYPAD_6] = '6', + [KEYPAD_PLUS] = '+', + [KEYPAD_1] = '1', + [KEYPAD_2] = '2', + [KEYPAD_3] = '3', + [KEYPAD_0] = '0', + [KEYPAD_PERIOD] = '.', + [KEYPAD_RETURN] = '\n', + [KEYPAD_ASTERISK] = '*', + [KEYPAD_SLASH] = '/', + + [KEY_LEFT_CTRL] = 0x00, + [KEY_RIGHT_CTRL] = 0x00, + [KEY_LEFT_SHIFT] = 0x00, + [KEY_RIGHT_SHIFT] = 0x00, + [KEY_LEFT_ALT] = 0x00, + [KEY_RIGHT_ALT] = 0x00, + [KEY_ESCAPE] = '\e', + [KEY_MINUS] = '_', + [KEY_EQUAL] = '+', + [KEY_BACKSPACE] = '\b', + [KEY_TAB] = '\t', + [KEY_LEFT_BRACKET] = '{', + [KEY_RIGHT_BRACKET] = '}', + [KEY_RETURN] = '\n', + [KEY_SEMICOLON] = ':', + [KEY_APOSTROPHE] = '\"', + [KEY_BACK_TICK] = '~', + [KEY_BACKSLASH] = '|', + [KEY_COMMA] = '<', + [KEY_PERIOD] = '>', + [KEY_SLASH] = '/', + [KEY_SPACE] = ' ', + [KEY_CAPS_LOCK] = 0x00, + [KEY_NUM_LOCK] = 0x00, + [KEY_SCROLL_LOCK] = 0x00, + [KEY_PRINT_SCREEN] = 0x00, + + [KEY_HOME] = 0x00, + [KEY_UP_ARROW] = 0x00, + [KEY_LEFT_ARROW] = 0x00, + [KEY_RIGHT_ARROW] = 0x00, + [KEY_DOWN_ARROW] = 0x00, + [KEY_PAGE_UP] = 0x00, + [KEY_PAGE_DOWN] = 0x00, + [KEY_END] = 0x00, + [KEY_INSERT] = 0x00, + [KEY_DELETE] = 0x00, + [KEY_LEFT_GUI] = 0x00, + [KEY_RIGHT_GUI] = 0x00, + [KEY_APPS] = 0x00, + + [KEY_MULTIMEDIA_PREV_TRACK] = 0x00, + [KEY_MULTIMEDIA_NEXT_TRACK] = 0x00, + [KEY_MULTIMEDIA_MUTE] = 0x00, + [KEY_MULTIMEDIA_CALCULATOR] = 0x00, + [KEY_MULTIMEDIA_PLAY] = 0x00, + [KEY_MULTIMEDIA_STOP] = 0x00, + [KEY_MULTIMEDIA_VOL_DOWN] = 0x00, + [KEY_MULTIMEDIA_VOL_UP] = 0x00, + [KEY_MULTIMEDIA_WWW_HOME] = 0x00, + [KEY_MULTIMEDIA_WWW_SEARCH] = 0x00, + [KEY_MULTIMEDIA_WWW_FAVORITES] = 0x00, + [KEY_MULTIMEDIA_WWW_REFRESH] = 0x00, + [KEY_MULTIMEDIA_WWW_STOP] = 0x00, + [KEY_MULTIMEDIA_WWW_FORWARD] = 0x00, + [KEY_MULTIMEDIA_WWW_BACK] = 0x00, + [KEY_MULTIMEDIA_MY_COMPUTER] = 0x00, + [KEY_MULTIMEDIA_EMAIL] = 0x00, + [KEY_MULTIMEDIA_MEDIA_SELECT] = 0x00, + + [KEY_ACPI_POWER] = 0x00, + [KEY_ACPI_SLEEP] = 0x00, + [KEY_ACPI_WAKE] = 0x00}; + +#ifdef DEBUG +static const char *ScanCodeDebugNames[] = { + "KEY_1", "KEY_2", "KEY_3", "KEY_4", "KEY_5", "KEY_6", "KEY_7", "KEY_8", + "KEY_9", "KEY_0", "KEY_Q", "KEY_W", "KEY_E", "KEY_R", "KEY_T", "KEY_Y", + "KEY_U", "KEY_I", "KEY_O", "KEY_P", "KEY_A", "KEY_S", "KEY_D", "KEY_F", + "KEY_G", "KEY_H", "KEY_J", "KEY_K", "KEY_L", "KEY_Z", "KEY_X", "KEY_C", + "KEY_V", "KEY_B", "KEY_N", "KEY_M", "KEY_F1", "KEY_F2", "KEY_F3", "KEY_F4", + "KEY_F5", "KEY_F6", "KEY_F7", "KEY_F8", "KEY_F9", "KEY_F10", "KEY_F11", + "KEY_F12", "KEYPAD_7", "KEYPAD_8", "KEYPAD_9", "KEYPAD_MINUS", "KEYPAD_4", + "KEYPAD_5", "KEYPAD_6", "KEYPAD_PLUS", "KEYPAD_1", "KEYPAD_2", "KEYPAD_3", + "KEYPAD_0", "KEYPAD_PERIOD", "KEYPAD_RETURN", "KEYPAD_ASTERISK", "KEYPAD_SLASH", + "KEY_LEFT_CTRL", "KEY_RIGHT_CTRL", "KEY_LEFT_SHIFT", "KEY_RIGHT_SHIFT", + "KEY_LEFT_ALT", "KEY_RIGHT_ALT", "KEY_ESCAPE", "KEY_MINUS", "KEY_EQUAL", + "KEY_BACKSPACE", "KEY_TAB", "KEY_LEFT_BRACKET", "KEY_RIGHT_BRACKET", + "KEY_RETURN", "KEY_SEMICOLON", "KEY_APOSTROPHE", "KEY_BACK_TICK", + "KEY_BACKSLASH", "KEY_COMMA", "KEY_PERIOD", "KEY_SLASH", "KEY_SPACE", + "KEY_CAPS_LOCK", "KEY_NUM_LOCK", "KEY_SCROLL_LOCK", "KEY_PRINT_SCREEN", + "KEY_HOME", "KEY_UP_ARROW", "KEY_LEFT_ARROW", "KEY_RIGHT_ARROW", + "KEY_DOWN_ARROW", "KEY_PAGE_UP", "KEY_PAGE_DOWN", "KEY_END", "KEY_INSERT", + "KEY_DELETE", "KEY_LEFT_GUI", "KEY_RIGHT_GUI", "KEY_APPS", + "KEY_MULTIMEDIA_PREV_TRACK", "KEY_MULTIMEDIA_NEXT_TRACK", "KEY_MULTIMEDIA_MUTE", + "KEY_MULTIMEDIA_CALCULATOR", "KEY_MULTIMEDIA_PLAY", "KEY_MULTIMEDIA_STOP", + "KEY_MULTIMEDIA_VOL_DOWN", "KEY_MULTIMEDIA_VOL_UP", "KEY_MULTIMEDIA_WWW_HOME", + "KEY_MULTIMEDIA_WWW_SEARCH", "KEY_MULTIMEDIA_WWW_FAVORITES", + "KEY_MULTIMEDIA_WWW_REFRESH", "KEY_MULTIMEDIA_WWW_STOP", + "KEY_MULTIMEDIA_WWW_FORWARD", "KEY_MULTIMEDIA_WWW_BACK", + "KEY_MULTIMEDIA_MY_COMPUTER", "KEY_MULTIMEDIA_EMAIL", + "KEY_MULTIMEDIA_MEDIA_SELECT", "KEY_ACPI_POWER", "KEY_ACPI_SLEEP", "KEY_ACPI_WAKE"}; +#endif + +namespace Driver +{ + char GetScanCode(uint8_t ScanCode, bool Upper) + { + ScanCode &= 0x7F; /* Remove KEY_PRESSED bit */ + if (ScanCode >= sizeof(ScanCodeConversionTableLower)) + { + warn("Unknown scancode %x", ScanCode); + return 0x00; + } + + // debug("Scancode %x (%s)", ScanCode, ScanCodeDebugNames[ScanCode]); + return Upper + ? ScanCodeConversionTableUpper[ScanCode] + : ScanCodeConversionTableLower[ScanCode]; + } + + bool IsValidChar(uint8_t ScanCode) + { + ScanCode &= 0x7F; /* Remove KEY_PRESSED bit */ + if (ScanCode >= sizeof(ScanCodeConversionTableLower)) + return false; + + if (ScanCode > KEY_M) + { + if (ScanCode < KEYPAD_7) + return false; /* F1 - F12 */ + + switch (ScanCode) + { + case KEY_MINUS: + case KEY_EQUAL: + case KEY_LEFT_BRACKET: + case KEY_RIGHT_BRACKET: + case KEY_RETURN: + case KEY_SEMICOLON: + case KEY_APOSTROPHE: + case KEY_BACK_TICK: + case KEY_BACKSLASH: + case KEY_COMMA: + case KEY_PERIOD: + case KEY_SLASH: + case KEY_SPACE: + return true; + + default: + return false; + } + } + return true; + } +} diff --git a/core/dsdt.cpp b/core/dsdt.cpp index 6bc302b..eddaf7a 100644 --- a/core/dsdt.cpp +++ b/core/dsdt.cpp @@ -54,11 +54,7 @@ namespace ACPI #define ACPI_GAS_IO 1 #define ACPI_GAS_PCI 2 -#if defined(a64) - void DSDT::OnInterruptReceived(CPU::x64::TrapFrame *) -#elif defined(a32) - void DSDT::OnInterruptReceived(CPU::x32::TrapFrame *) -#endif + void DSDT::OnInterruptReceived(CPU::TrapFrame *) { debug("SCI Handle Triggered"); uint16_t Event = 0; @@ -77,7 +73,27 @@ namespace ACPI Event = a | b; } - debug("SCI Event: %#lx", Event); +#ifdef DEBUG + char dbgEvStr[128]; + dbgEvStr[0] = '\0'; + if (Event & ACPI_BUSMASTER) + strcat(dbgEvStr, "BUSMASTER "); + if (Event & ACPI_GLOBAL) + strcat(dbgEvStr, "GLOBAL "); + if (Event & ACPI_POWER_BUTTON) + strcat(dbgEvStr, "POWER_BUTTON "); + if (Event & ACPI_SLEEP_BUTTON) + strcat(dbgEvStr, "SLEEP_BUTTON "); + if (Event & ACPI_RTC_ALARM) + strcat(dbgEvStr, "RTC_ALARM "); + if (Event & ACPI_PCIE_WAKE) + strcat(dbgEvStr, "PCIE_WAKE "); + if (Event & ACPI_WAKE) + strcat(dbgEvStr, "WAKE "); + if (Event & ACPI_TIMER) + strcat(dbgEvStr, "ACPI_TIMER "); + KPrint("SCI Event: %s", dbgEvStr); +#endif if (Event & ACPI_BUSMASTER) { fixme("ACPI Busmaster"); @@ -88,12 +104,13 @@ namespace ACPI } else if (Event & ACPI_POWER_BUTTON) { - if (TaskManager && !TaskManager->IsPanic()) + Tasking::PCB *pcb = thisProcess; + if (pcb && !pcb->GetContext()->IsPanic()) { - TaskManager->CreateThread(TaskManager->CreateProcess(nullptr, - "Shutdown", - Tasking::TaskExecutionMode::Kernel), - Tasking::IP(KST_Shutdown)); + Tasking::Task *ctx = pcb->GetContext(); + ctx->CreateThread(ctx->GetKernelProcess(), + Tasking::IP(KST_Shutdown)) + ->Rename("Shutdown"); } else KernelShutdownThread(false); @@ -120,35 +137,56 @@ namespace ACPI } else { - error("ACPI unknown event %#lx on CPU %d", Event, GetCurrentCPU()->ID); - CPU::Stop(); + error("ACPI unknown event %#lx on CPU %d", + Event, GetCurrentCPU()->ID); + KPrint("ACPI unknown event %#lx on CPU %d", + Event, GetCurrentCPU()->ID); } } void DSDT::Shutdown() { trace("Shutting down..."); - if (SCI_EN == 1) + 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); + error("ACPI Shutdown not supported"); + return; } + + if (inw(s_cst(uint16_t, PM1a_CNT) & SCI_EN) == 0) + { + KPrint("ACPI was disabled, enabling..."); + if (SMI_CMD == 0 || ACPI_ENABLE == 0) + { + error("ACPI Shutdown not supported"); + KPrint("ACPI Shutdown not supported"); + return; + } + + outb(s_cst(uint16_t, SMI_CMD), ACPI_ENABLE); + + uint16_t Timeout = 3000; + while ((inw(s_cst(uint16_t, PM1a_CNT)) & SCI_EN) == 0 && Timeout-- > 0) + ; + + if (Timeout == 0) + { + error("ACPI Shutdown not supported"); + KPrint("ACPI Shutdown not supported"); + return; + } + + if (PM1b_CNT) + { + Timeout = 3000; + while ((inw(s_cst(uint16_t, PM1b_CNT)) & SCI_EN) == 0 && Timeout-- > 0) + ; + } + } + + 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() @@ -187,21 +225,24 @@ namespace ACPI } } - DSDT::DSDT(ACPI *acpi) : Interrupts::Handler(acpi->FADT->SCI_Interrupt) + DSDT::DSDT(ACPI *acpi) : Interrupts::Handler(acpi->FADT->SCI_Interrupt, true) { + /* TODO: AML Interpreter */ + 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; - if (!Memory::Virtual().Check(Header)) + Memory::Virtual vmm; + if (!vmm.Check(Header)) { warn("DSDT is not mapped"); debug("DSDT: %#lx", Address); - Memory::Virtual().Map(Header, Header, Memory::RW); + vmm.Map(Header, Header, Memory::RW); } size_t Length = Header->Length; - Memory::Virtual().Map(Header, Header, Length, Memory::RW); + vmm.Map(Header, Header, Length, Memory::RW); while (Length-- > 0) { @@ -212,20 +253,27 @@ namespace ACPI if (Length <= 0) { - warn("_S5 not present in ACPI"); + warn("_S5_ not present in ACPI"); return; } - if ((*(S5Address - 1) == 0x08 || (*(S5Address - 2) == 0x08 && *(S5Address - 1) == '\\')) && *(S5Address + 4) == 0x12) + 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; @@ -235,11 +283,13 @@ namespace ACPI PM1_CNT_LEN = acpi->FADT->PM1ControlLength; SLP_EN = 1 << 13; SCI_EN = 1; - trace("ACPI Shutdown is supported"); + KPrint("ACPI Shutdown is supported"); ACPIShutdownSupported = true; { - uint16_t value = ACPI_POWER_BUTTON | ACPI_SLEEP_BUTTON | ACPI_WAKE; + const uint16_t value = /*ACPI_TIMER |*/ ACPI_BUSMASTER | ACPI_GLOBAL | + ACPI_POWER_BUTTON | ACPI_SLEEP_BUTTON | ACPI_RTC_ALARM | + ACPI_PCIE_WAKE | 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: %#x [a:%#x b:%#x]", value, a, b); @@ -266,7 +316,7 @@ namespace ACPI ((APIC::APIC *)Interrupts::apic[0])->RedirectIRQ(0, uint8_t(acpi->FADT->SCI_Interrupt), 1); return; } - warn("Failed to parse _S5 in ACPI"); + warn("Failed to parse _S5_ in ACPI"); SCI_EN = 0; } diff --git a/core/interrupts_manager.cpp b/core/interrupts_manager.cpp index e3299fa..6195007 100644 --- a/core/interrupts_manager.cpp +++ b/core/interrupts_manager.cpp @@ -46,10 +46,64 @@ namespace Interrupts { struct Event { - int ID; + /** Interrupt number */ + int IRQ; + + /** Raw pointer to the Handler */ void *Data; + + /** Is this a handler? */ + bool IsHandler; + + /** + * Function to call if this is not a Handler + * + * Used for C-style callbacks. + */ + void (*Callback)(CPU::TrapFrame *); + + /** + * Context for the callback + * + * Used for C-style callbacks if the callback needs a context. + * (e.g. a driver) + */ + void *Context; + + /** + * Priority of the event + * + * Used for sorting the events. + * + * This is incremented every time the event is called. + * + * This will improve performance by reducing the time + * spent on searching for the event. + */ + unsigned long Priority; + + /** + * If this is true, the event is critical. + * + * This will make sure that the event will not be + * removed by the kernel. + * + * This is used to prevent the kernel from removing + * ACPI related handlers. (SCI interrupts) + */ + bool Critical; }; - std::vector RegisteredEvents; + std::list RegisteredEvents; + +#ifdef DEBUG +#define SORT_DIVIDER 10 +#else +#define SORT_DIVIDER 1 +#endif + +#define SORT_START 10000 + std::atomic_uint SortEvents = SORT_START / SORT_DIVIDER; + constexpr uint32_t SORT_ITR = (SORT_START * 100) / SORT_DIVIDER; #if defined(a86) /* APIC::APIC */ void *apic[MAX_CPU]; @@ -120,6 +174,7 @@ namespace Interrupts #elif defined(aa64) warn("aarch64 is not supported yet"); #endif + CPU::Interrupts(CPU::Enable); } void InitializeTimer(int Core) @@ -139,7 +194,90 @@ namespace Interrupts SafeFunction void RemoveAll() { - RegisteredEvents.clear(); + forItr(itr, RegisteredEvents) + { + if (itr->Critical) + continue; + RegisteredEvents.erase(itr); + } + } + + void AddHandler(void (*Callback)(CPU::TrapFrame *), + int InterruptNumber, + void *ctx, bool Critical) + { + /* Just log a warning if the interrupt is already registered. */ + foreach (auto ev in RegisteredEvents) + { + if (ev.IRQ == InterruptNumber && + ev.Callback == Callback) + { + warn("IRQ%d is already registered.", + InterruptNumber); + } + } + + Event newEvent = + {InterruptNumber, /* IRQ */ + nullptr, /* Data */ + false, /* IsHandler */ + Callback, /* Callback */ + ctx, /* Context */ + 0, /* Priority */ + Critical}; /* Critical */ + RegisteredEvents.push_back(newEvent); + debug("Registered interrupt handler for IRQ%d to %#lx", + InterruptNumber, Callback); + } + + void RemoveHandler(void (*Callback)(CPU::TrapFrame *), int InterruptNumber) + { + forItr(itr, RegisteredEvents) + { + if (itr->IRQ == InterruptNumber && + itr->Callback == Callback) + { + RegisteredEvents.erase(itr); + debug("Unregistered interrupt handler for IRQ%d to %#lx", + InterruptNumber, Callback); + return; + } + } + warn("Event %d not found.", InterruptNumber); + } + + void RemoveHandler(void (*Callback)(CPU::TrapFrame *)) + { + forItr(itr, RegisteredEvents) + { + if (itr->Callback == Callback) + { + debug("Removing handle %d %#lx", itr->IRQ, + itr->IsHandler + ? itr->Data + : (void *)itr->Callback); + + RegisteredEvents.erase(itr); + } + } + warn("Handle not found."); + } + + void RemoveHandler(int InterruptNumber) + { + forItr(itr, RegisteredEvents) + { + if (itr->IRQ == InterruptNumber) + { + debug("Removing handle %d %#lx", itr->IRQ, + itr->IsHandler + ? itr->Data + : (void *)itr->Callback); + + RegisteredEvents.erase(itr); + } + } + warn("IRQ%d not found.", InterruptNumber); } extern "C" SafeFunction void MainInterruptHandler(void *Data) @@ -170,77 +308,126 @@ namespace Interrupts Core = CoreData->ID; /* If this is false, we have a big problem. */ - if (likely(Frame->InterruptNumber < CPU::x86::IRQ223 && - Frame->InterruptNumber > CPU::x86::ISR0)) - { - /* Halt core interrupt */ - if (unlikely(Frame->InterruptNumber == CPU::x86::IRQ29)) - CPU::Stop(); - - bool InterruptHandled = false; - foreach (auto ev in RegisteredEvents) - { -#if defined(a86) - if ((ev.ID + CPU::x86::IRQ0) == s_cst(int, Frame->InterruptNumber)) -#elif defined(aa64) - if (ev.ID == s_cst(int, Frame->InterruptNumber)) -#endif - { - Handler *hnd = (Handler *)ev.Data; - hnd->OnInterruptReceived(Frame); - InterruptHandled = true; - } - } - - if (!InterruptHandled) - { - error("IRQ%d is unhandled on CPU %d.", - Frame->InterruptNumber - 32, Core); - if (Frame->InterruptNumber == CPU::x86::IRQ1) - { - uint8_t scancode = inb(0x60); - warn("IRQ1 is the keyboard interrupt. Scancode: %#x", scancode); - } - } - - if (likely(apic[Core])) - { - APIC::APIC *this_apic = (APIC::APIC *)apic[Core]; - this_apic->EOI(); - // TODO: Handle PIC too - return; - } - else - fixme("APIC not found for core %d", Core); - // TODO: PIC - } - else + if (unlikely(Frame->InterruptNumber >= CPU::x86::IRQ223 || + Frame->InterruptNumber <= CPU::x86::ISR0)) { error("Interrupt number %d is out of range.", Frame->InterruptNumber); + assert(!"Interrupt number is out of range."); } - error("HALT HALT HALT HALT HALT HALT HALT HALT HALT [IRQ%d]", - Frame->InterruptNumber - 32); + /* Halt core interrupt */ + if (unlikely(Frame->InterruptNumber == CPU::x86::IRQ31)) + CPU::Stop(); + + bool InterruptHandled = false; + foreach (auto &ev in RegisteredEvents) + { +#if defined(a86) + int iEvNum = ev.IRQ + CPU::x86::IRQ0; +#elif defined(aa64) + int iEvNum = ev.IRQ; +#endif + if (iEvNum == s_cst(int, Frame->InterruptNumber)) + { + if (ev.IsHandler) + { + Handler *hnd = (Handler *)ev.Data; + hnd->OnInterruptReceived(Frame); + } + else + { + if (ev.Context != nullptr) + ev.Callback((CPU::TrapFrame *)ev.Context); + else + ev.Callback(Frame); + } + ev.Priority++; + InterruptHandled = true; + } + } + + if (unlikely(!InterruptHandled)) + { + error("IRQ%d is unhandled on CPU %d.", + Frame->InterruptNumber - 32, Core); + } + + /* TODO: This should be done when the os is idle */ + if (SortEvents++ > SORT_ITR) + { + debug("Sorting events"); + SortEvents = 0; + RegisteredEvents.sort([](const Event &a, const Event &b) + { return a.Priority < b.Priority; }); + +#ifdef DEBUG + foreach (auto ev in RegisteredEvents) + { + void *func = ev.IsHandler + ? ev.Data + : (void *)ev.Callback; + const char *symbol = ev.IsHandler + ? "class" + : KernelSymbolTable->GetSymbol((uintptr_t)func); + + debug("Event IRQ%d [%#lx %s] has priority %ld", + ev.IRQ, func, symbol, ev.Priority); + } +#endif + } + + if (likely(apic[Core])) + { + APIC::APIC *this_apic = (APIC::APIC *)apic[Core]; + this_apic->EOI(); + // TODO: Handle PIC too + return; + } + else + fixme("APIC not found for core %d", Core); + // TODO: PIC + + assert(!"Interrupt EOI not handled."); CPU::Stop(); } - Handler::Handler(int InterruptNumber) + Handler::Handler(int InterruptNumber, bool Critical) { foreach (auto ev in RegisteredEvents) { - if (ev.ID == InterruptNumber) + if (ev.IRQ == InterruptNumber) { warn("IRQ%d is already registered.", InterruptNumber); } } - debug("Registering interrupt handler for IRQ%d.", - InterruptNumber); - this->InterruptNumber = InterruptNumber; - RegisteredEvents.push_back({InterruptNumber, this}); + + Event newEvent = + {InterruptNumber, /* IRQ */ + this, /* Data */ + true, /* IsHandler */ + nullptr, /* Callback */ + nullptr, /* Context */ + 0, /* Priority */ + Critical}; /* Critical */ + RegisteredEvents.push_back(newEvent); + debug("Registered interrupt handler for IRQ%d.", + InterruptNumber); + } + + Handler::Handler(PCI::PCIDevice Device, bool Critical) + { + PCI::PCIHeader0 *hdr0 = + (PCI::PCIHeader0 *)Device.Header; + Handler(hdr0->InterruptLine, Critical); + } + + Handler::Handler() + { + debug("Empty interrupt handler."); } Handler::~Handler() @@ -250,7 +437,7 @@ namespace Interrupts forItr(itr, RegisteredEvents) { - if (itr->ID == this->InterruptNumber) + if (itr->IRQ == this->InterruptNumber) { RegisteredEvents.erase(itr); return; @@ -259,21 +446,9 @@ namespace Interrupts warn("Event %d not found.", this->InterruptNumber); } -#if defined(a64) - void Handler::OnInterruptReceived(CPU::x64::TrapFrame *Frame) + void Handler::OnInterruptReceived(CPU::TrapFrame *Frame) { - trace("Unhandled interrupt IRQ%d", - Frame->InterruptNumber - 32); -#elif defined(a32) - void Handler::OnInterruptReceived(CPU::x32::TrapFrame *Frame) - { - trace("Unhandled interrupt IRQ%d", - Frame->InterruptNumber - 32); -#elif defined(aa64) - void Handler::OnInterruptReceived(CPU::aarch64::TrapFrame *Frame) - { - trace("Unhandled interrupt IRQ%d", + trace("Unhandled interrupt %d", Frame->InterruptNumber); -#endif } } diff --git a/core/lock.cpp b/core/lock.cpp index 1d20e52..247afd8 100644 --- a/core/lock.cpp +++ b/core/lock.cpp @@ -22,76 +22,71 @@ #include "../kernel.h" -#ifdef DEBUG /* This might end up in a deadlock in the deadlock handler. Nobody can escape the deadlock, not even the deadlock handler itself. */ - -// #define PRINT_BACKTRACE -#endif +// #define PRINT_BACKTRACE 1 #ifdef PRINT_BACKTRACE -#pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wframe-address" void PrintStacktrace(LockClass::SpinLockData *Lock) { - if (KernelSymbolTable) + if (!KernelSymbolTable) { - struct StackFrame - { - uintptr_t BasePointer; - uintptr_t ReturnAddress; - }; - - // char DbgAttempt[1024] = "\0"; - // char DbgHolder[1024] = "\0"; - - std::string DbgAttempt = "\0"; - std::string DbgHolder = "\0"; - - StackFrame *FrameAttempt = (StackFrame *)Lock->StackPointerAttempt.load(); - StackFrame *FrameHolder = (StackFrame *)Lock->StackPointerHolder.load(); - - while (Memory::Virtual().Check(FrameAttempt)) - { - DbgAttempt.concat(KernelSymbolTable->GetSymbolFromAddress(FrameAttempt->ReturnAddress)); - DbgAttempt.concat("<-"); - FrameAttempt = (StackFrame *)FrameAttempt->BasePointer; - } - debug("Attempt: %s", DbgAttempt.c_str()); - - while (Memory::Virtual().Check(FrameHolder)) - { - DbgHolder.concat(KernelSymbolTable->GetSymbolFromAddress(FrameHolder->ReturnAddress)); - DbgHolder.concat("<-"); - FrameHolder = (StackFrame *)FrameHolder->BasePointer; - } - - debug("Holder: %s", DbgHolder.c_str()); - - // debug("\t\t%s<-%s<-%s<-%s<-%s<-%s<-%s<-%s<-%s<-%s", - // KernelSymbolTable->GetSymbolFromAddress((uintptr_t)__builtin_return_address(0)), - // KernelSymbolTable->GetSymbolFromAddress((uintptr_t)__builtin_return_address(1)), - // KernelSymbolTable->GetSymbolFromAddress((uintptr_t)__builtin_return_address(2)), - // KernelSymbolTable->GetSymbolFromAddress((uintptr_t)__builtin_return_address(3)), - // KernelSymbolTable->GetSymbolFromAddress((uintptr_t)__builtin_return_address(4)), - // KernelSymbolTable->GetSymbolFromAddress((uintptr_t)__builtin_return_address(5)), - // KernelSymbolTable->GetSymbolFromAddress((uintptr_t)__builtin_return_address(6)), - // KernelSymbolTable->GetSymbolFromAddress((uintptr_t)__builtin_return_address(7)), - // KernelSymbolTable->GetSymbolFromAddress((uintptr_t)__builtin_return_address(8)), - // KernelSymbolTable->GetSymbolFromAddress((uintptr_t)__builtin_return_address(9))); + warn("Symbol table not available."); + return; } + + struct StackFrame + { + uintptr_t BasePointer; + uintptr_t ReturnAddress; + }; + + // char DbgAttempt[1024] = "\0"; + // char DbgHolder[1024] = "\0"; + std::string DbgAttempt = "\0"; + std::string DbgHolder = "\0"; + + StackFrame *FrameAttempt = (StackFrame *)Lock->StackPointerAttempt.load(); + StackFrame *FrameHolder = (StackFrame *)Lock->StackPointerHolder.load(); + + while (Memory::Virtual().Check(FrameAttempt)) + { + DbgAttempt.concat(KernelSymbolTable->GetSymbol(FrameAttempt->ReturnAddress)); + DbgAttempt.concat("<-"); + FrameAttempt = (StackFrame *)FrameAttempt->BasePointer; + } + warn("Attempt: %s", DbgAttempt.c_str()); + + while (Memory::Virtual().Check(FrameHolder)) + { + DbgHolder.concat(KernelSymbolTable->GetSymbol(FrameHolder->ReturnAddress)); + DbgHolder.concat("<-"); + FrameHolder = (StackFrame *)FrameHolder->BasePointer; + } + + warn("Holder: %s", DbgHolder.c_str()); + + // warn("\t\t%s<-%s<-%s<-%s<-%s<-%s<-%s<-%s<-%s<-%s", + // KernelSymbolTable->GetSymbol((uintptr_t)__builtin_return_address(0)), + // KernelSymbolTable->GetSymbol((uintptr_t)__builtin_return_address(1)), + // KernelSymbolTable->GetSymbol((uintptr_t)__builtin_return_address(2)), + // KernelSymbolTable->GetSymbol((uintptr_t)__builtin_return_address(3)), + // KernelSymbolTable->GetSymbol((uintptr_t)__builtin_return_address(4)), + // KernelSymbolTable->GetSymbol((uintptr_t)__builtin_return_address(5)), + // KernelSymbolTable->GetSymbol((uintptr_t)__builtin_return_address(6)), + // KernelSymbolTable->GetSymbol((uintptr_t)__builtin_return_address(7)), + // KernelSymbolTable->GetSymbol((uintptr_t)__builtin_return_address(8)), + // KernelSymbolTable->GetSymbol((uintptr_t)__builtin_return_address(9))); } -#pragma GCC diagnostic pop #endif #ifdef DEBUG -#define DEADLOCK_TIMEOUT 0x100000 -#define DEADLOCK_TIMEOUT_DEBUGGER 0x1000 +#define DEADLOCK_TIMEOUT 0x1000 #else #define DEADLOCK_TIMEOUT 0x10000000 -#define DEADLOCK_TIMEOUT_DEBUGGER 0x100000 #endif bool ForceUnlock = false; @@ -159,26 +154,26 @@ int LockClass::Lock(const char *FunctionName) Retry: int i = 0; while (IsLocked.exchange(true, std::memory_order_acquire) && - ++i < (DebuggerIsAttached ? DEADLOCK_TIMEOUT_DEBUGGER : DEADLOCK_TIMEOUT)) + ++i < DEADLOCK_TIMEOUT) { this->Yield(); } - if (i >= (DebuggerIsAttached ? DEADLOCK_TIMEOUT_DEBUGGER : DEADLOCK_TIMEOUT)) + if (i >= DEADLOCK_TIMEOUT) { DeadLock(LockData); goto Retry; } - LockData.Count++; - LockData.CurrentHolder = FunctionName; - LockData.StackPointerHolder = (uintptr_t)__builtin_frame_address(0); + LockData.Count.fetch_add(1); + LockData.CurrentHolder.store(FunctionName); + LockData.StackPointerHolder.store((uintptr_t)__builtin_frame_address(0)); CPUData *CoreData = GetCurrentCPU(); if (CoreData != nullptr) - LockData.Core = CoreData->ID; + LockData.Core.store(CoreData->ID); - LocksCount++; + LocksCount.fetch_add(1); __sync; return 0; @@ -189,8 +184,8 @@ int LockClass::Unlock() __sync; IsLocked.store(false, std::memory_order_release); - LockData.Count--; - LocksCount--; + LockData.Count.fetch_sub(1); + LocksCount.fetch_sub(1); return 0; } @@ -230,19 +225,19 @@ int LockClass::TimeoutLock(const char *FunctionName, uint64_t Timeout) if (!TimeManager) return Lock(FunctionName); - LockData.AttemptingToGet = FunctionName; - LockData.StackPointerAttempt = (uintptr_t)__builtin_frame_address(0); + LockData.AttemptingToGet.store(FunctionName); + LockData.StackPointerAttempt.store((uintptr_t)__builtin_frame_address(0)); std::atomic_uint64_t Target = 0; Retry: int i = 0; while (IsLocked.exchange(true, std::memory_order_acquire) && - ++i < (DebuggerIsAttached ? DEADLOCK_TIMEOUT_DEBUGGER : DEADLOCK_TIMEOUT)) + ++i < DEADLOCK_TIMEOUT) { this->Yield(); } - if (i >= (DebuggerIsAttached ? DEADLOCK_TIMEOUT_DEBUGGER : DEADLOCK_TIMEOUT)) + if (i >= DEADLOCK_TIMEOUT) { if (Target.load() == 0) Target.store(TimeManager->CalculateTarget(Timeout, @@ -251,15 +246,15 @@ Retry: goto Retry; } - LockData.Count++; - LockData.CurrentHolder = FunctionName; - LockData.StackPointerHolder = (uintptr_t)__builtin_frame_address(0); + LockData.Count.fetch_add(1); + LockData.CurrentHolder.store(FunctionName); + LockData.StackPointerHolder.store((uintptr_t)__builtin_frame_address(0)); CPUData *CoreData = GetCurrentCPU(); if (CoreData != nullptr) - LockData.Core = CoreData->ID; + LockData.Core.store(CoreData->ID); - LocksCount++; + LocksCount.fetch_add(1); __sync; return 0; diff --git a/core/memory/brk.cpp b/core/memory/brk.cpp index 83a6813..ab81bca 100644 --- a/core/memory/brk.cpp +++ b/core/memory/brk.cpp @@ -38,39 +38,45 @@ namespace Memory /* Check if the address is valid. */ if ((uintptr_t)Address < HeapStart) + { + debug("Address %#lx is less than HeapStart %#lx", Address, HeapStart); return (void *)-ENOMEM; + } - Virtual vmm = Virtual(this->Table); + Virtual vmm(this->Table); if ((uintptr_t)Address > Break) { /* Allocate more memory. */ - size_t Pages = TO_PAGES(uintptr_t(Address) - Break); + ssize_t Pages = TO_PAGES(uintptr_t(Address) - Break); void *Allocated = vma->RequestPages(Pages); if (Allocated == nullptr) return (void *)-ENOMEM; /* Map the allocated pages. */ - for (size_t i = 0; i < Pages; i++) + for (ssize_t i = 0; i < Pages; i++) { void *VirtAddr = (void *)(Break + (i * PAGE_SIZE)); void *PhysAddr = (void *)(uintptr_t(Allocated) + (i * PAGE_SIZE)); + debug("Mapping %#lx to %#lx", VirtAddr, PhysAddr); vmm.Map(VirtAddr, PhysAddr, RW | US); } - Break = (uint64_t)Address; - return (void *)Break; + Break = ROUND_UP(uintptr_t(Address), PAGE_SIZE); + debug("Round up %#lx to %#lx", Address, Break); + return Address; } /* Free memory. */ - size_t Pages = TO_PAGES(uintptr_t(Address) - Break); + ssize_t Pages = TO_PAGES(Break - uintptr_t(Address)); vma->FreePages((void *)Break, Pages); /* Unmap the freed pages. */ - for (size_t i = 0; i < Pages; i++) + for (ssize_t i = 0; i < Pages; i++) { uint64_t Page = Break - (i * 0x1000); - vmm.Remap((void *)Page, (void *)Page, PTFlag::P | PTFlag::RW); + vmm.Remap((void *)Page, (void *)Page, RW); + debug("Unmapping %#lx", Page); } Break = (uint64_t)Address; @@ -82,12 +88,16 @@ namespace Memory assert(Table != nullptr); assert(vma != nullptr); + debug("+ %#lx", this); + this->Table = Table; this->vma = vma; } ProgramBreak::~ProgramBreak() { + debug("- %#lx", this); + /* Do nothing because VirtualMemoryArea will be destroyed later. */ } diff --git a/core/memory/heap_allocators/liballoc_1_1/liballoc_1_1.c b/core/memory/heap_allocators/liballoc_1_1/liballoc_1_1.c index cf7deb5..226d0b3 100644 --- a/core/memory/heap_allocators/liballoc_1_1/liballoc_1_1.c +++ b/core/memory/heap_allocators/liballoc_1_1/liballoc_1_1.c @@ -1,4 +1,5 @@ #include "liballoc_1_1.h" +#include #pragma GCC diagnostic ignored "-Wconversion" #pragma GCC diagnostic ignored "-Wsign-conversion" @@ -104,6 +105,7 @@ static long long l_possibleOverruns = 0; ///< Number of possible overruns __no_sanitize("undefined") static void *liballoc_memset(void *s, int c, size_t n) { + return memset(s, c, n); unsigned int i; for (i = 0; i < n; i++) ((char *)s)[i] = c; @@ -112,6 +114,7 @@ __no_sanitize("undefined") static void *liballoc_memset(void *s, int c, size_t n } __no_sanitize("undefined") static void *liballoc_memcpy(void *s1, const void *s2, size_t n) { + return memcpy(s1, s2, n); char *cdest; char *csrc; unsigned int *ldest = (unsigned int *)s1; diff --git a/core/memory/heap_allocators/liballoc_1_1/liballoc_1_1.h b/core/memory/heap_allocators/liballoc_1_1/liballoc_1_1.h index 3f3e7e5..5a67e5d 100644 --- a/core/memory/heap_allocators/liballoc_1_1/liballoc_1_1.h +++ b/core/memory/heap_allocators/liballoc_1_1/liballoc_1_1.h @@ -24,46 +24,46 @@ extern "C" { #endif - /** This function is supposed to lock the memory data structures. It - * could be as simple as disabling interrupts or acquiring a spinlock. - * It's up to you to decide. - * - * \return 0 if the lock was acquired successfully. Anything else is - * failure. - */ - extern int liballoc_lock(); + /** This function is supposed to lock the memory data structures. It + * could be as simple as disabling interrupts or acquiring a spinlock. + * It's up to you to decide. + * + * \return 0 if the lock was acquired successfully. Anything else is + * failure. + */ + extern int liballoc_lock(); - /** This function unlocks what was previously locked by the liballoc_lock - * function. If it disabled interrupts, it enables interrupts. If it - * had acquiried a spinlock, it releases the spinlock. etc. - * - * \return 0 if the lock was successfully released. - */ - extern int liballoc_unlock(); + /** This function unlocks what was previously locked by the liballoc_lock + * function. If it disabled interrupts, it enables interrupts. If it + * had acquiried a spinlock, it releases the spinlock. etc. + * + * \return 0 if the lock was successfully released. + */ + extern int liballoc_unlock(); - /** This is the hook into the local system which allocates pages. It - * accepts an integer parameter which is the number of pages - * required. The page size was set up in the liballoc_init function. - * - * \return NULL if the pages were not allocated. - * \return A pointer to the allocated memory. - */ - extern void *liballoc_alloc(size_t); + /** This is the hook into the local system which allocates pages. It + * accepts an integer parameter which is the number of pages + * required. The page size was set up in the liballoc_init function. + * + * \return NULL if the pages were not allocated. + * \return A pointer to the allocated memory. + */ + extern void *liballoc_alloc(size_t); - /** This frees previously allocated memory. The void* parameter passed - * to the function is the exact same value returned from a previous - * liballoc_alloc call. - * - * The integer value is the number of pages to free. - * - * \return 0 if the memory was successfully freed. - */ - extern int liballoc_free(void *, size_t); + /** This frees previously allocated memory. The void* parameter passed + * to the function is the exact same value returned from a previous + * liballoc_alloc call. + * + * The integer value is the number of pages to free. + * + * \return 0 if the memory was successfully freed. + */ + extern int liballoc_free(void *, size_t); - extern void *PREFIX(malloc)(size_t); ///< The standard function. - extern void *PREFIX(realloc)(void *, size_t); ///< The standard function. - extern void *PREFIX(calloc)(size_t, size_t); ///< The standard function. - extern void PREFIX(free)(void *); ///< The standard function. + extern void *PREFIX(malloc)(size_t); ///< The standard function. + extern void *PREFIX(realloc)(void *, size_t); ///< The standard function. + extern void *PREFIX(calloc)(size_t, size_t); ///< The standard function. + extern void PREFIX(free)(void *); ///< The standard function. #ifdef __cplusplus } diff --git a/core/memory/heap_allocators/liballoc_1_1/liballoc_hooks.cpp b/core/memory/heap_allocators/liballoc_1_1/liballoc_hooks.cpp index ea09bf8..52b2849 100644 --- a/core/memory/heap_allocators/liballoc_1_1/liballoc_hooks.cpp +++ b/core/memory/heap_allocators/liballoc_1_1/liballoc_hooks.cpp @@ -16,11 +16,14 @@ EXTERNC int liballoc_unlock() EXTERNC void *liballoc_alloc(size_t Pages) { - return KernelAllocator.RequestPages(Pages); + void *ret = KernelAllocator.RequestPages(Pages); + debug("(%d) = %#lx", Pages, ret); + return ret; } EXTERNC int liballoc_free(void *Address, size_t Pages) { + debug("(%#lx, %d)", Address, Pages); KernelAllocator.FreePages(Address, Pages); return 0; } diff --git a/core/memory/heap_allocators/rpmalloc/rpmalloc.c b/core/memory/heap_allocators/rpmalloc/rpmalloc.c new file mode 100644 index 0000000..68bc2a0 --- /dev/null +++ b/core/memory/heap_allocators/rpmalloc/rpmalloc.c @@ -0,0 +1,3597 @@ +/* rpmalloc.c - Memory allocator - Public Domain - 2016-2020 Mattias Jansson + * + * This library provides a cross-platform lock free thread caching malloc implementation in C11. + * The latest source code is always available at + * + * https://github.com/mjansson/rpmalloc + * + * This library is put in the public domain; you can redistribute it and/or modify it without any restrictions. + * + */ + +#include "rpmalloc.h" + +//////////// +/// +/// Build time configurable limits +/// +////// + +#if defined(__clang__) +#pragma clang diagnostic ignored "-Wunused-macros" +#pragma clang diagnostic ignored "-Wunused-function" +#if __has_warning("-Wreserved-identifier") +#pragma clang diagnostic ignored "-Wreserved-identifier" +#endif +#elif defined(__GNUC__) +#pragma GCC diagnostic ignored "-Wunused-macros" +#pragma GCC diagnostic ignored "-Wunused-function" +#endif + +#ifndef HEAP_ARRAY_SIZE +//! Size of heap hashmap +#define HEAP_ARRAY_SIZE 47 +#endif +#ifndef ENABLE_THREAD_CACHE +//! Enable per-thread cache +#define ENABLE_THREAD_CACHE 1 +#endif +#ifndef ENABLE_GLOBAL_CACHE +//! Enable global cache shared between all threads, requires thread cache +#define ENABLE_GLOBAL_CACHE 1 +#endif +#ifndef ENABLE_VALIDATE_ARGS +//! Enable validation of args to public entry points +#define ENABLE_VALIDATE_ARGS 1 +#endif +#ifndef ENABLE_STATISTICS +//! Enable statistics collection +#define ENABLE_STATISTICS 0 +#endif +#ifndef ENABLE_ASSERTS +//! Enable asserts +#define ENABLE_ASSERTS 1 +#endif +#ifndef ENABLE_OVERRIDE +//! Override standard library malloc/free and new/delete entry points +#define ENABLE_OVERRIDE 0 +#endif +#ifndef ENABLE_PRELOAD +//! Support preloading +#define ENABLE_PRELOAD 0 +#endif +#ifndef DISABLE_UNMAP +//! Disable unmapping memory pages (also enables unlimited cache) +#define DISABLE_UNMAP 0 +#endif +#ifndef ENABLE_UNLIMITED_CACHE +//! Enable unlimited global cache (no unmapping until finalization) +#define ENABLE_UNLIMITED_CACHE 0 +#endif +#ifndef ENABLE_ADAPTIVE_THREAD_CACHE +//! Enable adaptive thread cache size based on use heuristics +#define ENABLE_ADAPTIVE_THREAD_CACHE 0 +#endif +#ifndef DEFAULT_SPAN_MAP_COUNT +//! Default number of spans to map in call to map more virtual memory (default values yield 4MiB here) +#define DEFAULT_SPAN_MAP_COUNT 64 +#endif +#ifndef GLOBAL_CACHE_MULTIPLIER +//! Multiplier for global cache +#define GLOBAL_CACHE_MULTIPLIER 8 +#endif + +#if DISABLE_UNMAP && !ENABLE_GLOBAL_CACHE +#error Must use global cache if unmap is disabled +#endif + +#if DISABLE_UNMAP +#undef ENABLE_UNLIMITED_CACHE +#define ENABLE_UNLIMITED_CACHE 1 +#endif + +#if !ENABLE_GLOBAL_CACHE +#undef ENABLE_UNLIMITED_CACHE +#define ENABLE_UNLIMITED_CACHE 0 +#endif + +#if !ENABLE_THREAD_CACHE +#undef ENABLE_ADAPTIVE_THREAD_CACHE +#define ENABLE_ADAPTIVE_THREAD_CACHE 0 +#endif + +#ifndef FORCEINLINE +#define FORCEINLINE inline __attribute__((__always_inline__)) +#endif + +#include +#include +#include +#include +#include +#include +#include + +#if defined(_WIN32) && (!defined(BUILD_DYNAMIC_LINK) || !BUILD_DYNAMIC_LINK) +#include +static DWORD fls_key; +#endif + +#include +#include +#define PROT_MAX(f) 0 + +#ifndef MAP_UNINITIALIZED +#define MAP_UNINITIALIZED 0 +#endif + +#include + +long __rpmalloc_sysconf(int name); +void *__rpmalloc_mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset); +int __rpmalloc_munmap(void *addr, size_t length); +int __rpmalloc_posix_madvise(void *addr, size_t length, int advice); + +#if ENABLE_ASSERTS +#undef NDEBUG +#if defined(_MSC_VER) && !defined(_DEBUG) +#define _DEBUG +#endif +#include +#define RPMALLOC_TOSTRING_M(x) #x +#define RPMALLOC_TOSTRING(x) RPMALLOC_TOSTRING_M(x) +#define rpmalloc_assert(truth, message) \ + do \ + { \ + if (!(truth)) \ + { \ + if (_memory_config.error_callback) \ + { \ + _memory_config.error_callback( \ + message " (" RPMALLOC_TOSTRING(truth) ") at " __FILE__ ":" RPMALLOC_TOSTRING(__LINE__)); \ + } \ + else \ + { \ + assert((truth) && message); \ + } \ + } \ + } while (0) +#else +#define rpmalloc_assert(truth, message) \ + do \ + { \ + } while (0) +#endif +#if ENABLE_STATISTICS +#include +#endif + +#include + +typedef volatile _Atomic(int32_t) atomic32_t; +typedef volatile _Atomic(int64_t) atomic64_t; +typedef volatile _Atomic(void *) atomicptr_t; + +/* Intellisense errors */ +#ifndef __debug_vscode__ + +static FORCEINLINE int32_t atomic_load32(atomic32_t *src) { return atomic_load_explicit(src, memory_order_relaxed); } +static FORCEINLINE void atomic_store32(atomic32_t *dst, int32_t val) { atomic_store_explicit(dst, val, memory_order_relaxed); } +static FORCEINLINE int32_t atomic_incr32(atomic32_t *val) { return atomic_fetch_add_explicit(val, 1, memory_order_relaxed) + 1; } +static FORCEINLINE int32_t atomic_decr32(atomic32_t *val) { return atomic_fetch_add_explicit(val, -1, memory_order_relaxed) - 1; } +static FORCEINLINE int32_t atomic_add32(atomic32_t *val, int32_t add) { return atomic_fetch_add_explicit(val, add, memory_order_relaxed) + add; } +static FORCEINLINE int atomic_cas32_acquire(atomic32_t *dst, int32_t val, int32_t ref) { return atomic_compare_exchange_weak_explicit(dst, &ref, val, memory_order_acquire, memory_order_relaxed); } +static FORCEINLINE void atomic_store32_release(atomic32_t *dst, int32_t val) { atomic_store_explicit(dst, val, memory_order_release); } +static FORCEINLINE int64_t atomic_load64(atomic64_t *val) { return atomic_load_explicit(val, memory_order_relaxed); } +static FORCEINLINE int64_t atomic_add64(atomic64_t *val, int64_t add) { return atomic_fetch_add_explicit(val, add, memory_order_relaxed) + add; } +static FORCEINLINE void *atomic_load_ptr(atomicptr_t *src) { return atomic_load_explicit(src, memory_order_relaxed); } +static FORCEINLINE void atomic_store_ptr(atomicptr_t *dst, void *val) { atomic_store_explicit(dst, val, memory_order_relaxed); } +static FORCEINLINE void atomic_store_ptr_release(atomicptr_t *dst, void *val) { atomic_store_explicit(dst, val, memory_order_release); } +static FORCEINLINE void *atomic_exchange_ptr_acquire(atomicptr_t *dst, void *val) { return atomic_exchange_explicit(dst, val, memory_order_acquire); } +static FORCEINLINE int atomic_cas_ptr(atomicptr_t *dst, void *val, void *ref) { return atomic_compare_exchange_weak_explicit(dst, &ref, val, memory_order_relaxed, memory_order_relaxed); } + +#else + +static FORCEINLINE int32_t atomic_load32(atomic32_t *src) { return 0; } +static FORCEINLINE void atomic_store32(atomic32_t *dst, int32_t val) {} +static FORCEINLINE int32_t atomic_incr32(atomic32_t *val) { return 0; } +static FORCEINLINE int32_t atomic_decr32(atomic32_t *val) { return 0; } +static FORCEINLINE int32_t atomic_add32(atomic32_t *val, int32_t add) { return 0; } +static FORCEINLINE int atomic_cas32_acquire(atomic32_t *dst, int32_t val, int32_t ref) { return 0; } +static FORCEINLINE void atomic_store32_release(atomic32_t *dst, int32_t val) {} +static FORCEINLINE int64_t atomic_load64(atomic64_t *val) { return 0; } +static FORCEINLINE int64_t atomic_add64(atomic64_t *val, int64_t add) { return 0; } +static FORCEINLINE void *atomic_load_ptr(atomicptr_t *src) { return 0; } +static FORCEINLINE void atomic_store_ptr(atomicptr_t *dst, void *val) {} +static FORCEINLINE void atomic_store_ptr_release(atomicptr_t *dst, void *val) {} +static FORCEINLINE void *atomic_exchange_ptr_acquire(atomicptr_t *dst, void *val) { return 0; } +static FORCEINLINE int atomic_cas_ptr(atomicptr_t *dst, void *val, void *ref) { return 0; } + +#endif + +#define EXPECTED(x) __builtin_expect((x), 1) +#define UNEXPECTED(x) __builtin_expect((x), 0) + +//////////// +/// +/// Statistics related functions (evaluate to nothing when statistics not enabled) +/// +////// + +#if ENABLE_STATISTICS +#define _rpmalloc_stat_inc(counter) atomic_incr32(counter) +#define _rpmalloc_stat_dec(counter) atomic_decr32(counter) +#define _rpmalloc_stat_add(counter, value) atomic_add32(counter, (int32_t)(value)) +#define _rpmalloc_stat_add64(counter, value) atomic_add64(counter, (int64_t)(value)) +#define _rpmalloc_stat_add_peak(counter, value, peak) \ + do \ + { \ + int32_t _cur_count = atomic_add32(counter, (int32_t)(value)); \ + if (_cur_count > (peak)) \ + peak = _cur_count; \ + } while (0) +#define _rpmalloc_stat_sub(counter, value) atomic_add32(counter, -(int32_t)(value)) +#define _rpmalloc_stat_inc_alloc(heap, class_idx) \ + do \ + { \ + int32_t alloc_current = atomic_incr32(&heap->size_class_use[class_idx].alloc_current); \ + if (alloc_current > heap->size_class_use[class_idx].alloc_peak) \ + heap->size_class_use[class_idx].alloc_peak = alloc_current; \ + atomic_incr32(&heap->size_class_use[class_idx].alloc_total); \ + } while (0) +#define _rpmalloc_stat_inc_free(heap, class_idx) \ + do \ + { \ + atomic_decr32(&heap->size_class_use[class_idx].alloc_current); \ + atomic_incr32(&heap->size_class_use[class_idx].free_total); \ + } while (0) +#else +#define _rpmalloc_stat_inc(counter) \ + do \ + { \ + } while (0) +#define _rpmalloc_stat_dec(counter) \ + do \ + { \ + } while (0) +#define _rpmalloc_stat_add(counter, value) \ + do \ + { \ + } while (0) +#define _rpmalloc_stat_add64(counter, value) \ + do \ + { \ + } while (0) +#define _rpmalloc_stat_add_peak(counter, value, peak) \ + do \ + { \ + } while (0) +#define _rpmalloc_stat_sub(counter, value) \ + do \ + { \ + } while (0) +#define _rpmalloc_stat_inc_alloc(heap, class_idx) \ + do \ + { \ + } while (0) +#define _rpmalloc_stat_inc_free(heap, class_idx) \ + do \ + { \ + } while (0) +#endif + +/// +/// Preconfigured limits and sizes +/// + +//! Granularity of a small allocation block (must be power of two) +#define SMALL_GRANULARITY 16 +//! Small granularity shift count +#define SMALL_GRANULARITY_SHIFT 4 +//! Number of small block size classes +#define SMALL_CLASS_COUNT 65 +//! Maximum size of a small block +#define SMALL_SIZE_LIMIT (SMALL_GRANULARITY * (SMALL_CLASS_COUNT - 1)) +//! Granularity of a medium allocation block +#define MEDIUM_GRANULARITY 512 +//! Medium granularity shift count +#define MEDIUM_GRANULARITY_SHIFT 9 +//! Number of medium block size classes +#define MEDIUM_CLASS_COUNT 61 +//! Total number of small + medium size classes +#define SIZE_CLASS_COUNT (SMALL_CLASS_COUNT + MEDIUM_CLASS_COUNT) +//! Number of large block size classes +#define LARGE_CLASS_COUNT 63 +//! Maximum size of a medium block +#define MEDIUM_SIZE_LIMIT (SMALL_SIZE_LIMIT + (MEDIUM_GRANULARITY * MEDIUM_CLASS_COUNT)) +//! Maximum size of a large block +#define LARGE_SIZE_LIMIT ((LARGE_CLASS_COUNT * _memory_span_size) - SPAN_HEADER_SIZE) +//! Size of a span header (must be a multiple of SMALL_GRANULARITY and a power of two) +#define SPAN_HEADER_SIZE 128 +//! Number of spans in thread cache +#define MAX_THREAD_SPAN_CACHE 400 +//! Number of spans to transfer between thread and global cache +#define THREAD_SPAN_CACHE_TRANSFER 64 +//! Number of spans in thread cache for large spans (must be greater than LARGE_CLASS_COUNT / 2) +#define MAX_THREAD_SPAN_LARGE_CACHE 100 +//! Number of spans to transfer between thread and global cache for large spans +#define THREAD_SPAN_LARGE_CACHE_TRANSFER 6 + +_Static_assert((SMALL_GRANULARITY & (SMALL_GRANULARITY - 1)) == 0, "Small granularity must be power of two"); +_Static_assert((SPAN_HEADER_SIZE & (SPAN_HEADER_SIZE - 1)) == 0, "Span header size must be power of two"); + +#if ENABLE_VALIDATE_ARGS +//! Maximum allocation size to avoid integer overflow +#undef MAX_ALLOC_SIZE +#define MAX_ALLOC_SIZE (((size_t)-1) - _memory_span_size) +#endif + +#define pointer_offset(ptr, ofs) (void *)((char *)(ptr) + (ptrdiff_t)(ofs)) +#define pointer_diff(first, second) (ptrdiff_t)((const char *)(first) - (const char *)(second)) + +#define INVALID_POINTER ((void *)((uintptr_t)-1)) + +#define SIZE_CLASS_LARGE SIZE_CLASS_COUNT +#define SIZE_CLASS_HUGE ((uint32_t)-1) + +//////////// +/// +/// Data types +/// +////// + +//! A memory heap, per thread +typedef struct heap_t heap_t; +//! Span of memory pages +typedef struct span_t span_t; +//! Span list +typedef struct span_list_t span_list_t; +//! Span active data +typedef struct span_active_t span_active_t; +//! Size class definition +typedef struct size_class_t size_class_t; +//! Global cache +typedef struct global_cache_t global_cache_t; + +//! Flag indicating span is the first (master) span of a split superspan +#define SPAN_FLAG_MASTER 1U +//! Flag indicating span is a secondary (sub) span of a split superspan +#define SPAN_FLAG_SUBSPAN 2U +//! Flag indicating span has blocks with increased alignment +#define SPAN_FLAG_ALIGNED_BLOCKS 4U +//! Flag indicating an unmapped master span +#define SPAN_FLAG_UNMAPPED_MASTER 8U + +#if ENABLE_ADAPTIVE_THREAD_CACHE || ENABLE_STATISTICS +struct span_use_t +{ + //! Current number of spans used (actually used, not in cache) + atomic32_t current; + //! High water mark of spans used + atomic32_t high; +#if ENABLE_STATISTICS + //! Number of spans in deferred list + atomic32_t spans_deferred; + //! Number of spans transitioned to global cache + atomic32_t spans_to_global; + //! Number of spans transitioned from global cache + atomic32_t spans_from_global; + //! Number of spans transitioned to thread cache + atomic32_t spans_to_cache; + //! Number of spans transitioned from thread cache + atomic32_t spans_from_cache; + //! Number of spans transitioned to reserved state + atomic32_t spans_to_reserved; + //! Number of spans transitioned from reserved state + atomic32_t spans_from_reserved; + //! Number of raw memory map calls + atomic32_t spans_map_calls; +#endif +}; +typedef struct span_use_t span_use_t; +#endif + +#if ENABLE_STATISTICS +struct size_class_use_t +{ + //! Current number of allocations + atomic32_t alloc_current; + //! Peak number of allocations + int32_t alloc_peak; + //! Total number of allocations + atomic32_t alloc_total; + //! Total number of frees + atomic32_t free_total; + //! Number of spans in use + atomic32_t spans_current; + //! Number of spans transitioned to cache + int32_t spans_peak; + //! Number of spans transitioned to cache + atomic32_t spans_to_cache; + //! Number of spans transitioned from cache + atomic32_t spans_from_cache; + //! Number of spans transitioned from reserved state + atomic32_t spans_from_reserved; + //! Number of spans mapped + atomic32_t spans_map_calls; + int32_t unused; +}; +typedef struct size_class_use_t size_class_use_t; +#endif + +// A span can either represent a single span of memory pages with size declared by span_map_count configuration variable, +// or a set of spans in a continuous region, a super span. Any reference to the term "span" usually refers to both a single +// span or a super span. A super span can further be divided into multiple spans (or this, super spans), where the first +// (super)span is the master and subsequent (super)spans are subspans. The master span keeps track of how many subspans +// that are still alive and mapped in virtual memory, and once all subspans and master have been unmapped the entire +// superspan region is released and unmapped (on Windows for example, the entire superspan range has to be released +// in the same call to release the virtual memory range, but individual subranges can be decommitted individually +// to reduce physical memory use). +struct span_t +{ + //! Free list + void *free_list; + //! Total block count of size class + uint32_t block_count; + //! Size class + uint32_t size_class; + //! Index of last block initialized in free list + uint32_t free_list_limit; + //! Number of used blocks remaining when in partial state + uint32_t used_count; + //! Deferred free list + atomicptr_t free_list_deferred; + //! Size of deferred free list, or list of spans when part of a cache list + uint32_t list_size; + //! Size of a block + uint32_t block_size; + //! Flags and counters + uint32_t flags; + //! Number of spans + uint32_t span_count; + //! Total span counter for master spans + uint32_t total_spans; + //! Offset from master span for subspans + uint32_t offset_from_master; + //! Remaining span counter, for master spans + atomic32_t remaining_spans; + //! Alignment offset + uint32_t align_offset; + //! Owning heap + heap_t *heap; + //! Next span + span_t *next; + //! Previous span + span_t *prev; +}; +_Static_assert(sizeof(span_t) <= SPAN_HEADER_SIZE, "span size mismatch"); + +struct span_cache_t +{ + size_t count; + span_t *span[MAX_THREAD_SPAN_CACHE]; +}; +typedef struct span_cache_t span_cache_t; + +struct span_large_cache_t +{ + size_t count; + span_t *span[MAX_THREAD_SPAN_LARGE_CACHE]; +}; +typedef struct span_large_cache_t span_large_cache_t; + +struct heap_size_class_t +{ + //! Free list of active span + void *free_list; + //! Double linked list of partially used spans with free blocks. + // Previous span pointer in head points to tail span of list. + span_t *partial_span; + //! Early level cache of fully free spans + span_t *cache; +}; +typedef struct heap_size_class_t heap_size_class_t; + +// Control structure for a heap, either a thread heap or a first class heap if enabled +struct heap_t +{ + //! Owning thread ID + uintptr_t owner_thread; + //! Free lists for each size class + heap_size_class_t size_class[SIZE_CLASS_COUNT]; +#if ENABLE_THREAD_CACHE + //! Arrays of fully freed spans, single span + span_cache_t span_cache; +#endif + //! List of deferred free spans (single linked list) + atomicptr_t span_free_deferred; + //! Number of full spans + size_t full_span_count; + //! Mapped but unused spans + span_t *span_reserve; + //! Master span for mapped but unused spans + span_t *span_reserve_master; + //! Number of mapped but unused spans + uint32_t spans_reserved; + //! Child count + atomic32_t child_count; + //! Next heap in id list + heap_t *next_heap; + //! Next heap in orphan list + heap_t *next_orphan; + //! Heap ID + int32_t id; + //! Finalization state flag + int finalize; + //! Master heap owning the memory pages + heap_t *master_heap; +#if ENABLE_THREAD_CACHE + //! Arrays of fully freed spans, large spans with > 1 span count + span_large_cache_t span_large_cache[LARGE_CLASS_COUNT - 1]; +#endif +#if RPMALLOC_FIRST_CLASS_HEAPS + //! Double linked list of fully utilized spans with free blocks for each size class. + // Previous span pointer in head points to tail span of list. + span_t *full_span[SIZE_CLASS_COUNT]; + //! Double linked list of large and huge spans allocated by this heap + span_t *large_huge_span; +#endif +#if ENABLE_ADAPTIVE_THREAD_CACHE || ENABLE_STATISTICS + //! Current and high water mark of spans used per span count + span_use_t span_use[LARGE_CLASS_COUNT]; +#endif +#if ENABLE_STATISTICS + //! Allocation stats per size class + size_class_use_t size_class_use[SIZE_CLASS_COUNT + 1]; + //! Number of bytes transitioned thread -> global + atomic64_t thread_to_global; + //! Number of bytes transitioned global -> thread + atomic64_t global_to_thread; +#endif +}; + +/* Keep in sync with heap_t inside rpmalloc_compat.cpp */ +static_assert(sizeof(heap_t) == 56408, "heap_t size mismatch"); + +// Size class for defining a block size bucket +struct size_class_t +{ + //! Size of blocks in this class + uint32_t block_size; + //! Number of blocks in each chunk + uint16_t block_count; + //! Class index this class is merged with + uint16_t class_idx; +}; +_Static_assert(sizeof(size_class_t) == 8, "Size class size mismatch"); + +struct global_cache_t +{ + //! Cache lock + atomic32_t lock; + //! Cache count + uint32_t count; +#if ENABLE_STATISTICS + //! Insert count + size_t insert_count; + //! Extract count + size_t extract_count; +#endif + //! Cached spans + span_t *span[GLOBAL_CACHE_MULTIPLIER * MAX_THREAD_SPAN_CACHE]; + //! Unlimited cache overflow + span_t *overflow; +}; + +//////////// +/// +/// Global data +/// +////// + +//! Default span size (64KiB) +#define _memory_default_span_size (64 * 1024) +#define _memory_default_span_size_shift 16 +#define _memory_default_span_mask (~((uintptr_t)(_memory_span_size - 1))) + +//! Initialized flag +static int _rpmalloc_initialized; +//! Main thread ID +static uintptr_t _rpmalloc_main_thread_id; +//! Configuration +static rpmalloc_config_t _memory_config; +//! Memory page size +static size_t _memory_page_size; +//! Shift to divide by page size +static size_t _memory_page_size_shift; +//! Granularity at which memory pages are mapped by OS +static size_t _memory_map_granularity; +#if RPMALLOC_CONFIGURABLE +//! Size of a span of memory pages +static size_t _memory_span_size; +//! Shift to divide by span size +static size_t _memory_span_size_shift; +//! Mask to get to start of a memory span +static uintptr_t _memory_span_mask; +#else +//! Hardwired span size +#define _memory_span_size _memory_default_span_size +#define _memory_span_size_shift _memory_default_span_size_shift +#define _memory_span_mask _memory_default_span_mask +#endif +//! Number of spans to map in each map call +static size_t _memory_span_map_count; +//! Number of spans to keep reserved in each heap +static size_t _memory_heap_reserve_count; +//! Global size classes +static size_class_t _memory_size_class[SIZE_CLASS_COUNT]; +//! Run-time size limit of medium blocks +static size_t _memory_medium_size_limit; +//! Heap ID counter +static atomic32_t _memory_heap_id; +//! Huge page support +static int _memory_huge_pages; +#if ENABLE_GLOBAL_CACHE +//! Global span cache +static global_cache_t _memory_span_cache[LARGE_CLASS_COUNT]; +#endif +//! Global reserved spans +static span_t *_memory_global_reserve; +//! Global reserved count +static size_t _memory_global_reserve_count; +//! Global reserved master +static span_t *_memory_global_reserve_master; +//! All heaps +static heap_t *_memory_heaps[HEAP_ARRAY_SIZE]; +//! Used to restrict access to mapping memory for huge pages +static atomic32_t _memory_global_lock; +//! Orphaned heaps +static heap_t *_memory_orphan_heaps; +#if RPMALLOC_FIRST_CLASS_HEAPS +//! Orphaned heaps (first class heaps) +static heap_t *_memory_first_class_orphan_heaps; +#endif +#if ENABLE_STATISTICS +//! Allocations counter +static atomic64_t _allocation_counter; +//! Deallocations counter +static atomic64_t _deallocation_counter; +//! Active heap count +static atomic32_t _memory_active_heaps; +//! Number of currently mapped memory pages +static atomic32_t _mapped_pages; +//! Peak number of concurrently mapped memory pages +static int32_t _mapped_pages_peak; +//! Number of mapped master spans +static atomic32_t _master_spans; +//! Number of unmapped dangling master spans +static atomic32_t _unmapped_master_spans; +//! Running counter of total number of mapped memory pages since start +static atomic32_t _mapped_total; +//! Running counter of total number of unmapped memory pages since start +static atomic32_t _unmapped_total; +//! Number of currently mapped memory pages in OS calls +static atomic32_t _mapped_pages_os; +//! Number of currently allocated pages in huge allocations +static atomic32_t _huge_pages_current; +//! Peak number of currently allocated pages in huge allocations +static int32_t _huge_pages_peak; +#endif + +//////////// +/// +/// Thread local heap and ID +/// +////// + +//! Current thread heap +#if ((defined(__APPLE__) || defined(__HAIKU__)) && ENABLE_PRELOAD) || defined(__TINYC__) +static pthread_key_t _memory_thread_heap; +#else +#ifdef _MSC_VER +#define _Thread_local __declspec(thread) +#define TLS_MODEL +#else +#ifndef __HAIKU__ +#define TLS_MODEL __attribute__((tls_model("initial-exec"))) +#else +#define TLS_MODEL +#endif +#if !defined(__clang__) && defined(__GNUC__) +#define _Thread_local __thread +#endif +#endif +// static _Thread_local heap_t *_memory_thread_heap TLS_MODEL; +extern heap_t **__memory_thread_heap(void); +#define _memory_thread_heap (*__memory_thread_heap()) +#endif + +static inline heap_t * +get_thread_heap_raw(void) +{ + return _memory_thread_heap; +} + +//! Get the current thread heap +static inline heap_t * +get_thread_heap(void) +{ + heap_t *heap = get_thread_heap_raw(); +#if ENABLE_PRELOAD + if (EXPECTED(heap != 0)) + return heap; + rpmalloc_initialize(); + return get_thread_heap_raw(); +#else + return heap; +#endif +} + +extern uintptr_t __get_tid(void); + +//! Fast thread ID +static inline uintptr_t +get_thread_id(void) { return __get_tid(); } + +//! Set the current thread heap +static void +set_thread_heap(heap_t *heap) +{ + _memory_thread_heap = heap; + if (heap) + heap->owner_thread = get_thread_id(); +} + +//! Set main thread ID +extern void +rpmalloc_set_main_thread(void); + +void rpmalloc_set_main_thread(void) +{ + _rpmalloc_main_thread_id = get_thread_id(); +} + +static void +_rpmalloc_spin(void) +{ +#if defined(_MSC_VER) + _mm_pause(); +#elif defined(__x86_64__) || defined(__i386__) + __asm__ volatile("pause" ::: "memory"); +#elif defined(__aarch64__) || (defined(__arm__) && __ARM_ARCH >= 7) + __asm__ volatile("yield" ::: "memory"); +#elif defined(__powerpc__) || defined(__powerpc64__) + // No idea if ever been compiled in such archs but ... as precaution + __asm__ volatile("or 27,27,27"); +#elif defined(__sparc__) + __asm__ volatile("rd %ccr, %g0 \n\trd %ccr, %g0 \n\trd %ccr, %g0"); +#else + struct timespec ts = {0}; + nanosleep(&ts, 0); +#endif +} + +//////////// +/// +/// Low level memory map/unmap +/// +////// + +static void +_rpmalloc_set_name(void *address, size_t size) +{ +#if defined(__linux__) || defined(__ANDROID__) + const char *name = _memory_huge_pages ? _memory_config.huge_page_name : _memory_config.page_name; + if (address == MAP_FAILED || !name) + return; + // If the kernel does not support CONFIG_ANON_VMA_NAME or if the call fails + // (e.g. invalid name) it is a no-op basically. + (void)prctl(PR_SET_VMA, PR_SET_VMA_ANON_NAME, (uintptr_t)address, size, (uintptr_t)name); +#else + (void)sizeof(size); + (void)sizeof(address); +#endif +} + +//! Map more virtual memory +// size is number of bytes to map +// offset receives the offset in bytes from start of mapped region +// returns address to start of mapped region to use +static void * +_rpmalloc_mmap(size_t size, size_t *offset) +{ + rpmalloc_assert(!(size % _memory_page_size), "Invalid mmap size"); + rpmalloc_assert(size >= _memory_page_size, "Invalid mmap size"); + void *address = _memory_config.memory_map(size, offset); + if (EXPECTED(address != 0)) + { + _rpmalloc_stat_add_peak(&_mapped_pages, (size >> _memory_page_size_shift), _mapped_pages_peak); + _rpmalloc_stat_add(&_mapped_total, (size >> _memory_page_size_shift)); + } + return address; +} + +//! Unmap virtual memory +// address is the memory address to unmap, as returned from _memory_map +// size is the number of bytes to unmap, which might be less than full region for a partial unmap +// offset is the offset in bytes to the actual mapped region, as set by _memory_map +// release is set to 0 for partial unmap, or size of entire range for a full unmap +static void +_rpmalloc_unmap(void *address, size_t size, size_t offset, size_t release) +{ + rpmalloc_assert(!release || (release >= size), "Invalid unmap size"); + rpmalloc_assert(!release || (release >= _memory_page_size), "Invalid unmap size"); + if (release) + { + rpmalloc_assert(!(release % _memory_page_size), "Invalid unmap size"); + _rpmalloc_stat_sub(&_mapped_pages, (release >> _memory_page_size_shift)); + _rpmalloc_stat_add(&_unmapped_total, (release >> _memory_page_size_shift)); + } + _memory_config.memory_unmap(address, size, offset, release); +} + +//! Default implementation to map new pages to virtual memory +static void * +_rpmalloc_mmap_os(size_t size, size_t *offset) +{ + // Either size is a heap (a single page) or a (multiple) span - we only need to align spans, and only if larger than map granularity + size_t padding = ((size >= _memory_span_size) && (_memory_span_size > _memory_map_granularity)) ? _memory_span_size : 0; + rpmalloc_assert(size >= _memory_page_size, "Invalid mmap size"); + + int flags = MAP_PRIVATE | MAP_ANONYMOUS | MAP_UNINITIALIZED; + void *ptr = __rpmalloc_mmap(0, size + padding, PROT_READ | PROT_WRITE, flags, -1, 0); + + if ((ptr == MAP_FAILED) || !ptr) + { + if (_memory_config.map_fail_callback) + { + if (_memory_config.map_fail_callback(size + padding)) + return _rpmalloc_mmap_os(size, offset); + } + else if (errno != ENOMEM) + { + rpmalloc_assert((ptr != MAP_FAILED) && ptr, "Failed to map virtual memory block"); + } + return 0; + } + + _rpmalloc_stat_add(&_mapped_pages_os, (int32_t)((size + padding) >> _memory_page_size_shift)); + if (padding) + { + size_t final_padding = padding - ((uintptr_t)ptr & ~_memory_span_mask); + rpmalloc_assert(final_padding <= _memory_span_size, "Internal failure in padding"); + rpmalloc_assert(final_padding <= padding, "Internal failure in padding"); + rpmalloc_assert(!(final_padding % 8), "Internal failure in padding"); + ptr = pointer_offset(ptr, final_padding); + *offset = final_padding >> 3; + } + rpmalloc_assert((size < _memory_span_size) || !((uintptr_t)ptr & ~_memory_span_mask), "Internal failure in padding"); + return ptr; +} + +//! Default implementation to unmap pages from virtual memory +static void +_rpmalloc_unmap_os(void *address, size_t size, size_t offset, size_t release) +{ + rpmalloc_assert(release || (offset == 0), "Invalid unmap size"); + rpmalloc_assert(!release || (release >= _memory_page_size), "Invalid unmap size"); + rpmalloc_assert(size >= _memory_page_size, "Invalid unmap size"); + if (release && offset) + { + offset <<= 3; + address = pointer_offset(address, -(int32_t)offset); + if ((release >= _memory_span_size) && (_memory_span_size > _memory_map_granularity)) + { + // Padding is always one span size + release += _memory_span_size; + } + } +#if !DISABLE_UNMAP + if (release) + { + if (__rpmalloc_munmap(address, release)) + { + rpmalloc_assert(0, "Failed to unmap virtual memory block"); + } + } + else + { + if (__rpmalloc_posix_madvise(address, size, POSIX_MADV_DONTNEED)) + { + rpmalloc_assert(0, "Failed to madvise virtual memory block as free"); + } + } +#endif + if (release) + _rpmalloc_stat_sub(&_mapped_pages_os, release >> _memory_page_size_shift); +} + +static void +_rpmalloc_span_mark_as_subspan_unless_master(span_t *master, span_t *subspan, size_t span_count); + +//! Use global reserved spans to fulfill a memory map request (reserve size must be checked by caller) +static span_t * +_rpmalloc_global_get_reserved_spans(size_t span_count) +{ + span_t *span = _memory_global_reserve; + _rpmalloc_span_mark_as_subspan_unless_master(_memory_global_reserve_master, span, span_count); + _memory_global_reserve_count -= span_count; + if (_memory_global_reserve_count) + _memory_global_reserve = (span_t *)pointer_offset(span, span_count << _memory_span_size_shift); + else + _memory_global_reserve = 0; + return span; +} + +//! Store the given spans as global reserve (must only be called from within new heap allocation, not thread safe) +static void +_rpmalloc_global_set_reserved_spans(span_t *master, span_t *reserve, size_t reserve_span_count) +{ + _memory_global_reserve_master = master; + _memory_global_reserve_count = reserve_span_count; + _memory_global_reserve = reserve; +} + +//////////// +/// +/// Span linked list management +/// +////// + +//! Add a span to double linked list at the head +static void +_rpmalloc_span_double_link_list_add(span_t **head, span_t *span) +{ + if (*head) + (*head)->prev = span; + span->next = *head; + *head = span; +} + +//! Pop head span from double linked list +static void +_rpmalloc_span_double_link_list_pop_head(span_t **head, span_t *span) +{ + rpmalloc_assert(*head == span, "Linked list corrupted"); + span = *head; + *head = span->next; +} + +//! Remove a span from double linked list +static void +_rpmalloc_span_double_link_list_remove(span_t **head, span_t *span) +{ + rpmalloc_assert(*head, "Linked list corrupted"); + if (*head == span) + { + *head = span->next; + } + else + { + span_t *next_span = span->next; + span_t *prev_span = span->prev; + prev_span->next = next_span; + if (EXPECTED(next_span != 0)) + next_span->prev = prev_span; + } +} + +//////////// +/// +/// Span control +/// +////// + +static void +_rpmalloc_heap_cache_insert(heap_t *heap, span_t *span); + +static void +_rpmalloc_heap_finalize(heap_t *heap); + +static void +_rpmalloc_heap_set_reserved_spans(heap_t *heap, span_t *master, span_t *reserve, size_t reserve_span_count); + +//! Declare the span to be a subspan and store distance from master span and span count +static void +_rpmalloc_span_mark_as_subspan_unless_master(span_t *master, span_t *subspan, size_t span_count) +{ + rpmalloc_assert((subspan != master) || (subspan->flags & SPAN_FLAG_MASTER), "Span master pointer and/or flag mismatch"); + if (subspan != master) + { + subspan->flags = SPAN_FLAG_SUBSPAN; + subspan->offset_from_master = (uint32_t)((uintptr_t)pointer_diff(subspan, master) >> _memory_span_size_shift); + subspan->align_offset = 0; + } + subspan->span_count = (uint32_t)span_count; +} + +//! Use reserved spans to fulfill a memory map request (reserve size must be checked by caller) +static span_t * +_rpmalloc_span_map_from_reserve(heap_t *heap, size_t span_count) +{ + // Update the heap span reserve + span_t *span = heap->span_reserve; + heap->span_reserve = (span_t *)pointer_offset(span, span_count * _memory_span_size); + heap->spans_reserved -= (uint32_t)span_count; + + _rpmalloc_span_mark_as_subspan_unless_master(heap->span_reserve_master, span, span_count); + if (span_count <= LARGE_CLASS_COUNT) + _rpmalloc_stat_inc(&heap->span_use[span_count - 1].spans_from_reserved); + + return span; +} + +//! Get the aligned number of spans to map in based on wanted count, configured mapping granularity and the page size +static size_t +_rpmalloc_span_align_count(size_t span_count) +{ + size_t request_count = (span_count > _memory_span_map_count) ? span_count : _memory_span_map_count; + if ((_memory_page_size > _memory_span_size) && ((request_count * _memory_span_size) % _memory_page_size)) + request_count += _memory_span_map_count - (request_count % _memory_span_map_count); + return request_count; +} + +//! Setup a newly mapped span +static void +_rpmalloc_span_initialize(span_t *span, size_t total_span_count, size_t span_count, size_t align_offset) +{ + span->total_spans = (uint32_t)total_span_count; + span->span_count = (uint32_t)span_count; + span->align_offset = (uint32_t)align_offset; + span->flags = SPAN_FLAG_MASTER; + atomic_store32(&span->remaining_spans, (int32_t)total_span_count); +} + +static void +_rpmalloc_span_unmap(span_t *span); + +//! Map an aligned set of spans, taking configured mapping granularity and the page size into account +static span_t * +_rpmalloc_span_map_aligned_count(heap_t *heap, size_t span_count) +{ + // If we already have some, but not enough, reserved spans, release those to heap cache and map a new + // full set of spans. Otherwise we would waste memory if page size > span size (huge pages) + size_t aligned_span_count = _rpmalloc_span_align_count(span_count); + size_t align_offset = 0; + span_t *span = (span_t *)_rpmalloc_mmap(aligned_span_count * _memory_span_size, &align_offset); + if (!span) + return 0; + _rpmalloc_span_initialize(span, aligned_span_count, span_count, align_offset); + _rpmalloc_stat_inc(&_master_spans); + if (span_count <= LARGE_CLASS_COUNT) + _rpmalloc_stat_inc(&heap->span_use[span_count - 1].spans_map_calls); + if (aligned_span_count > span_count) + { + span_t *reserved_spans = (span_t *)pointer_offset(span, span_count * _memory_span_size); + size_t reserved_count = aligned_span_count - span_count; + if (heap->spans_reserved) + { + _rpmalloc_span_mark_as_subspan_unless_master(heap->span_reserve_master, heap->span_reserve, heap->spans_reserved); + _rpmalloc_heap_cache_insert(heap, heap->span_reserve); + } + if (reserved_count > _memory_heap_reserve_count) + { + // If huge pages or eager spam map count, the global reserve spin lock is held by caller, _rpmalloc_span_map + rpmalloc_assert(atomic_load32(&_memory_global_lock) == 1, "Global spin lock not held as expected"); + size_t remain_count = reserved_count - _memory_heap_reserve_count; + reserved_count = _memory_heap_reserve_count; + span_t *remain_span = (span_t *)pointer_offset(reserved_spans, reserved_count * _memory_span_size); + if (_memory_global_reserve) + { + _rpmalloc_span_mark_as_subspan_unless_master(_memory_global_reserve_master, _memory_global_reserve, _memory_global_reserve_count); + _rpmalloc_span_unmap(_memory_global_reserve); + } + _rpmalloc_global_set_reserved_spans(span, remain_span, remain_count); + } + _rpmalloc_heap_set_reserved_spans(heap, span, reserved_spans, reserved_count); + } + return span; +} + +//! Map in memory pages for the given number of spans (or use previously reserved pages) +static span_t * +_rpmalloc_span_map(heap_t *heap, size_t span_count) +{ + if (span_count <= heap->spans_reserved) + return _rpmalloc_span_map_from_reserve(heap, span_count); + span_t *span = 0; + int use_global_reserve = (_memory_page_size > _memory_span_size) || (_memory_span_map_count > _memory_heap_reserve_count); + if (use_global_reserve) + { + // If huge pages, make sure only one thread maps more memory to avoid bloat + while (!atomic_cas32_acquire(&_memory_global_lock, 1, 0)) + _rpmalloc_spin(); + if (_memory_global_reserve_count >= span_count) + { + size_t reserve_count = (!heap->spans_reserved ? _memory_heap_reserve_count : span_count); + if (_memory_global_reserve_count < reserve_count) + reserve_count = _memory_global_reserve_count; + span = _rpmalloc_global_get_reserved_spans(reserve_count); + if (span) + { + if (reserve_count > span_count) + { + span_t *reserved_span = (span_t *)pointer_offset(span, span_count << _memory_span_size_shift); + _rpmalloc_heap_set_reserved_spans(heap, _memory_global_reserve_master, reserved_span, reserve_count - span_count); + } + // Already marked as subspan in _rpmalloc_global_get_reserved_spans + span->span_count = (uint32_t)span_count; + } + } + } + if (!span) + span = _rpmalloc_span_map_aligned_count(heap, span_count); + if (use_global_reserve) + atomic_store32_release(&_memory_global_lock, 0); + return span; +} + +//! Unmap memory pages for the given number of spans (or mark as unused if no partial unmappings) +static void +_rpmalloc_span_unmap(span_t *span) +{ + rpmalloc_assert((span->flags & SPAN_FLAG_MASTER) || (span->flags & SPAN_FLAG_SUBSPAN), "Span flag corrupted"); + rpmalloc_assert(!(span->flags & SPAN_FLAG_MASTER) || !(span->flags & SPAN_FLAG_SUBSPAN), "Span flag corrupted"); + + int is_master = !!(span->flags & SPAN_FLAG_MASTER); + span_t *master = is_master ? span : ((span_t *)pointer_offset(span, -(intptr_t)((uintptr_t)span->offset_from_master * _memory_span_size))); + rpmalloc_assert(is_master || (span->flags & SPAN_FLAG_SUBSPAN), "Span flag corrupted"); + rpmalloc_assert(master->flags & SPAN_FLAG_MASTER, "Span flag corrupted"); + + size_t span_count = span->span_count; + if (!is_master) + { + // Directly unmap subspans (unless huge pages, in which case we defer and unmap entire page range with master) + rpmalloc_assert(span->align_offset == 0, "Span align offset corrupted"); + if (_memory_span_size >= _memory_page_size) + _rpmalloc_unmap(span, span_count * _memory_span_size, 0, 0); + } + else + { + // Special double flag to denote an unmapped master + // It must be kept in memory since span header must be used + span->flags |= SPAN_FLAG_MASTER | SPAN_FLAG_SUBSPAN | SPAN_FLAG_UNMAPPED_MASTER; + _rpmalloc_stat_add(&_unmapped_master_spans, 1); + } + + if (atomic_add32(&master->remaining_spans, -(int32_t)span_count) <= 0) + { + // Everything unmapped, unmap the master span with release flag to unmap the entire range of the super span + rpmalloc_assert(!!(master->flags & SPAN_FLAG_MASTER) && !!(master->flags & SPAN_FLAG_SUBSPAN), "Span flag corrupted"); + size_t unmap_count = master->span_count; + if (_memory_span_size < _memory_page_size) + unmap_count = master->total_spans; + _rpmalloc_stat_sub(&_master_spans, 1); + _rpmalloc_stat_sub(&_unmapped_master_spans, 1); + _rpmalloc_unmap(master, unmap_count * _memory_span_size, master->align_offset, (size_t)master->total_spans * _memory_span_size); + } +} + +//! Move the span (used for small or medium allocations) to the heap thread cache +static void +_rpmalloc_span_release_to_cache(heap_t *heap, span_t *span) +{ + rpmalloc_assert(heap == span->heap, "Span heap pointer corrupted"); + rpmalloc_assert(span->size_class < SIZE_CLASS_COUNT, "Invalid span size class"); + rpmalloc_assert(span->span_count == 1, "Invalid span count"); +#if ENABLE_ADAPTIVE_THREAD_CACHE || ENABLE_STATISTICS + atomic_decr32(&heap->span_use[0].current); +#endif + _rpmalloc_stat_dec(&heap->size_class_use[span->size_class].spans_current); + if (!heap->finalize) + { + _rpmalloc_stat_inc(&heap->span_use[0].spans_to_cache); + _rpmalloc_stat_inc(&heap->size_class_use[span->size_class].spans_to_cache); + if (heap->size_class[span->size_class].cache) + _rpmalloc_heap_cache_insert(heap, heap->size_class[span->size_class].cache); + heap->size_class[span->size_class].cache = span; + } + else + { + _rpmalloc_span_unmap(span); + } +} + +//! Initialize a (partial) free list up to next system memory page, while reserving the first block +//! as allocated, returning number of blocks in list +static uint32_t +free_list_partial_init(void **list, void **first_block, void *page_start, void *block_start, uint32_t block_count, uint32_t block_size) +{ + rpmalloc_assert(block_count, "Internal failure"); + *first_block = block_start; + if (block_count > 1) + { + void *free_block = pointer_offset(block_start, block_size); + void *block_end = pointer_offset(block_start, (size_t)block_size * block_count); + // If block size is less than half a memory page, bound init to next memory page boundary + if (block_size < (_memory_page_size >> 1)) + { + void *page_end = pointer_offset(page_start, _memory_page_size); + if (page_end < block_end) + block_end = page_end; + } + *list = free_block; + block_count = 2; + void *next_block = pointer_offset(free_block, block_size); + while (next_block < block_end) + { + *((void **)free_block) = next_block; + free_block = next_block; + ++block_count; + next_block = pointer_offset(next_block, block_size); + } + *((void **)free_block) = 0; + } + else + { + *list = 0; + } + return block_count; +} + +//! Initialize an unused span (from cache or mapped) to be new active span, putting the initial free list in heap class free list +static void * +_rpmalloc_span_initialize_new(heap_t *heap, heap_size_class_t *heap_size_class, span_t *span, uint32_t class_idx) +{ + rpmalloc_assert(span->span_count == 1, "Internal failure"); + size_class_t *size_class = _memory_size_class + class_idx; + span->size_class = class_idx; + span->heap = heap; + span->flags &= ~SPAN_FLAG_ALIGNED_BLOCKS; + span->block_size = size_class->block_size; + span->block_count = size_class->block_count; + span->free_list = 0; + span->list_size = 0; + atomic_store_ptr_release(&span->free_list_deferred, 0); + + // Setup free list. Only initialize one system page worth of free blocks in list + void *block; + span->free_list_limit = free_list_partial_init(&heap_size_class->free_list, &block, + span, pointer_offset(span, SPAN_HEADER_SIZE), size_class->block_count, size_class->block_size); + // Link span as partial if there remains blocks to be initialized as free list, or full if fully initialized + if (span->free_list_limit < span->block_count) + { + _rpmalloc_span_double_link_list_add(&heap_size_class->partial_span, span); + span->used_count = span->free_list_limit; + } + else + { +#if RPMALLOC_FIRST_CLASS_HEAPS + _rpmalloc_span_double_link_list_add(&heap->full_span[class_idx], span); +#endif + ++heap->full_span_count; + span->used_count = span->block_count; + } + return block; +} + +static void +_rpmalloc_span_extract_free_list_deferred(span_t *span) +{ + // We need acquire semantics on the CAS operation since we are interested in the list size + // Refer to _rpmalloc_deallocate_defer_small_or_medium for further comments on this dependency + do + { + span->free_list = atomic_exchange_ptr_acquire(&span->free_list_deferred, INVALID_POINTER); + } while (span->free_list == INVALID_POINTER); + span->used_count -= span->list_size; + span->list_size = 0; + atomic_store_ptr_release(&span->free_list_deferred, 0); +} + +static int +_rpmalloc_span_is_fully_utilized(span_t *span) +{ + rpmalloc_assert(span->free_list_limit <= span->block_count, "Span free list corrupted"); + return !span->free_list && (span->free_list_limit >= span->block_count); +} + +static int +_rpmalloc_span_finalize(heap_t *heap, size_t iclass, span_t *span, span_t **list_head) +{ + void *free_list = heap->size_class[iclass].free_list; + span_t *class_span = (span_t *)((uintptr_t)free_list & _memory_span_mask); + if (span == class_span) + { + // Adopt the heap class free list back into the span free list + void *block = span->free_list; + void *last_block = 0; + while (block) + { + last_block = block; + block = *((void **)block); + } + uint32_t free_count = 0; + block = free_list; + while (block) + { + ++free_count; + block = *((void **)block); + } + if (last_block) + { + *((void **)last_block) = free_list; + } + else + { + span->free_list = free_list; + } + heap->size_class[iclass].free_list = 0; + span->used_count -= free_count; + } + // If this assert triggers you have memory leaks + rpmalloc_assert(span->list_size == span->used_count, "Memory leak detected"); + if (span->list_size == span->used_count) + { + _rpmalloc_stat_dec(&heap->span_use[0].current); + _rpmalloc_stat_dec(&heap->size_class_use[iclass].spans_current); + // This function only used for spans in double linked lists + if (list_head) + _rpmalloc_span_double_link_list_remove(list_head, span); + _rpmalloc_span_unmap(span); + return 1; + } + return 0; +} + +//////////// +/// +/// Global cache +/// +////// + +#if ENABLE_GLOBAL_CACHE + +//! Finalize a global cache +static void +_rpmalloc_global_cache_finalize(global_cache_t *cache) +{ + while (!atomic_cas32_acquire(&cache->lock, 1, 0)) + _rpmalloc_spin(); + + for (size_t ispan = 0; ispan < cache->count; ++ispan) + _rpmalloc_span_unmap(cache->span[ispan]); + cache->count = 0; + + while (cache->overflow) + { + span_t *span = cache->overflow; + cache->overflow = span->next; + _rpmalloc_span_unmap(span); + } + + atomic_store32_release(&cache->lock, 0); +} + +static void +_rpmalloc_global_cache_insert_spans(span_t **span, size_t span_count, size_t count) +{ + const size_t cache_limit = (span_count == 1) ? GLOBAL_CACHE_MULTIPLIER * MAX_THREAD_SPAN_CACHE : GLOBAL_CACHE_MULTIPLIER * (MAX_THREAD_SPAN_LARGE_CACHE - (span_count >> 1)); + + global_cache_t *cache = &_memory_span_cache[span_count - 1]; + + size_t insert_count = count; + while (!atomic_cas32_acquire(&cache->lock, 1, 0)) + _rpmalloc_spin(); + +#if ENABLE_STATISTICS + cache->insert_count += count; +#endif + if ((cache->count + insert_count) > cache_limit) + insert_count = cache_limit - cache->count; + + memcpy_unsafe(cache->span + cache->count, span, sizeof(span_t *) * insert_count); + cache->count += (uint32_t)insert_count; + +#if ENABLE_UNLIMITED_CACHE + while (insert_count < count) + { +#else + // Enable unlimited cache if huge pages, or we will leak since it is unlikely that an entire huge page + // will be unmapped, and we're unable to partially decommit a huge page + while ((_memory_page_size > _memory_span_size) && (insert_count < count)) + { +#endif + span_t *current_span = span[insert_count++]; + current_span->next = cache->overflow; + cache->overflow = current_span; + } + atomic_store32_release(&cache->lock, 0); + + span_t *keep = 0; + for (size_t ispan = insert_count; ispan < count; ++ispan) + { + span_t *current_span = span[ispan]; + // Keep master spans that has remaining subspans to avoid dangling them + if ((current_span->flags & SPAN_FLAG_MASTER) && + (atomic_load32(¤t_span->remaining_spans) > (int32_t)current_span->span_count)) + { + current_span->next = keep; + keep = current_span; + } + else + { + _rpmalloc_span_unmap(current_span); + } + } + + if (keep) + { + while (!atomic_cas32_acquire(&cache->lock, 1, 0)) + _rpmalloc_spin(); + + size_t islot = 0; + while (keep) + { + for (; islot < cache->count; ++islot) + { + span_t *current_span = cache->span[islot]; + if (!(current_span->flags & SPAN_FLAG_MASTER) || ((current_span->flags & SPAN_FLAG_MASTER) && + (atomic_load32(¤t_span->remaining_spans) <= (int32_t)current_span->span_count))) + { + _rpmalloc_span_unmap(current_span); + cache->span[islot] = keep; + break; + } + } + if (islot == cache->count) + break; + keep = keep->next; + } + + if (keep) + { + span_t *tail = keep; + while (tail->next) + tail = tail->next; + tail->next = cache->overflow; + cache->overflow = keep; + } + + atomic_store32_release(&cache->lock, 0); + } +} + +static size_t +_rpmalloc_global_cache_extract_spans(span_t **span, size_t span_count, size_t count) +{ + global_cache_t *cache = &_memory_span_cache[span_count - 1]; + + size_t extract_count = 0; + while (!atomic_cas32_acquire(&cache->lock, 1, 0)) + _rpmalloc_spin(); + +#if ENABLE_STATISTICS + cache->extract_count += count; +#endif + size_t want = count - extract_count; + if (want > cache->count) + want = cache->count; + + memcpy_unsafe(span + extract_count, cache->span + (cache->count - want), sizeof(span_t *) * want); + cache->count -= (uint32_t)want; + extract_count += want; + + while ((extract_count < count) && cache->overflow) + { + span_t *current_span = cache->overflow; + span[extract_count++] = current_span; + cache->overflow = current_span->next; + } + +#if ENABLE_ASSERTS + for (size_t ispan = 0; ispan < extract_count; ++ispan) + { + assert(span[ispan]->span_count == span_count); + } +#endif + + atomic_store32_release(&cache->lock, 0); + + return extract_count; +} + +#endif + +//////////// +/// +/// Heap control +/// +////// + +static void _rpmalloc_deallocate_huge(span_t *); + +//! Store the given spans as reserve in the given heap +static void +_rpmalloc_heap_set_reserved_spans(heap_t *heap, span_t *master, span_t *reserve, size_t reserve_span_count) +{ + heap->span_reserve_master = master; + heap->span_reserve = reserve; + heap->spans_reserved = (uint32_t)reserve_span_count; +} + +//! Adopt the deferred span cache list, optionally extracting the first single span for immediate re-use +static void +_rpmalloc_heap_cache_adopt_deferred(heap_t *heap, span_t **single_span) +{ + span_t *span = (span_t *)((void *)atomic_exchange_ptr_acquire(&heap->span_free_deferred, 0)); + while (span) + { + span_t *next_span = (span_t *)span->free_list; + rpmalloc_assert(span->heap == heap, "Span heap pointer corrupted"); + if (EXPECTED(span->size_class < SIZE_CLASS_COUNT)) + { + rpmalloc_assert(heap->full_span_count, "Heap span counter corrupted"); + --heap->full_span_count; + _rpmalloc_stat_dec(&heap->span_use[0].spans_deferred); +#if RPMALLOC_FIRST_CLASS_HEAPS + _rpmalloc_span_double_link_list_remove(&heap->full_span[span->size_class], span); +#endif + _rpmalloc_stat_dec(&heap->span_use[0].current); + _rpmalloc_stat_dec(&heap->size_class_use[span->size_class].spans_current); + if (single_span && !*single_span) + *single_span = span; + else + _rpmalloc_heap_cache_insert(heap, span); + } + else + { + if (span->size_class == SIZE_CLASS_HUGE) + { + _rpmalloc_deallocate_huge(span); + } + else + { + rpmalloc_assert(span->size_class == SIZE_CLASS_LARGE, "Span size class invalid"); + rpmalloc_assert(heap->full_span_count, "Heap span counter corrupted"); + --heap->full_span_count; +#if RPMALLOC_FIRST_CLASS_HEAPS + _rpmalloc_span_double_link_list_remove(&heap->large_huge_span, span); +#endif + uint32_t idx = span->span_count - 1; + _rpmalloc_stat_dec(&heap->span_use[idx].spans_deferred); + _rpmalloc_stat_dec(&heap->span_use[idx].current); + if (!idx && single_span && !*single_span) + *single_span = span; + else + _rpmalloc_heap_cache_insert(heap, span); + } + } + span = next_span; + } +} + +static void +_rpmalloc_heap_unmap(heap_t *heap) +{ + if (!heap->master_heap) + { + if ((heap->finalize > 1) && !atomic_load32(&heap->child_count)) + { + span_t *span = (span_t *)((uintptr_t)heap & _memory_span_mask); + _rpmalloc_span_unmap(span); + } + } + else + { + if (atomic_decr32(&heap->master_heap->child_count) == 0) + { + _rpmalloc_heap_unmap(heap->master_heap); + } + } +} + +static void +_rpmalloc_heap_global_finalize(heap_t *heap) +{ + if (heap->finalize++ > 1) + { + --heap->finalize; + return; + } + + _rpmalloc_heap_finalize(heap); + +#if ENABLE_THREAD_CACHE + for (size_t iclass = 0; iclass < LARGE_CLASS_COUNT; ++iclass) + { + span_cache_t *span_cache; + if (!iclass) + span_cache = &heap->span_cache; + else + span_cache = (span_cache_t *)(heap->span_large_cache + (iclass - 1)); + for (size_t ispan = 0; ispan < span_cache->count; ++ispan) + _rpmalloc_span_unmap(span_cache->span[ispan]); + span_cache->count = 0; + } +#endif + + if (heap->full_span_count) + { + --heap->finalize; + return; + } + + for (size_t iclass = 0; iclass < SIZE_CLASS_COUNT; ++iclass) + { + if (heap->size_class[iclass].free_list || heap->size_class[iclass].partial_span) + { + --heap->finalize; + return; + } + } + // Heap is now completely free, unmap and remove from heap list + size_t list_idx = (size_t)heap->id % HEAP_ARRAY_SIZE; + heap_t *list_heap = _memory_heaps[list_idx]; + if (list_heap == heap) + { + _memory_heaps[list_idx] = heap->next_heap; + } + else + { + while (list_heap->next_heap != heap) + list_heap = list_heap->next_heap; + list_heap->next_heap = heap->next_heap; + } + + _rpmalloc_heap_unmap(heap); +} + +//! Insert a single span into thread heap cache, releasing to global cache if overflow +static void +_rpmalloc_heap_cache_insert(heap_t *heap, span_t *span) +{ + if (UNEXPECTED(heap->finalize != 0)) + { + _rpmalloc_span_unmap(span); + _rpmalloc_heap_global_finalize(heap); + return; + } +#if ENABLE_THREAD_CACHE + size_t span_count = span->span_count; + _rpmalloc_stat_inc(&heap->span_use[span_count - 1].spans_to_cache); + if (span_count == 1) + { + span_cache_t *span_cache = &heap->span_cache; + span_cache->span[span_cache->count++] = span; + if (span_cache->count == MAX_THREAD_SPAN_CACHE) + { + const size_t remain_count = MAX_THREAD_SPAN_CACHE - THREAD_SPAN_CACHE_TRANSFER; +#if ENABLE_GLOBAL_CACHE + _rpmalloc_stat_add64(&heap->thread_to_global, THREAD_SPAN_CACHE_TRANSFER * _memory_span_size); + _rpmalloc_stat_add(&heap->span_use[span_count - 1].spans_to_global, THREAD_SPAN_CACHE_TRANSFER); + _rpmalloc_global_cache_insert_spans(span_cache->span + remain_count, span_count, THREAD_SPAN_CACHE_TRANSFER); +#else + for (size_t ispan = 0; ispan < THREAD_SPAN_CACHE_TRANSFER; ++ispan) + _rpmalloc_span_unmap(span_cache->span[remain_count + ispan]); +#endif + span_cache->count = remain_count; + } + } + else + { + size_t cache_idx = span_count - 2; + span_large_cache_t *span_cache = heap->span_large_cache + cache_idx; + span_cache->span[span_cache->count++] = span; + const size_t cache_limit = (MAX_THREAD_SPAN_LARGE_CACHE - (span_count >> 1)); + if (span_cache->count == cache_limit) + { + const size_t transfer_limit = 2 + (cache_limit >> 2); + const size_t transfer_count = (THREAD_SPAN_LARGE_CACHE_TRANSFER <= transfer_limit ? THREAD_SPAN_LARGE_CACHE_TRANSFER : transfer_limit); + const size_t remain_count = cache_limit - transfer_count; +#if ENABLE_GLOBAL_CACHE + _rpmalloc_stat_add64(&heap->thread_to_global, transfer_count * span_count * _memory_span_size); + _rpmalloc_stat_add(&heap->span_use[span_count - 1].spans_to_global, transfer_count); + _rpmalloc_global_cache_insert_spans(span_cache->span + remain_count, span_count, transfer_count); +#else + for (size_t ispan = 0; ispan < transfer_count; ++ispan) + _rpmalloc_span_unmap(span_cache->span[remain_count + ispan]); +#endif + span_cache->count = remain_count; + } + } +#else + (void)sizeof(heap); + _rpmalloc_span_unmap(span); +#endif +} + +//! Extract the given number of spans from the different cache levels +static span_t * +_rpmalloc_heap_thread_cache_extract(heap_t *heap, size_t span_count) +{ + span_t *span = 0; +#if ENABLE_THREAD_CACHE + span_cache_t *span_cache; + if (span_count == 1) + span_cache = &heap->span_cache; + else + span_cache = (span_cache_t *)(heap->span_large_cache + (span_count - 2)); + if (span_cache->count) + { + _rpmalloc_stat_inc(&heap->span_use[span_count - 1].spans_from_cache); + return span_cache->span[--span_cache->count]; + } +#endif + return span; +} + +static span_t * +_rpmalloc_heap_thread_cache_deferred_extract(heap_t *heap, size_t span_count) +{ + span_t *span = 0; + if (span_count == 1) + { + _rpmalloc_heap_cache_adopt_deferred(heap, &span); + } + else + { + _rpmalloc_heap_cache_adopt_deferred(heap, 0); + span = _rpmalloc_heap_thread_cache_extract(heap, span_count); + } + return span; +} + +static span_t * +_rpmalloc_heap_reserved_extract(heap_t *heap, size_t span_count) +{ + if (heap->spans_reserved >= span_count) + return _rpmalloc_span_map(heap, span_count); + return 0; +} + +//! Extract a span from the global cache +static span_t * +_rpmalloc_heap_global_cache_extract(heap_t *heap, size_t span_count) +{ +#if ENABLE_GLOBAL_CACHE +#if ENABLE_THREAD_CACHE + span_cache_t *span_cache; + size_t wanted_count; + if (span_count == 1) + { + span_cache = &heap->span_cache; + wanted_count = THREAD_SPAN_CACHE_TRANSFER; + } + else + { + span_cache = (span_cache_t *)(heap->span_large_cache + (span_count - 2)); + wanted_count = THREAD_SPAN_LARGE_CACHE_TRANSFER; + } + span_cache->count = _rpmalloc_global_cache_extract_spans(span_cache->span, span_count, wanted_count); + if (span_cache->count) + { + _rpmalloc_stat_add64(&heap->global_to_thread, span_count * span_cache->count * _memory_span_size); + _rpmalloc_stat_add(&heap->span_use[span_count - 1].spans_from_global, span_cache->count); + return span_cache->span[--span_cache->count]; + } +#else + span_t *span = 0; + size_t count = _rpmalloc_global_cache_extract_spans(&span, span_count, 1); + if (count) + { + _rpmalloc_stat_add64(&heap->global_to_thread, span_count * count * _memory_span_size); + _rpmalloc_stat_add(&heap->span_use[span_count - 1].spans_from_global, count); + return span; + } +#endif +#endif + (void)sizeof(heap); + (void)sizeof(span_count); + return 0; +} + +static void +_rpmalloc_inc_span_statistics(heap_t *heap, size_t span_count, uint32_t class_idx) +{ + (void)sizeof(heap); + (void)sizeof(span_count); + (void)sizeof(class_idx); +#if ENABLE_ADAPTIVE_THREAD_CACHE || ENABLE_STATISTICS + uint32_t idx = (uint32_t)span_count - 1; + uint32_t current_count = (uint32_t)atomic_incr32(&heap->span_use[idx].current); + if (current_count > (uint32_t)atomic_load32(&heap->span_use[idx].high)) + atomic_store32(&heap->span_use[idx].high, (int32_t)current_count); + _rpmalloc_stat_add_peak(&heap->size_class_use[class_idx].spans_current, 1, heap->size_class_use[class_idx].spans_peak); +#endif +} + +//! Get a span from one of the cache levels (thread cache, reserved, global cache) or fallback to mapping more memory +static span_t * +_rpmalloc_heap_extract_new_span(heap_t *heap, heap_size_class_t *heap_size_class, size_t span_count, uint32_t class_idx) +{ + span_t *span; +#if ENABLE_THREAD_CACHE + if (heap_size_class && heap_size_class->cache) + { + span = heap_size_class->cache; + heap_size_class->cache = (heap->span_cache.count ? heap->span_cache.span[--heap->span_cache.count] : 0); + _rpmalloc_inc_span_statistics(heap, span_count, class_idx); + return span; + } +#endif + (void)sizeof(class_idx); + // Allow 50% overhead to increase cache hits + size_t base_span_count = span_count; + size_t limit_span_count = (span_count > 2) ? (span_count + (span_count >> 1)) : span_count; + if (limit_span_count > LARGE_CLASS_COUNT) + limit_span_count = LARGE_CLASS_COUNT; + do + { + span = _rpmalloc_heap_thread_cache_extract(heap, span_count); + if (EXPECTED(span != 0)) + { + _rpmalloc_stat_inc(&heap->size_class_use[class_idx].spans_from_cache); + _rpmalloc_inc_span_statistics(heap, span_count, class_idx); + return span; + } + span = _rpmalloc_heap_thread_cache_deferred_extract(heap, span_count); + if (EXPECTED(span != 0)) + { + _rpmalloc_stat_inc(&heap->size_class_use[class_idx].spans_from_cache); + _rpmalloc_inc_span_statistics(heap, span_count, class_idx); + return span; + } + span = _rpmalloc_heap_reserved_extract(heap, span_count); + if (EXPECTED(span != 0)) + { + _rpmalloc_stat_inc(&heap->size_class_use[class_idx].spans_from_reserved); + _rpmalloc_inc_span_statistics(heap, span_count, class_idx); + return span; + } + span = _rpmalloc_heap_global_cache_extract(heap, span_count); + if (EXPECTED(span != 0)) + { + _rpmalloc_stat_inc(&heap->size_class_use[class_idx].spans_from_cache); + _rpmalloc_inc_span_statistics(heap, span_count, class_idx); + return span; + } + ++span_count; + } while (span_count <= limit_span_count); + // Final fallback, map in more virtual memory + span = _rpmalloc_span_map(heap, base_span_count); + _rpmalloc_inc_span_statistics(heap, base_span_count, class_idx); + _rpmalloc_stat_inc(&heap->size_class_use[class_idx].spans_map_calls); + return span; +} + +static void +_rpmalloc_heap_initialize(heap_t *heap) +{ + memset_unsafe(heap, 0, sizeof(heap_t)); + // Get a new heap ID + heap->id = 1 + atomic_incr32(&_memory_heap_id); + + // Link in heap in heap ID map + size_t list_idx = (size_t)heap->id % HEAP_ARRAY_SIZE; + heap->next_heap = _memory_heaps[list_idx]; + _memory_heaps[list_idx] = heap; +} + +static void +_rpmalloc_heap_orphan(heap_t *heap, int first_class) +{ + heap->owner_thread = (uintptr_t)-1; +#if RPMALLOC_FIRST_CLASS_HEAPS + heap_t **heap_list = (first_class ? &_memory_first_class_orphan_heaps : &_memory_orphan_heaps); +#else + (void)sizeof(first_class); + heap_t **heap_list = &_memory_orphan_heaps; +#endif + heap->next_orphan = *heap_list; + *heap_list = heap; +} + +//! Allocate a new heap from newly mapped memory pages +static heap_t * +_rpmalloc_heap_allocate_new(void) +{ + // Map in pages for a 16 heaps. If page size is greater than required size for this, map a page and + // use first part for heaps and remaining part for spans for allocations. Adds a lot of complexity, + // but saves a lot of memory on systems where page size > 64 spans (4MiB) + size_t heap_size = sizeof(heap_t); + size_t aligned_heap_size = 16 * ((heap_size + 15) / 16); + size_t request_heap_count = 16; + size_t heap_span_count = ((aligned_heap_size * request_heap_count) + sizeof(span_t) + _memory_span_size - 1) / _memory_span_size; + size_t block_size = _memory_span_size * heap_span_count; + size_t span_count = heap_span_count; + span_t *span = 0; + // If there are global reserved spans, use these first + if (_memory_global_reserve_count >= heap_span_count) + { + span = _rpmalloc_global_get_reserved_spans(heap_span_count); + } + if (!span) + { + if (_memory_page_size > block_size) + { + span_count = _memory_page_size / _memory_span_size; + block_size = _memory_page_size; + // If using huge pages, make sure to grab enough heaps to avoid reallocating a huge page just to serve new heaps + size_t possible_heap_count = (block_size - sizeof(span_t)) / aligned_heap_size; + if (possible_heap_count >= (request_heap_count * 16)) + request_heap_count *= 16; + else if (possible_heap_count < request_heap_count) + request_heap_count = possible_heap_count; + heap_span_count = ((aligned_heap_size * request_heap_count) + sizeof(span_t) + _memory_span_size - 1) / _memory_span_size; + } + + size_t align_offset = 0; + span = (span_t *)_rpmalloc_mmap(block_size, &align_offset); + if (!span) + return 0; + + // Master span will contain the heaps + _rpmalloc_stat_inc(&_master_spans); + _rpmalloc_span_initialize(span, span_count, heap_span_count, align_offset); + } + + size_t remain_size = _memory_span_size - sizeof(span_t); + heap_t *heap = (heap_t *)pointer_offset(span, sizeof(span_t)); + _rpmalloc_heap_initialize(heap); + + // Put extra heaps as orphans + size_t num_heaps = remain_size / aligned_heap_size; + if (num_heaps < request_heap_count) + num_heaps = request_heap_count; + atomic_store32(&heap->child_count, (int32_t)num_heaps - 1); + heap_t *extra_heap = (heap_t *)pointer_offset(heap, aligned_heap_size); + while (num_heaps > 1) + { + _rpmalloc_heap_initialize(extra_heap); + extra_heap->master_heap = heap; + _rpmalloc_heap_orphan(extra_heap, 1); + extra_heap = (heap_t *)pointer_offset(extra_heap, aligned_heap_size); + --num_heaps; + } + + if (span_count > heap_span_count) + { + // Cap reserved spans + size_t remain_count = span_count - heap_span_count; + size_t reserve_count = (remain_count > _memory_heap_reserve_count ? _memory_heap_reserve_count : remain_count); + span_t *remain_span = (span_t *)pointer_offset(span, heap_span_count * _memory_span_size); + _rpmalloc_heap_set_reserved_spans(heap, span, remain_span, reserve_count); + + if (remain_count > reserve_count) + { + // Set to global reserved spans + remain_span = (span_t *)pointer_offset(remain_span, reserve_count * _memory_span_size); + reserve_count = remain_count - reserve_count; + _rpmalloc_global_set_reserved_spans(span, remain_span, reserve_count); + } + } + + return heap; +} + +static heap_t * +_rpmalloc_heap_extract_orphan(heap_t **heap_list) +{ + heap_t *heap = *heap_list; + *heap_list = (heap ? heap->next_orphan : 0); + return heap; +} + +//! Allocate a new heap, potentially reusing a previously orphaned heap +static heap_t * +_rpmalloc_heap_allocate(int first_class) +{ + heap_t *heap = 0; + while (!atomic_cas32_acquire(&_memory_global_lock, 1, 0)) + _rpmalloc_spin(); + if (first_class == 0) + heap = _rpmalloc_heap_extract_orphan(&_memory_orphan_heaps); +#if RPMALLOC_FIRST_CLASS_HEAPS + if (!heap) + heap = _rpmalloc_heap_extract_orphan(&_memory_first_class_orphan_heaps); +#endif + if (!heap) + heap = _rpmalloc_heap_allocate_new(); + atomic_store32_release(&_memory_global_lock, 0); + _rpmalloc_heap_cache_adopt_deferred(heap, 0); + return heap; +} + +static void +_rpmalloc_heap_release(void *heapptr, int first_class, int release_cache) +{ + heap_t *heap = (heap_t *)heapptr; + if (!heap) + return; + // Release thread cache spans back to global cache + _rpmalloc_heap_cache_adopt_deferred(heap, 0); + if (release_cache || heap->finalize) + { +#if ENABLE_THREAD_CACHE + for (size_t iclass = 0; iclass < LARGE_CLASS_COUNT; ++iclass) + { + span_cache_t *span_cache; + if (!iclass) + span_cache = &heap->span_cache; + else + span_cache = (span_cache_t *)(heap->span_large_cache + (iclass - 1)); + if (!span_cache->count) + continue; +#if ENABLE_GLOBAL_CACHE + if (heap->finalize) + { + for (size_t ispan = 0; ispan < span_cache->count; ++ispan) + _rpmalloc_span_unmap(span_cache->span[ispan]); + } + else + { + _rpmalloc_stat_add64(&heap->thread_to_global, span_cache->count * (iclass + 1) * _memory_span_size); + _rpmalloc_stat_add(&heap->span_use[iclass].spans_to_global, span_cache->count); + _rpmalloc_global_cache_insert_spans(span_cache->span, iclass + 1, span_cache->count); + } +#else + for (size_t ispan = 0; ispan < span_cache->count; ++ispan) + _rpmalloc_span_unmap(span_cache->span[ispan]); +#endif + span_cache->count = 0; + } +#endif + } + + if (get_thread_heap_raw() == heap) + set_thread_heap(0); + +#if ENABLE_STATISTICS + atomic_decr32(&_memory_active_heaps); + rpmalloc_assert(atomic_load32(&_memory_active_heaps) >= 0, "Still active heaps during finalization"); +#endif + + // If we are forcibly terminating with _exit the state of the + // lock atomic is unknown and it's best to just go ahead and exit + if (get_thread_id() != _rpmalloc_main_thread_id) + { + while (!atomic_cas32_acquire(&_memory_global_lock, 1, 0)) + _rpmalloc_spin(); + } + _rpmalloc_heap_orphan(heap, first_class); + atomic_store32_release(&_memory_global_lock, 0); +} + +static void +_rpmalloc_heap_release_raw(void *heapptr, int release_cache) +{ + _rpmalloc_heap_release(heapptr, 0, release_cache); +} + +static void +_rpmalloc_heap_release_raw_fc(void *heapptr) +{ + _rpmalloc_heap_release_raw(heapptr, 1); +} + +static void +_rpmalloc_heap_finalize(heap_t *heap) +{ + if (heap->spans_reserved) + { + span_t *span = _rpmalloc_span_map(heap, heap->spans_reserved); + _rpmalloc_span_unmap(span); + heap->spans_reserved = 0; + } + + _rpmalloc_heap_cache_adopt_deferred(heap, 0); + + for (size_t iclass = 0; iclass < SIZE_CLASS_COUNT; ++iclass) + { + if (heap->size_class[iclass].cache) + _rpmalloc_span_unmap(heap->size_class[iclass].cache); + heap->size_class[iclass].cache = 0; + span_t *span = heap->size_class[iclass].partial_span; + while (span) + { + span_t *next = span->next; + _rpmalloc_span_finalize(heap, iclass, span, &heap->size_class[iclass].partial_span); + span = next; + } + // If class still has a free list it must be a full span + if (heap->size_class[iclass].free_list) + { + span_t *class_span = (span_t *)((uintptr_t)heap->size_class[iclass].free_list & _memory_span_mask); + span_t **list = 0; +#if RPMALLOC_FIRST_CLASS_HEAPS + list = &heap->full_span[iclass]; +#endif + --heap->full_span_count; + if (!_rpmalloc_span_finalize(heap, iclass, class_span, list)) + { + if (list) + _rpmalloc_span_double_link_list_remove(list, class_span); + _rpmalloc_span_double_link_list_add(&heap->size_class[iclass].partial_span, class_span); + } + } + } + +#if ENABLE_THREAD_CACHE + for (size_t iclass = 0; iclass < LARGE_CLASS_COUNT; ++iclass) + { + span_cache_t *span_cache; + if (!iclass) + span_cache = &heap->span_cache; + else + span_cache = (span_cache_t *)(heap->span_large_cache + (iclass - 1)); + for (size_t ispan = 0; ispan < span_cache->count; ++ispan) + _rpmalloc_span_unmap(span_cache->span[ispan]); + span_cache->count = 0; + } +#endif + rpmalloc_assert(!atomic_load_ptr(&heap->span_free_deferred), "Heaps still active during finalization"); +} + +//////////// +/// +/// Allocation entry points +/// +////// + +//! Pop first block from a free list +static void * +free_list_pop(void **list) +{ + void *block = *list; + *list = *((void **)block); + return block; +} + +//! Allocate a small/medium sized memory block from the given heap +static void * +_rpmalloc_allocate_from_heap_fallback(heap_t *heap, heap_size_class_t *heap_size_class, uint32_t class_idx) +{ + span_t *span = heap_size_class->partial_span; + if (EXPECTED(span != 0)) + { + rpmalloc_assert(span->block_count == _memory_size_class[span->size_class].block_count, "Span block count corrupted"); + rpmalloc_assert(!_rpmalloc_span_is_fully_utilized(span), "Internal failure"); + void *block; + if (span->free_list) + { + // Span local free list is not empty, swap to size class free list + block = free_list_pop(&span->free_list); + heap_size_class->free_list = span->free_list; + span->free_list = 0; + } + else + { + // If the span did not fully initialize free list, link up another page worth of blocks + void *block_start = pointer_offset(span, SPAN_HEADER_SIZE + ((size_t)span->free_list_limit * span->block_size)); + span->free_list_limit += free_list_partial_init(&heap_size_class->free_list, &block, + (void *)((uintptr_t)block_start & ~(_memory_page_size - 1)), block_start, + span->block_count - span->free_list_limit, span->block_size); + } + rpmalloc_assert(span->free_list_limit <= span->block_count, "Span block count corrupted"); + span->used_count = span->free_list_limit; + + // Swap in deferred free list if present + if (atomic_load_ptr(&span->free_list_deferred)) + _rpmalloc_span_extract_free_list_deferred(span); + + // If span is still not fully utilized keep it in partial list and early return block + if (!_rpmalloc_span_is_fully_utilized(span)) + return block; + + // The span is fully utilized, unlink from partial list and add to fully utilized list + _rpmalloc_span_double_link_list_pop_head(&heap_size_class->partial_span, span); +#if RPMALLOC_FIRST_CLASS_HEAPS + _rpmalloc_span_double_link_list_add(&heap->full_span[class_idx], span); +#endif + ++heap->full_span_count; + return block; + } + + // Find a span in one of the cache levels + span = _rpmalloc_heap_extract_new_span(heap, heap_size_class, 1, class_idx); + if (EXPECTED(span != 0)) + { + // Mark span as owned by this heap and set base data, return first block + return _rpmalloc_span_initialize_new(heap, heap_size_class, span, class_idx); + } + + return 0; +} + +//! Allocate a small sized memory block from the given heap +static void * +_rpmalloc_allocate_small(heap_t *heap, size_t size) +{ + rpmalloc_assert(heap, "No thread heap"); + // Small sizes have unique size classes + const uint32_t class_idx = (uint32_t)((size + (SMALL_GRANULARITY - 1)) >> SMALL_GRANULARITY_SHIFT); + heap_size_class_t *heap_size_class = heap->size_class + class_idx; + _rpmalloc_stat_inc_alloc(heap, class_idx); + if (EXPECTED(heap_size_class->free_list != 0)) + return free_list_pop(&heap_size_class->free_list); + return _rpmalloc_allocate_from_heap_fallback(heap, heap_size_class, class_idx); +} + +//! Allocate a medium sized memory block from the given heap +static void * +_rpmalloc_allocate_medium(heap_t *heap, size_t size) +{ + rpmalloc_assert(heap, "No thread heap"); + // Calculate the size class index and do a dependent lookup of the final class index (in case of merged classes) + const uint32_t base_idx = (uint32_t)(SMALL_CLASS_COUNT + ((size - (SMALL_SIZE_LIMIT + 1)) >> MEDIUM_GRANULARITY_SHIFT)); + const uint32_t class_idx = _memory_size_class[base_idx].class_idx; + heap_size_class_t *heap_size_class = heap->size_class + class_idx; + _rpmalloc_stat_inc_alloc(heap, class_idx); + if (EXPECTED(heap_size_class->free_list != 0)) + return free_list_pop(&heap_size_class->free_list); + return _rpmalloc_allocate_from_heap_fallback(heap, heap_size_class, class_idx); +} + +//! Allocate a large sized memory block from the given heap +static void * +_rpmalloc_allocate_large(heap_t *heap, size_t size) +{ + rpmalloc_assert(heap, "No thread heap"); + // Calculate number of needed max sized spans (including header) + // Since this function is never called if size > LARGE_SIZE_LIMIT + // the span_count is guaranteed to be <= LARGE_CLASS_COUNT + size += SPAN_HEADER_SIZE; + size_t span_count = size >> _memory_span_size_shift; + if (size & (_memory_span_size - 1)) + ++span_count; + + // Find a span in one of the cache levels + span_t *span = _rpmalloc_heap_extract_new_span(heap, 0, span_count, SIZE_CLASS_LARGE); + if (!span) + return span; + + // Mark span as owned by this heap and set base data + rpmalloc_assert(span->span_count >= span_count, "Internal failure"); + span->size_class = SIZE_CLASS_LARGE; + span->heap = heap; + +#if RPMALLOC_FIRST_CLASS_HEAPS + _rpmalloc_span_double_link_list_add(&heap->large_huge_span, span); +#endif + ++heap->full_span_count; + + return pointer_offset(span, SPAN_HEADER_SIZE); +} + +//! Allocate a huge block by mapping memory pages directly +static void * +_rpmalloc_allocate_huge(heap_t *heap, size_t size) +{ + rpmalloc_assert(heap, "No thread heap"); + _rpmalloc_heap_cache_adopt_deferred(heap, 0); + size += SPAN_HEADER_SIZE; + size_t num_pages = size >> _memory_page_size_shift; + if (size & (_memory_page_size - 1)) + ++num_pages; + size_t align_offset = 0; + span_t *span = (span_t *)_rpmalloc_mmap(num_pages * _memory_page_size, &align_offset); + if (!span) + return span; + + // Store page count in span_count + span->size_class = SIZE_CLASS_HUGE; + span->span_count = (uint32_t)num_pages; + span->align_offset = (uint32_t)align_offset; + span->heap = heap; + _rpmalloc_stat_add_peak(&_huge_pages_current, num_pages, _huge_pages_peak); + +#if RPMALLOC_FIRST_CLASS_HEAPS + _rpmalloc_span_double_link_list_add(&heap->large_huge_span, span); +#endif + ++heap->full_span_count; + + return pointer_offset(span, SPAN_HEADER_SIZE); +} + +//! Allocate a block of the given size +static void * +_rpmalloc_allocate(heap_t *heap, size_t size) +{ + _rpmalloc_stat_add64(&_allocation_counter, 1); + if (EXPECTED(size <= SMALL_SIZE_LIMIT)) + return _rpmalloc_allocate_small(heap, size); + else if (size <= _memory_medium_size_limit) + return _rpmalloc_allocate_medium(heap, size); + else if (size <= LARGE_SIZE_LIMIT) + return _rpmalloc_allocate_large(heap, size); + return _rpmalloc_allocate_huge(heap, size); +} + +static void * +_rpmalloc_aligned_allocate(heap_t *heap, size_t alignment, size_t size) +{ + if (alignment <= SMALL_GRANULARITY) + return _rpmalloc_allocate(heap, size); + +#if ENABLE_VALIDATE_ARGS + assert((size + alignment) > size); + assert((alignment & (alignment - 1)) == 0); +#endif + + if ((alignment <= SPAN_HEADER_SIZE) && (size < _memory_medium_size_limit)) + { + // If alignment is less or equal to span header size (which is power of two), + // and size aligned to span header size multiples is less than size + alignment, + // then use natural alignment of blocks to provide alignment + size_t multiple_size = size ? (size + (SPAN_HEADER_SIZE - 1)) & ~(uintptr_t)(SPAN_HEADER_SIZE - 1) : SPAN_HEADER_SIZE; + rpmalloc_assert(!(multiple_size % SPAN_HEADER_SIZE), "Failed alignment calculation"); + if (multiple_size <= (size + alignment)) + return _rpmalloc_allocate(heap, multiple_size); + } + + void *ptr = 0; + size_t align_mask = alignment - 1; + if (alignment <= _memory_page_size) + { + ptr = _rpmalloc_allocate(heap, size + alignment); + if ((uintptr_t)ptr & align_mask) + { + ptr = (void *)(((uintptr_t)ptr & ~(uintptr_t)align_mask) + alignment); + // Mark as having aligned blocks + span_t *span = (span_t *)((uintptr_t)ptr & _memory_span_mask); + span->flags |= SPAN_FLAG_ALIGNED_BLOCKS; + } + return ptr; + } + + // Fallback to mapping new pages for this request. Since pointers passed + // to rpfree must be able to reach the start of the span by bitmasking of + // the address with the span size, the returned aligned pointer from this + // function must be with a span size of the start of the mapped area. + // In worst case this requires us to loop and map pages until we get a + // suitable memory address. It also means we can never align to span size + // or greater, since the span header will push alignment more than one + // span size away from span start (thus causing pointer mask to give us + // an invalid span start on free) + if (alignment & align_mask) + { + errno = EINVAL; + return 0; + } + if (alignment >= _memory_span_size) + { + errno = EINVAL; + return 0; + } + + size_t extra_pages = alignment / _memory_page_size; + + // Since each span has a header, we will at least need one extra memory page + size_t num_pages = 1 + (size / _memory_page_size); + if (size & (_memory_page_size - 1)) + ++num_pages; + + if (extra_pages > num_pages) + num_pages = 1 + extra_pages; + + size_t original_pages = num_pages; + size_t limit_pages = (_memory_span_size / _memory_page_size) * 2; + if (limit_pages < (original_pages * 2)) + limit_pages = original_pages * 2; + + size_t mapped_size, align_offset; + span_t *span; + +retry: + align_offset = 0; + mapped_size = num_pages * _memory_page_size; + + span = (span_t *)_rpmalloc_mmap(mapped_size, &align_offset); + if (!span) + { + errno = ENOMEM; + return 0; + } + ptr = pointer_offset(span, SPAN_HEADER_SIZE); + + if ((uintptr_t)ptr & align_mask) + ptr = (void *)(((uintptr_t)ptr & ~(uintptr_t)align_mask) + alignment); + + if (((size_t)pointer_diff(ptr, span) >= _memory_span_size) || + (pointer_offset(ptr, size) > pointer_offset(span, mapped_size)) || + (((uintptr_t)ptr & _memory_span_mask) != (uintptr_t)span)) + { + _rpmalloc_unmap(span, mapped_size, align_offset, mapped_size); + ++num_pages; + if (num_pages > limit_pages) + { + errno = EINVAL; + return 0; + } + goto retry; + } + + // Store page count in span_count + span->size_class = SIZE_CLASS_HUGE; + span->span_count = (uint32_t)num_pages; + span->align_offset = (uint32_t)align_offset; + span->heap = heap; + _rpmalloc_stat_add_peak(&_huge_pages_current, num_pages, _huge_pages_peak); + +#if RPMALLOC_FIRST_CLASS_HEAPS + _rpmalloc_span_double_link_list_add(&heap->large_huge_span, span); +#endif + ++heap->full_span_count; + + _rpmalloc_stat_add64(&_allocation_counter, 1); + + return ptr; +} + +//////////// +/// +/// Deallocation entry points +/// +////// + +//! Deallocate the given small/medium memory block in the current thread local heap +static void +_rpmalloc_deallocate_direct_small_or_medium(span_t *span, void *block) +{ + heap_t *heap = span->heap; + rpmalloc_assert(heap->owner_thread == get_thread_id() || !heap->owner_thread || heap->finalize, "Internal failure"); + // Add block to free list + if (UNEXPECTED(_rpmalloc_span_is_fully_utilized(span))) + { + span->used_count = span->block_count; +#if RPMALLOC_FIRST_CLASS_HEAPS + _rpmalloc_span_double_link_list_remove(&heap->full_span[span->size_class], span); +#endif + _rpmalloc_span_double_link_list_add(&heap->size_class[span->size_class].partial_span, span); + --heap->full_span_count; + } + *((void **)block) = span->free_list; + --span->used_count; + span->free_list = block; + if (UNEXPECTED(span->used_count == span->list_size)) + { + // If there are no used blocks it is guaranteed that no other external thread is accessing the span + if (span->used_count) + { + // Make sure we have synchronized the deferred list and list size by using acquire semantics + // and guarantee that no external thread is accessing span concurrently + void *free_list; + do + { + free_list = atomic_exchange_ptr_acquire(&span->free_list_deferred, INVALID_POINTER); + } while (free_list == INVALID_POINTER); + atomic_store_ptr_release(&span->free_list_deferred, free_list); + } + _rpmalloc_span_double_link_list_remove(&heap->size_class[span->size_class].partial_span, span); + _rpmalloc_span_release_to_cache(heap, span); + } +} + +static void +_rpmalloc_deallocate_defer_free_span(heap_t *heap, span_t *span) +{ + if (span->size_class != SIZE_CLASS_HUGE) + _rpmalloc_stat_inc(&heap->span_use[span->span_count - 1].spans_deferred); + // This list does not need ABA protection, no mutable side state + do + { + span->free_list = (void *)atomic_load_ptr(&heap->span_free_deferred); + } while (!atomic_cas_ptr(&heap->span_free_deferred, span, span->free_list)); +} + +//! Put the block in the deferred free list of the owning span +static void +_rpmalloc_deallocate_defer_small_or_medium(span_t *span, void *block) +{ + // The memory ordering here is a bit tricky, to avoid having to ABA protect + // the deferred free list to avoid desynchronization of list and list size + // we need to have acquire semantics on successful CAS of the pointer to + // guarantee the list_size variable validity + release semantics on pointer store + void *free_list; + do + { + free_list = atomic_exchange_ptr_acquire(&span->free_list_deferred, INVALID_POINTER); + } while (free_list == INVALID_POINTER); + *((void **)block) = free_list; + uint32_t free_count = ++span->list_size; + int all_deferred_free = (free_count == span->block_count); + atomic_store_ptr_release(&span->free_list_deferred, block); + if (all_deferred_free) + { + // Span was completely freed by this block. Due to the INVALID_POINTER spin lock + // no other thread can reach this state simultaneously on this span. + // Safe to move to owner heap deferred cache + _rpmalloc_deallocate_defer_free_span(span->heap, span); + } +} + +static void +_rpmalloc_deallocate_small_or_medium(span_t *span, void *p) +{ + _rpmalloc_stat_inc_free(span->heap, span->size_class); + if (span->flags & SPAN_FLAG_ALIGNED_BLOCKS) + { + // Realign pointer to block start + void *blocks_start = pointer_offset(span, SPAN_HEADER_SIZE); + uint32_t block_offset = (uint32_t)pointer_diff(p, blocks_start); + p = pointer_offset(p, -(int32_t)(block_offset % span->block_size)); + } + // Check if block belongs to this heap or if deallocation should be deferred +#if RPMALLOC_FIRST_CLASS_HEAPS + int defer = (span->heap->owner_thread && (span->heap->owner_thread != get_thread_id()) && !span->heap->finalize); +#else + int defer = ((span->heap->owner_thread != get_thread_id()) && !span->heap->finalize); +#endif + if (!defer) + _rpmalloc_deallocate_direct_small_or_medium(span, p); + else + _rpmalloc_deallocate_defer_small_or_medium(span, p); +} + +//! Deallocate the given large memory block to the current heap +static void +_rpmalloc_deallocate_large(span_t *span) +{ + rpmalloc_assert(span->size_class == SIZE_CLASS_LARGE, "Bad span size class"); + rpmalloc_assert(!(span->flags & SPAN_FLAG_MASTER) || !(span->flags & SPAN_FLAG_SUBSPAN), "Span flag corrupted"); + rpmalloc_assert((span->flags & SPAN_FLAG_MASTER) || (span->flags & SPAN_FLAG_SUBSPAN), "Span flag corrupted"); + // We must always defer (unless finalizing) if from another heap since we cannot touch the list or counters of another heap +#if RPMALLOC_FIRST_CLASS_HEAPS + int defer = (span->heap->owner_thread && (span->heap->owner_thread != get_thread_id()) && !span->heap->finalize); +#else + int defer = ((span->heap->owner_thread != get_thread_id()) && !span->heap->finalize); +#endif + if (defer) + { + _rpmalloc_deallocate_defer_free_span(span->heap, span); + return; + } + rpmalloc_assert(span->heap->full_span_count, "Heap span counter corrupted"); + --span->heap->full_span_count; +#if RPMALLOC_FIRST_CLASS_HEAPS + _rpmalloc_span_double_link_list_remove(&span->heap->large_huge_span, span); +#endif +#if ENABLE_ADAPTIVE_THREAD_CACHE || ENABLE_STATISTICS + // Decrease counter + size_t idx = span->span_count - 1; + atomic_decr32(&span->heap->span_use[idx].current); +#endif + heap_t *heap = span->heap; + rpmalloc_assert(heap, "No thread heap"); +#if ENABLE_THREAD_CACHE + const int set_as_reserved = ((span->span_count > 1) && (heap->span_cache.count == 0) && !heap->finalize && !heap->spans_reserved); +#else + const int set_as_reserved = ((span->span_count > 1) && !heap->finalize && !heap->spans_reserved); +#endif + if (set_as_reserved) + { + heap->span_reserve = span; + heap->spans_reserved = span->span_count; + if (span->flags & SPAN_FLAG_MASTER) + { + heap->span_reserve_master = span; + } + else + { // SPAN_FLAG_SUBSPAN + span_t *master = (span_t *)pointer_offset(span, -(intptr_t)((size_t)span->offset_from_master * _memory_span_size)); + heap->span_reserve_master = master; + rpmalloc_assert(master->flags & SPAN_FLAG_MASTER, "Span flag corrupted"); + rpmalloc_assert(atomic_load32(&master->remaining_spans) >= (int32_t)span->span_count, "Master span count corrupted"); + } + _rpmalloc_stat_inc(&heap->span_use[idx].spans_to_reserved); + } + else + { + // Insert into cache list + _rpmalloc_heap_cache_insert(heap, span); + } +} + +//! Deallocate the given huge span +static void +_rpmalloc_deallocate_huge(span_t *span) +{ + rpmalloc_assert(span->heap, "No span heap"); +#if RPMALLOC_FIRST_CLASS_HEAPS + int defer = (span->heap->owner_thread && (span->heap->owner_thread != get_thread_id()) && !span->heap->finalize); +#else + int defer = ((span->heap->owner_thread != get_thread_id()) && !span->heap->finalize); +#endif + if (defer) + { + _rpmalloc_deallocate_defer_free_span(span->heap, span); + return; + } + rpmalloc_assert(span->heap->full_span_count, "Heap span counter corrupted"); + --span->heap->full_span_count; +#if RPMALLOC_FIRST_CLASS_HEAPS + _rpmalloc_span_double_link_list_remove(&span->heap->large_huge_span, span); +#endif + + // Oversized allocation, page count is stored in span_count + size_t num_pages = span->span_count; + _rpmalloc_unmap(span, num_pages * _memory_page_size, span->align_offset, num_pages * _memory_page_size); + _rpmalloc_stat_sub(&_huge_pages_current, num_pages); +} + +//! Deallocate the given block +static void +_rpmalloc_deallocate(void *p) +{ + _rpmalloc_stat_add64(&_deallocation_counter, 1); + // Grab the span (always at start of span, using span alignment) + span_t *span = (span_t *)((uintptr_t)p & _memory_span_mask); + if (UNEXPECTED(!span)) + return; + if (EXPECTED(span->size_class < SIZE_CLASS_COUNT)) + _rpmalloc_deallocate_small_or_medium(span, p); + else if (span->size_class == SIZE_CLASS_LARGE) + _rpmalloc_deallocate_large(span); + else + _rpmalloc_deallocate_huge(span); +} + +//////////// +/// +/// Reallocation entry points +/// +////// + +static size_t +_rpmalloc_usable_size(void *p); + +//! Reallocate the given block to the given size +static void * +_rpmalloc_reallocate(heap_t *heap, void *p, size_t size, size_t oldsize, unsigned int flags) +{ + if (p) + { + // Grab the span using guaranteed span alignment + span_t *span = (span_t *)((uintptr_t)p & _memory_span_mask); + if (EXPECTED(span->size_class < SIZE_CLASS_COUNT)) + { + // Small/medium sized block + rpmalloc_assert(span->span_count == 1, "Span counter corrupted"); + void *blocks_start = pointer_offset(span, SPAN_HEADER_SIZE); + uint32_t block_offset = (uint32_t)pointer_diff(p, blocks_start); + uint32_t block_idx = block_offset / span->block_size; + void *block = pointer_offset(blocks_start, (size_t)block_idx * span->block_size); + if (!oldsize) + oldsize = (size_t)((ptrdiff_t)span->block_size - pointer_diff(p, block)); + if ((size_t)span->block_size >= size) + { + // Still fits in block, never mind trying to save memory, but preserve data if alignment changed + if ((p != block) && !(flags & RPMALLOC_NO_PRESERVE)) + memmove_unsafe(block, p, oldsize); + return block; + } + } + else if (span->size_class == SIZE_CLASS_LARGE) + { + // Large block + size_t total_size = size + SPAN_HEADER_SIZE; + size_t num_spans = total_size >> _memory_span_size_shift; + if (total_size & (_memory_span_mask - 1)) + ++num_spans; + size_t current_spans = span->span_count; + void *block = pointer_offset(span, SPAN_HEADER_SIZE); + if (!oldsize) + oldsize = (current_spans * _memory_span_size) - (size_t)pointer_diff(p, block) - SPAN_HEADER_SIZE; + if ((current_spans >= num_spans) && (total_size >= (oldsize / 2))) + { + // Still fits in block, never mind trying to save memory, but preserve data if alignment changed + if ((p != block) && !(flags & RPMALLOC_NO_PRESERVE)) + memmove_unsafe(block, p, oldsize); + return block; + } + } + else + { + // Oversized block + size_t total_size = size + SPAN_HEADER_SIZE; + size_t num_pages = total_size >> _memory_page_size_shift; + if (total_size & (_memory_page_size - 1)) + ++num_pages; + // Page count is stored in span_count + size_t current_pages = span->span_count; + void *block = pointer_offset(span, SPAN_HEADER_SIZE); + if (!oldsize) + oldsize = (current_pages * _memory_page_size) - (size_t)pointer_diff(p, block) - SPAN_HEADER_SIZE; + if ((current_pages >= num_pages) && (num_pages >= (current_pages / 2))) + { + // Still fits in block, never mind trying to save memory, but preserve data if alignment changed + if ((p != block) && !(flags & RPMALLOC_NO_PRESERVE)) + memmove_unsafe(block, p, oldsize); + return block; + } + } + } + else + { + oldsize = 0; + } + + if (!!(flags & RPMALLOC_GROW_OR_FAIL)) + return 0; + + // Size is greater than block size, need to allocate a new block and deallocate the old + // Avoid hysteresis by overallocating if increase is small (below 37%) + size_t lower_bound = oldsize + (oldsize >> 2) + (oldsize >> 3); + size_t new_size = (size > lower_bound) ? size : ((size > oldsize) ? lower_bound : size); + void *block = _rpmalloc_allocate(heap, new_size); + if (p && block) + { + if (!(flags & RPMALLOC_NO_PRESERVE)) + memcpy_unsafe(block, p, oldsize < new_size ? oldsize : new_size); + _rpmalloc_deallocate(p); + } + + return block; +} + +static void * +_rpmalloc_aligned_reallocate(heap_t *heap, void *ptr, size_t alignment, size_t size, size_t oldsize, + unsigned int flags) +{ + if (alignment <= SMALL_GRANULARITY) + return _rpmalloc_reallocate(heap, ptr, size, oldsize, flags); + + int no_alloc = !!(flags & RPMALLOC_GROW_OR_FAIL); + size_t usablesize = (ptr ? _rpmalloc_usable_size(ptr) : 0); + if ((usablesize >= size) && !((uintptr_t)ptr & (alignment - 1))) + { + if (no_alloc || (size >= (usablesize / 2))) + return ptr; + } + // Aligned alloc marks span as having aligned blocks + void *block = (!no_alloc ? _rpmalloc_aligned_allocate(heap, alignment, size) : 0); + if (EXPECTED(block != 0)) + { + if (!(flags & RPMALLOC_NO_PRESERVE) && ptr) + { + if (!oldsize) + oldsize = usablesize; + memcpy_unsafe(block, ptr, oldsize < size ? oldsize : size); + } + _rpmalloc_deallocate(ptr); + } + return block; +} + +//////////// +/// +/// Initialization, finalization and utility +/// +////// + +//! Get the usable size of the given block +static size_t +_rpmalloc_usable_size(void *p) +{ + // Grab the span using guaranteed span alignment + span_t *span = (span_t *)((uintptr_t)p & _memory_span_mask); + if (span->size_class < SIZE_CLASS_COUNT) + { + // Small/medium block + void *blocks_start = pointer_offset(span, SPAN_HEADER_SIZE); + return span->block_size - ((size_t)pointer_diff(p, blocks_start) % span->block_size); + } + if (span->size_class == SIZE_CLASS_LARGE) + { + // Large block + size_t current_spans = span->span_count; + return (current_spans * _memory_span_size) - (size_t)pointer_diff(p, span); + } + // Oversized block, page count is stored in span_count + size_t current_pages = span->span_count; + return (current_pages * _memory_page_size) - (size_t)pointer_diff(p, span); +} + +//! Adjust and optimize the size class properties for the given class +static void +_rpmalloc_adjust_size_class(size_t iclass) +{ + size_t block_size = _memory_size_class[iclass].block_size; + size_t block_count = (_memory_span_size - SPAN_HEADER_SIZE) / block_size; + + _memory_size_class[iclass].block_count = (uint16_t)block_count; + _memory_size_class[iclass].class_idx = (uint16_t)iclass; + + // Check if previous size classes can be merged + if (iclass >= SMALL_CLASS_COUNT) + { + size_t prevclass = iclass; + while (prevclass > 0) + { + --prevclass; + // A class can be merged if number of pages and number of blocks are equal + if (_memory_size_class[prevclass].block_count == _memory_size_class[iclass].block_count) + memcpy_unsafe(_memory_size_class + prevclass, _memory_size_class + iclass, sizeof(_memory_size_class[iclass])); + else + break; + } + } +} + +//! Initialize the allocator and setup global data +extern inline int +rpmalloc_initialize(void) +{ + if (_rpmalloc_initialized) + { + rpmalloc_thread_initialize(); + return 0; + } + return rpmalloc_initialize_config(0); +} + +int rpmalloc_initialize_config(const rpmalloc_config_t *config) +{ + if (_rpmalloc_initialized) + { + rpmalloc_thread_initialize(); + return 0; + } + _rpmalloc_initialized = 1; + + if (config) + memcpy_unsafe(&_memory_config, config, sizeof(rpmalloc_config_t)); + else + memset_unsafe(&_memory_config, 0, sizeof(rpmalloc_config_t)); + + if (!_memory_config.memory_map || !_memory_config.memory_unmap) + { + _memory_config.memory_map = _rpmalloc_mmap_os; + _memory_config.memory_unmap = _rpmalloc_unmap_os; + } + + _memory_map_granularity = (size_t)__rpmalloc_sysconf(_SC_PAGESIZE); + +#if RPMALLOC_CONFIGURABLE + _memory_page_size = _memory_config.page_size; +#else + _memory_page_size = 0; +#endif + _memory_huge_pages = 0; + if (!_memory_page_size) + { + _memory_page_size = _memory_map_granularity; + if (_memory_config.enable_huge_pages) + { +#if defined(__linux__) + size_t huge_page_size = 0; + FILE *meminfo = fopen("/proc/meminfo", "r"); + if (meminfo) + { + char line[128]; + while (!huge_page_size && fgets(line, sizeof(line) - 1, meminfo)) + { + line[sizeof(line) - 1] = 0; + if (strstr(line, "Hugepagesize:")) + huge_page_size = (size_t)strtol(line + 13, 0, 10) * 1024; + } + fclose(meminfo); + } + if (huge_page_size) + { + _memory_huge_pages = 1; + _memory_page_size = huge_page_size; + _memory_map_granularity = huge_page_size; + } +#endif + } + } + else + { + if (_memory_config.enable_huge_pages) + _memory_huge_pages = 1; + } + + size_t min_span_size = 256; + size_t max_page_size; +#if UINTPTR_MAX > 0xFFFFFFFF + max_page_size = 4096ULL * 1024ULL * 1024ULL; +#else + max_page_size = 4 * 1024 * 1024; +#endif + if (_memory_page_size < min_span_size) + _memory_page_size = min_span_size; + if (_memory_page_size > max_page_size) + _memory_page_size = max_page_size; + _memory_page_size_shift = 0; + size_t page_size_bit = _memory_page_size; + while (page_size_bit != 1) + { + ++_memory_page_size_shift; + page_size_bit >>= 1; + } + _memory_page_size = ((size_t)1 << _memory_page_size_shift); + +#if RPMALLOC_CONFIGURABLE + if (!_memory_config.span_size) + { + _memory_span_size = _memory_default_span_size; + _memory_span_size_shift = _memory_default_span_size_shift; + _memory_span_mask = _memory_default_span_mask; + } + else + { + size_t span_size = _memory_config.span_size; + if (span_size > (256 * 1024)) + span_size = (256 * 1024); + _memory_span_size = 4096; + _memory_span_size_shift = 12; + while (_memory_span_size < span_size) + { + _memory_span_size <<= 1; + ++_memory_span_size_shift; + } + _memory_span_mask = ~(uintptr_t)(_memory_span_size - 1); + } +#endif + + _memory_span_map_count = (_memory_config.span_map_count ? _memory_config.span_map_count : DEFAULT_SPAN_MAP_COUNT); + if ((_memory_span_size * _memory_span_map_count) < _memory_page_size) + _memory_span_map_count = (_memory_page_size / _memory_span_size); + if ((_memory_page_size >= _memory_span_size) && ((_memory_span_map_count * _memory_span_size) % _memory_page_size)) + _memory_span_map_count = (_memory_page_size / _memory_span_size); + _memory_heap_reserve_count = (_memory_span_map_count > DEFAULT_SPAN_MAP_COUNT) ? DEFAULT_SPAN_MAP_COUNT : _memory_span_map_count; + + _memory_config.page_size = _memory_page_size; + _memory_config.span_size = _memory_span_size; + _memory_config.span_map_count = _memory_span_map_count; + _memory_config.enable_huge_pages = _memory_huge_pages; + +#if ((defined(__APPLE__) || defined(__HAIKU__)) && ENABLE_PRELOAD) || defined(__TINYC__) + if (pthread_key_create(&_memory_thread_heap, _rpmalloc_heap_release_raw_fc)) + return -1; +#endif + + // Setup all small and medium size classes + size_t iclass = 0; + _memory_size_class[iclass].block_size = SMALL_GRANULARITY; + _rpmalloc_adjust_size_class(iclass); + for (iclass = 1; iclass < SMALL_CLASS_COUNT; ++iclass) + { + size_t size = iclass * SMALL_GRANULARITY; + _memory_size_class[iclass].block_size = (uint32_t)size; + _rpmalloc_adjust_size_class(iclass); + } + // At least two blocks per span, then fall back to large allocations + _memory_medium_size_limit = (_memory_span_size - SPAN_HEADER_SIZE) >> 1; + if (_memory_medium_size_limit > MEDIUM_SIZE_LIMIT) + _memory_medium_size_limit = MEDIUM_SIZE_LIMIT; + for (iclass = 0; iclass < MEDIUM_CLASS_COUNT; ++iclass) + { + size_t size = SMALL_SIZE_LIMIT + ((iclass + 1) * MEDIUM_GRANULARITY); + if (size > _memory_medium_size_limit) + break; + _memory_size_class[SMALL_CLASS_COUNT + iclass].block_size = (uint32_t)size; + _rpmalloc_adjust_size_class(SMALL_CLASS_COUNT + iclass); + } + + _memory_orphan_heaps = 0; +#if RPMALLOC_FIRST_CLASS_HEAPS + _memory_first_class_orphan_heaps = 0; +#endif +#if ENABLE_STATISTICS + atomic_store32(&_memory_active_heaps, 0); + atomic_store32(&_mapped_pages, 0); + _mapped_pages_peak = 0; + atomic_store32(&_master_spans, 0); + atomic_store32(&_mapped_total, 0); + atomic_store32(&_unmapped_total, 0); + atomic_store32(&_mapped_pages_os, 0); + atomic_store32(&_huge_pages_current, 0); + _huge_pages_peak = 0; +#endif + memset_unsafe(_memory_heaps, 0, sizeof(_memory_heaps)); + atomic_store32_release(&_memory_global_lock, 0); + + // Initialize this thread + rpmalloc_thread_initialize(); + return 0; +} + +//! Finalize the allocator +void rpmalloc_finalize(void) +{ + rpmalloc_thread_finalize(1); + // rpmalloc_dump_statistics(stdout); + + if (_memory_global_reserve) + { + atomic_add32(&_memory_global_reserve_master->remaining_spans, -(int32_t)_memory_global_reserve_count); + _memory_global_reserve_master = 0; + _memory_global_reserve_count = 0; + _memory_global_reserve = 0; + } + atomic_store32_release(&_memory_global_lock, 0); + + // Free all thread caches and fully free spans + for (size_t list_idx = 0; list_idx < HEAP_ARRAY_SIZE; ++list_idx) + { + heap_t *heap = _memory_heaps[list_idx]; + while (heap) + { + heap_t *next_heap = heap->next_heap; + heap->finalize = 1; + _rpmalloc_heap_global_finalize(heap); + heap = next_heap; + } + } + +#if ENABLE_GLOBAL_CACHE + // Free global caches + for (size_t iclass = 0; iclass < LARGE_CLASS_COUNT; ++iclass) + _rpmalloc_global_cache_finalize(&_memory_span_cache[iclass]); +#endif + +#if (defined(__APPLE__) || defined(__HAIKU__)) && ENABLE_PRELOAD + pthread_key_delete(_memory_thread_heap); +#endif +#if defined(_WIN32) && (!defined(BUILD_DYNAMIC_LINK) || !BUILD_DYNAMIC_LINK) + FlsFree(fls_key); + fls_key = 0; +#endif +#if ENABLE_STATISTICS + // If you hit these asserts you probably have memory leaks (perhaps global scope data doing dynamic allocations) or double frees in your code + rpmalloc_assert(atomic_load32(&_mapped_pages) == 0, "Memory leak detected"); + rpmalloc_assert(atomic_load32(&_mapped_pages_os) == 0, "Memory leak detected"); +#endif + + _rpmalloc_initialized = 0; +} + +//! Initialize thread, assign heap +extern inline void +rpmalloc_thread_initialize(void) +{ + if (!get_thread_heap_raw()) + { + heap_t *heap = _rpmalloc_heap_allocate(0); + if (heap) + { + _rpmalloc_stat_inc(&_memory_active_heaps); + set_thread_heap(heap); +#if defined(_WIN32) && (!defined(BUILD_DYNAMIC_LINK) || !BUILD_DYNAMIC_LINK) + FlsSetValue(fls_key, heap); +#endif + } + } +} + +//! Finalize thread, orphan heap +void rpmalloc_thread_finalize(int release_caches) +{ + heap_t *heap = get_thread_heap_raw(); + if (heap) + _rpmalloc_heap_release_raw(heap, release_caches); + set_thread_heap(0); +#if defined(_WIN32) && (!defined(BUILD_DYNAMIC_LINK) || !BUILD_DYNAMIC_LINK) + FlsSetValue(fls_key, 0); +#endif +} + +int rpmalloc_is_thread_initialized(void) +{ + return (get_thread_heap_raw() != 0) ? 1 : 0; +} + +const rpmalloc_config_t * +rpmalloc_config(void) +{ + return &_memory_config; +} + +// Extern interface + +extern inline RPMALLOC_ALLOCATOR void * +rpmalloc(size_t size) +{ +#if ENABLE_VALIDATE_ARGS + assert(size < MAX_ALLOC_SIZE); +#endif + heap_t *heap = get_thread_heap(); + return _rpmalloc_allocate(heap, size); +} + +extern inline void +rpfree(void *ptr) +{ + _rpmalloc_deallocate(ptr); +} + +extern inline RPMALLOC_ALLOCATOR void * +rpcalloc(size_t num, size_t size) +{ + size_t total; +#if ENABLE_VALIDATE_ARGS + int err = __builtin_umull_overflow(num, size, &total); + assert(!err && (total < MAX_ALLOC_SIZE)); +#else + total = num * size; +#endif + heap_t *heap = get_thread_heap(); + void *block = _rpmalloc_allocate(heap, total); + if (block) + memset_unsafe(block, 0, total); + return block; +} + +extern inline RPMALLOC_ALLOCATOR void * +rprealloc(void *ptr, size_t size) +{ +#if ENABLE_VALIDATE_ARGS + assert(size < MAX_ALLOC_SIZE); +#endif + heap_t *heap = get_thread_heap(); + return _rpmalloc_reallocate(heap, ptr, size, 0, 0); +} + +extern RPMALLOC_ALLOCATOR void * +rpaligned_realloc(void *ptr, size_t alignment, size_t size, size_t oldsize, + unsigned int flags) +{ +#if ENABLE_VALIDATE_ARGS + assert((size + alignment) >= size && (alignment <= _memory_page_size)); +#endif + heap_t *heap = get_thread_heap(); + return _rpmalloc_aligned_reallocate(heap, ptr, alignment, size, oldsize, flags); +} + +extern RPMALLOC_ALLOCATOR void * +rpaligned_alloc(size_t alignment, size_t size) +{ + heap_t *heap = get_thread_heap(); + return _rpmalloc_aligned_allocate(heap, alignment, size); +} + +extern inline RPMALLOC_ALLOCATOR void * +rpaligned_calloc(size_t alignment, size_t num, size_t size) +{ + size_t total; +#if ENABLE_VALIDATE_ARGS + int err = __builtin_umull_overflow(num, size, &total); + assert(!err && (total < MAX_ALLOC_SIZE)); +#else + total = num * size; +#endif + void *block = rpaligned_alloc(alignment, total); + if (block) + memset_unsafe(block, 0, total); + return block; +} + +extern inline RPMALLOC_ALLOCATOR void * +rpmemalign(size_t alignment, size_t size) +{ + return rpaligned_alloc(alignment, size); +} + +extern inline int +rpposix_memalign(void **memptr, size_t alignment, size_t size) +{ + if (memptr) + *memptr = rpaligned_alloc(alignment, size); + else + return EINVAL; + return *memptr ? 0 : ENOMEM; +} + +extern inline size_t +rpmalloc_usable_size(void *ptr) +{ + return (ptr ? _rpmalloc_usable_size(ptr) : 0); +} + +extern inline void +rpmalloc_thread_collect(void) +{ +} + +void rpmalloc_thread_statistics(rpmalloc_thread_statistics_t *stats) +{ + memset_unsafe(stats, 0, sizeof(rpmalloc_thread_statistics_t)); + heap_t *heap = get_thread_heap_raw(); + if (!heap) + return; + + for (size_t iclass = 0; iclass < SIZE_CLASS_COUNT; ++iclass) + { + size_class_t *size_class = _memory_size_class + iclass; + span_t *span = heap->size_class[iclass].partial_span; + while (span) + { + size_t free_count = span->list_size; + size_t block_count = size_class->block_count; + if (span->free_list_limit < block_count) + block_count = span->free_list_limit; + free_count += (block_count - span->used_count); + stats->sizecache = free_count * size_class->block_size; + span = span->next; + } + } + +#if ENABLE_THREAD_CACHE + for (size_t iclass = 0; iclass < LARGE_CLASS_COUNT; ++iclass) + { + span_cache_t *span_cache; + if (!iclass) + span_cache = &heap->span_cache; + else + span_cache = (span_cache_t *)(heap->span_large_cache + (iclass - 1)); + stats->spancache = span_cache->count * (iclass + 1) * _memory_span_size; + } +#endif + + span_t *deferred = (span_t *)atomic_load_ptr(&heap->span_free_deferred); + while (deferred) + { + if (deferred->size_class != SIZE_CLASS_HUGE) + stats->spancache = (size_t)deferred->span_count * _memory_span_size; + deferred = (span_t *)deferred->free_list; + } + +#if ENABLE_STATISTICS + stats->thread_to_global = (size_t)atomic_load64(&heap->thread_to_global); + stats->global_to_thread = (size_t)atomic_load64(&heap->global_to_thread); + + for (size_t iclass = 0; iclass < LARGE_CLASS_COUNT; ++iclass) + { + stats->span_use[iclass].current = (size_t)atomic_load32(&heap->span_use[iclass].current); + stats->span_use[iclass].peak = (size_t)atomic_load32(&heap->span_use[iclass].high); + stats->span_use[iclass].to_global = (size_t)atomic_load32(&heap->span_use[iclass].spans_to_global); + stats->span_use[iclass].from_global = (size_t)atomic_load32(&heap->span_use[iclass].spans_from_global); + stats->span_use[iclass].to_cache = (size_t)atomic_load32(&heap->span_use[iclass].spans_to_cache); + stats->span_use[iclass].from_cache = (size_t)atomic_load32(&heap->span_use[iclass].spans_from_cache); + stats->span_use[iclass].to_reserved = (size_t)atomic_load32(&heap->span_use[iclass].spans_to_reserved); + stats->span_use[iclass].from_reserved = (size_t)atomic_load32(&heap->span_use[iclass].spans_from_reserved); + stats->span_use[iclass].map_calls = (size_t)atomic_load32(&heap->span_use[iclass].spans_map_calls); + } + for (size_t iclass = 0; iclass < SIZE_CLASS_COUNT; ++iclass) + { + stats->size_use[iclass].alloc_current = (size_t)atomic_load32(&heap->size_class_use[iclass].alloc_current); + stats->size_use[iclass].alloc_peak = (size_t)heap->size_class_use[iclass].alloc_peak; + stats->size_use[iclass].alloc_total = (size_t)atomic_load32(&heap->size_class_use[iclass].alloc_total); + stats->size_use[iclass].free_total = (size_t)atomic_load32(&heap->size_class_use[iclass].free_total); + stats->size_use[iclass].spans_to_cache = (size_t)atomic_load32(&heap->size_class_use[iclass].spans_to_cache); + stats->size_use[iclass].spans_from_cache = (size_t)atomic_load32(&heap->size_class_use[iclass].spans_from_cache); + stats->size_use[iclass].spans_from_reserved = (size_t)atomic_load32(&heap->size_class_use[iclass].spans_from_reserved); + stats->size_use[iclass].map_calls = (size_t)atomic_load32(&heap->size_class_use[iclass].spans_map_calls); + } +#endif +} + +void rpmalloc_global_statistics(rpmalloc_global_statistics_t *stats) +{ + memset_unsafe(stats, 0, sizeof(rpmalloc_global_statistics_t)); +#if ENABLE_STATISTICS + stats->mapped = (size_t)atomic_load32(&_mapped_pages) * _memory_page_size; + stats->mapped_peak = (size_t)_mapped_pages_peak * _memory_page_size; + stats->mapped_total = (size_t)atomic_load32(&_mapped_total) * _memory_page_size; + stats->unmapped_total = (size_t)atomic_load32(&_unmapped_total) * _memory_page_size; + stats->huge_alloc = (size_t)atomic_load32(&_huge_pages_current) * _memory_page_size; + stats->huge_alloc_peak = (size_t)_huge_pages_peak * _memory_page_size; +#endif +#if ENABLE_GLOBAL_CACHE + for (size_t iclass = 0; iclass < LARGE_CLASS_COUNT; ++iclass) + stats->cached += _memory_span_cache[iclass].count * (iclass + 1) * _memory_span_size; +#endif +} + +#if ENABLE_STATISTICS + +static void +_memory_heap_dump_statistics(heap_t *heap, void *file) +{ + fprintf(file, "Heap %d stats:\n", heap->id); + fprintf(file, "Class CurAlloc PeakAlloc TotAlloc TotFree BlkSize BlkCount SpansCur SpansPeak PeakAllocMiB ToCacheMiB FromCacheMiB FromReserveMiB MmapCalls\n"); + for (size_t iclass = 0; iclass < SIZE_CLASS_COUNT; ++iclass) + { + if (!atomic_load32(&heap->size_class_use[iclass].alloc_total)) + continue; + fprintf(file, "%3u: %10u %10u %10u %10u %8u %8u %8d %9d %13zu %11zu %12zu %14zu %9u\n", (uint32_t)iclass, + atomic_load32(&heap->size_class_use[iclass].alloc_current), + heap->size_class_use[iclass].alloc_peak, + atomic_load32(&heap->size_class_use[iclass].alloc_total), + atomic_load32(&heap->size_class_use[iclass].free_total), + _memory_size_class[iclass].block_size, + _memory_size_class[iclass].block_count, + atomic_load32(&heap->size_class_use[iclass].spans_current), + heap->size_class_use[iclass].spans_peak, + ((size_t)heap->size_class_use[iclass].alloc_peak * (size_t)_memory_size_class[iclass].block_size) / (size_t)(1024 * 1024), + ((size_t)atomic_load32(&heap->size_class_use[iclass].spans_to_cache) * _memory_span_size) / (size_t)(1024 * 1024), + ((size_t)atomic_load32(&heap->size_class_use[iclass].spans_from_cache) * _memory_span_size) / (size_t)(1024 * 1024), + ((size_t)atomic_load32(&heap->size_class_use[iclass].spans_from_reserved) * _memory_span_size) / (size_t)(1024 * 1024), + atomic_load32(&heap->size_class_use[iclass].spans_map_calls)); + } + fprintf(file, "Spans Current Peak Deferred PeakMiB Cached ToCacheMiB FromCacheMiB ToReserveMiB FromReserveMiB ToGlobalMiB FromGlobalMiB MmapCalls\n"); + for (size_t iclass = 0; iclass < LARGE_CLASS_COUNT; ++iclass) + { + if (!atomic_load32(&heap->span_use[iclass].high) && !atomic_load32(&heap->span_use[iclass].spans_map_calls)) + continue; + fprintf(file, "%4u: %8d %8u %8u %8zu %7u %11zu %12zu %12zu %14zu %11zu %13zu %10u\n", (uint32_t)(iclass + 1), + atomic_load32(&heap->span_use[iclass].current), + atomic_load32(&heap->span_use[iclass].high), + atomic_load32(&heap->span_use[iclass].spans_deferred), + ((size_t)atomic_load32(&heap->span_use[iclass].high) * (size_t)_memory_span_size * (iclass + 1)) / (size_t)(1024 * 1024), +#if ENABLE_THREAD_CACHE + (unsigned int)(!iclass ? heap->span_cache.count : heap->span_large_cache[iclass - 1].count), + ((size_t)atomic_load32(&heap->span_use[iclass].spans_to_cache) * (iclass + 1) * _memory_span_size) / (size_t)(1024 * 1024), + ((size_t)atomic_load32(&heap->span_use[iclass].spans_from_cache) * (iclass + 1) * _memory_span_size) / (size_t)(1024 * 1024), +#else + 0, (size_t)0, (size_t)0, +#endif + ((size_t)atomic_load32(&heap->span_use[iclass].spans_to_reserved) * (iclass + 1) * _memory_span_size) / (size_t)(1024 * 1024), + ((size_t)atomic_load32(&heap->span_use[iclass].spans_from_reserved) * (iclass + 1) * _memory_span_size) / (size_t)(1024 * 1024), + ((size_t)atomic_load32(&heap->span_use[iclass].spans_to_global) * (size_t)_memory_span_size * (iclass + 1)) / (size_t)(1024 * 1024), + ((size_t)atomic_load32(&heap->span_use[iclass].spans_from_global) * (size_t)_memory_span_size * (iclass + 1)) / (size_t)(1024 * 1024), + atomic_load32(&heap->span_use[iclass].spans_map_calls)); + } + fprintf(file, "Full spans: %zu\n", heap->full_span_count); + fprintf(file, "ThreadToGlobalMiB GlobalToThreadMiB\n"); + fprintf(file, "%17zu %17zu\n", (size_t)atomic_load64(&heap->thread_to_global) / (size_t)(1024 * 1024), (size_t)atomic_load64(&heap->global_to_thread) / (size_t)(1024 * 1024)); +} + +#endif + +void rpmalloc_dump_statistics(void *file) +{ +#if ENABLE_STATISTICS + for (size_t list_idx = 0; list_idx < HEAP_ARRAY_SIZE; ++list_idx) + { + heap_t *heap = _memory_heaps[list_idx]; + while (heap) + { + int need_dump = 0; + for (size_t iclass = 0; !need_dump && (iclass < SIZE_CLASS_COUNT); ++iclass) + { + if (!atomic_load32(&heap->size_class_use[iclass].alloc_total)) + { + rpmalloc_assert(!atomic_load32(&heap->size_class_use[iclass].free_total), "Heap statistics counter mismatch"); + rpmalloc_assert(!atomic_load32(&heap->size_class_use[iclass].spans_map_calls), "Heap statistics counter mismatch"); + continue; + } + need_dump = 1; + } + for (size_t iclass = 0; !need_dump && (iclass < LARGE_CLASS_COUNT); ++iclass) + { + if (!atomic_load32(&heap->span_use[iclass].high) && !atomic_load32(&heap->span_use[iclass].spans_map_calls)) + continue; + need_dump = 1; + } + if (need_dump) + _memory_heap_dump_statistics(heap, file); + heap = heap->next_heap; + } + } + fprintf(file, "Global stats:\n"); + size_t huge_current = (size_t)atomic_load32(&_huge_pages_current) * _memory_page_size; + size_t huge_peak = (size_t)_huge_pages_peak * _memory_page_size; + fprintf(file, "HugeCurrentMiB HugePeakMiB\n"); + fprintf(file, "%14zu %11zu\n", huge_current / (size_t)(1024 * 1024), huge_peak / (size_t)(1024 * 1024)); + + fprintf(file, "GlobalCacheMiB\n"); + for (size_t iclass = 0; iclass < LARGE_CLASS_COUNT; ++iclass) + { + global_cache_t *cache = _memory_span_cache + iclass; + size_t global_cache = (size_t)cache->count * iclass * _memory_span_size; + + size_t global_overflow_cache = 0; + span_t *span = cache->overflow; + while (span) + { + global_overflow_cache += iclass * _memory_span_size; + span = span->next; + } + if (global_cache || global_overflow_cache || cache->insert_count || cache->extract_count) + fprintf(file, "%4zu: %8zuMiB (%8zuMiB overflow) %14zu insert %14zu extract\n", iclass + 1, global_cache / (size_t)(1024 * 1024), global_overflow_cache / (size_t)(1024 * 1024), cache->insert_count, cache->extract_count); + } + + size_t mapped = (size_t)atomic_load32(&_mapped_pages) * _memory_page_size; + size_t mapped_os = (size_t)atomic_load32(&_mapped_pages_os) * _memory_page_size; + size_t mapped_peak = (size_t)_mapped_pages_peak * _memory_page_size; + size_t mapped_total = (size_t)atomic_load32(&_mapped_total) * _memory_page_size; + size_t unmapped_total = (size_t)atomic_load32(&_unmapped_total) * _memory_page_size; + fprintf(file, "MappedMiB MappedOSMiB MappedPeakMiB MappedTotalMiB UnmappedTotalMiB\n"); + fprintf(file, "%9zu %11zu %13zu %14zu %16zu\n", + mapped / (size_t)(1024 * 1024), + mapped_os / (size_t)(1024 * 1024), + mapped_peak / (size_t)(1024 * 1024), + mapped_total / (size_t)(1024 * 1024), + unmapped_total / (size_t)(1024 * 1024)); + + fprintf(file, "\n"); +#if 0 + int64_t allocated = atomic_load64(&_allocation_counter); + int64_t deallocated = atomic_load64(&_deallocation_counter); + fprintf(file, "Allocation count: %lli\n", allocated); + fprintf(file, "Deallocation count: %lli\n", deallocated); + fprintf(file, "Current allocations: %lli\n", (allocated - deallocated)); + fprintf(file, "Master spans: %d\n", atomic_load32(&_master_spans)); + fprintf(file, "Dangling master spans: %d\n", atomic_load32(&_unmapped_master_spans)); +#endif +#endif + (void)sizeof(file); +} + +#if RPMALLOC_FIRST_CLASS_HEAPS + +extern inline rpmalloc_heap_t * +rpmalloc_heap_acquire(void) +{ + // Must be a pristine heap from newly mapped memory pages, or else memory blocks + // could already be allocated from the heap which would (wrongly) be released when + // heap is cleared with rpmalloc_heap_free_all(). Also heaps guaranteed to be + // pristine from the dedicated orphan list can be used. + heap_t *heap = _rpmalloc_heap_allocate(1); + heap->owner_thread = 0; + _rpmalloc_stat_inc(&_memory_active_heaps); + return heap; +} + +extern inline void +rpmalloc_heap_release(rpmalloc_heap_t *heap) +{ + if (heap) + _rpmalloc_heap_release(heap, 1, 1); +} + +extern inline RPMALLOC_ALLOCATOR void * +rpmalloc_heap_alloc(rpmalloc_heap_t *heap, size_t size) +{ +#if ENABLE_VALIDATE_ARGS + assert(size < MAX_ALLOC_SIZE); +#endif + return _rpmalloc_allocate(heap, size); +} + +extern inline RPMALLOC_ALLOCATOR void * +rpmalloc_heap_aligned_alloc(rpmalloc_heap_t *heap, size_t alignment, size_t size) +{ +#if ENABLE_VALIDATE_ARGS + assert(size < MAX_ALLOC_SIZE); +#endif + return _rpmalloc_aligned_allocate(heap, alignment, size); +} + +extern inline RPMALLOC_ALLOCATOR void * +rpmalloc_heap_calloc(rpmalloc_heap_t *heap, size_t num, size_t size) +{ + return rpmalloc_heap_aligned_calloc(heap, 0, num, size); +} + +extern inline RPMALLOC_ALLOCATOR void * +rpmalloc_heap_aligned_calloc(rpmalloc_heap_t *heap, size_t alignment, size_t num, size_t size) +{ + size_t total; +#if ENABLE_VALIDATE_ARGS + int err = __builtin_umull_overflow(num, size, &total); + assert(!err && (total < MAX_ALLOC_SIZE)); +#else + total = num * size; +#endif + void *block = _rpmalloc_aligned_allocate(heap, alignment, total); + if (block) + memset_unsafe(block, 0, total); + return block; +} + +extern inline RPMALLOC_ALLOCATOR void * +rpmalloc_heap_realloc(rpmalloc_heap_t *heap, void *ptr, size_t size, unsigned int flags) +{ +#if ENABLE_VALIDATE_ARGS + assert(size < MAX_ALLOC_SIZE); +#endif + return _rpmalloc_reallocate(heap, ptr, size, 0, flags); +} + +extern inline RPMALLOC_ALLOCATOR void * +rpmalloc_heap_aligned_realloc(rpmalloc_heap_t *heap, void *ptr, size_t alignment, size_t size, unsigned int flags) +{ +#if ENABLE_VALIDATE_ARGS + assert((size + alignment) >= size && (alignment <= _memory_page_size)); +#endif + return _rpmalloc_aligned_reallocate(heap, ptr, alignment, size, 0, flags); +} + +extern inline void +rpmalloc_heap_free(rpmalloc_heap_t *heap, void *ptr) +{ + (void)sizeof(heap); + _rpmalloc_deallocate(ptr); +} + +extern inline void +rpmalloc_heap_free_all(rpmalloc_heap_t *heap) +{ + span_t *span; + span_t *next_span; + + _rpmalloc_heap_cache_adopt_deferred(heap, 0); + + for (size_t iclass = 0; iclass < SIZE_CLASS_COUNT; ++iclass) + { + span = heap->size_class[iclass].partial_span; + while (span) + { + next_span = span->next; + _rpmalloc_heap_cache_insert(heap, span); + span = next_span; + } + heap->size_class[iclass].partial_span = 0; + span = heap->full_span[iclass]; + while (span) + { + next_span = span->next; + _rpmalloc_heap_cache_insert(heap, span); + span = next_span; + } + } + memset_unsafe(heap->size_class, 0, sizeof(heap->size_class)); + memset_unsafe(heap->full_span, 0, sizeof(heap->full_span)); + + span = heap->large_huge_span; + while (span) + { + next_span = span->next; + if (UNEXPECTED(span->size_class == SIZE_CLASS_HUGE)) + _rpmalloc_deallocate_huge(span); + else + _rpmalloc_heap_cache_insert(heap, span); + span = next_span; + } + heap->large_huge_span = 0; + heap->full_span_count = 0; + +#if ENABLE_THREAD_CACHE + for (size_t iclass = 0; iclass < LARGE_CLASS_COUNT; ++iclass) + { + span_cache_t *span_cache; + if (!iclass) + span_cache = &heap->span_cache; + else + span_cache = (span_cache_t *)(heap->span_large_cache + (iclass - 1)); + if (!span_cache->count) + continue; +#if ENABLE_GLOBAL_CACHE + _rpmalloc_stat_add64(&heap->thread_to_global, span_cache->count * (iclass + 1) * _memory_span_size); + _rpmalloc_stat_add(&heap->span_use[iclass].spans_to_global, span_cache->count); + _rpmalloc_global_cache_insert_spans(span_cache->span, iclass + 1, span_cache->count); +#else + for (size_t ispan = 0; ispan < span_cache->count; ++ispan) + _rpmalloc_span_unmap(span_cache->span[ispan]); +#endif + span_cache->count = 0; + } +#endif + +#if ENABLE_STATISTICS + for (size_t iclass = 0; iclass < SIZE_CLASS_COUNT; ++iclass) + { + atomic_store32(&heap->size_class_use[iclass].alloc_current, 0); + atomic_store32(&heap->size_class_use[iclass].spans_current, 0); + } + for (size_t iclass = 0; iclass < LARGE_CLASS_COUNT; ++iclass) + { + atomic_store32(&heap->span_use[iclass].current, 0); + } +#endif +} + +extern inline void +rpmalloc_heap_thread_set_current(rpmalloc_heap_t *heap) +{ + heap_t *prev_heap = get_thread_heap_raw(); + if (prev_heap != heap) + { + set_thread_heap(heap); + if (prev_heap) + rpmalloc_heap_release(prev_heap); + } +} + +#endif + +#if ENABLE_PRELOAD || ENABLE_OVERRIDE + +#include "malloc.c" + +#endif diff --git a/core/memory/heap_allocators/rpmalloc/rpmalloc.h b/core/memory/heap_allocators/rpmalloc/rpmalloc.h new file mode 100644 index 0000000..f79c162 --- /dev/null +++ b/core/memory/heap_allocators/rpmalloc/rpmalloc.h @@ -0,0 +1,371 @@ +/* rpmalloc.h - Memory allocator - Public Domain - 2016 Mattias Jansson + * + * This library provides a cross-platform lock free thread caching malloc implementation in C11. + * The latest source code is always available at + * + * https://github.com/mjansson/rpmalloc + * + * This library is put in the public domain; you can redistribute it and/or modify it without any restrictions. + * + */ + +#pragma once + +#include + +#ifdef __cplusplus +extern "C" +{ +#endif + +#if defined(__clang__) || defined(__GNUC__) +#define RPMALLOC_EXPORT __attribute__((visibility("default"))) +#define RPMALLOC_ALLOCATOR +#if (defined(__clang_major__) && (__clang_major__ < 4)) || (defined(__GNUC__) && defined(ENABLE_PRELOAD) && ENABLE_PRELOAD) +#define RPMALLOC_ATTRIB_MALLOC +#define RPMALLOC_ATTRIB_ALLOC_SIZE(size) +#define RPMALLOC_ATTRIB_ALLOC_SIZE2(count, size) +#else +#define RPMALLOC_ATTRIB_MALLOC __attribute__((__malloc__)) +#define RPMALLOC_ATTRIB_ALLOC_SIZE(size) __attribute__((alloc_size(size))) +#define RPMALLOC_ATTRIB_ALLOC_SIZE2(count, size) __attribute__((alloc_size(count, size))) +#endif +#define RPMALLOC_CDECL +#elif defined(_MSC_VER) +#define RPMALLOC_EXPORT +#define RPMALLOC_ALLOCATOR __declspec(allocator) __declspec(restrict) +#define RPMALLOC_ATTRIB_MALLOC +#define RPMALLOC_ATTRIB_ALLOC_SIZE(size) +#define RPMALLOC_ATTRIB_ALLOC_SIZE2(count, size) +#define RPMALLOC_CDECL __cdecl +#else +#define RPMALLOC_EXPORT +#define RPMALLOC_ALLOCATOR +#define RPMALLOC_ATTRIB_MALLOC +#define RPMALLOC_ATTRIB_ALLOC_SIZE(size) +#define RPMALLOC_ATTRIB_ALLOC_SIZE2(count, size) +#define RPMALLOC_CDECL +#endif + +//! Define RPMALLOC_CONFIGURABLE to enable configuring sizes. Will introduce +// a very small overhead due to some size calculations not being compile time constants +#ifndef RPMALLOC_CONFIGURABLE +#define RPMALLOC_CONFIGURABLE 1 +#endif + +//! Define RPMALLOC_FIRST_CLASS_HEAPS to enable heap based API (rpmalloc_heap_* functions). +// Will introduce a very small overhead to track fully allocated spans in heaps +#ifndef RPMALLOC_FIRST_CLASS_HEAPS +#define RPMALLOC_FIRST_CLASS_HEAPS 0 +#endif + +//! Flag to rpaligned_realloc to not preserve content in reallocation +#define RPMALLOC_NO_PRESERVE 1 +//! Flag to rpaligned_realloc to fail and return null pointer if grow cannot be done in-place, +// in which case the original pointer is still valid (just like a call to realloc which failes to allocate +// a new block). +#define RPMALLOC_GROW_OR_FAIL 2 + + typedef struct rpmalloc_global_statistics_t + { + //! Current amount of virtual memory mapped, all of which might not have been committed (only if ENABLE_STATISTICS=1) + size_t mapped; + //! Peak amount of virtual memory mapped, all of which might not have been committed (only if ENABLE_STATISTICS=1) + size_t mapped_peak; + //! Current amount of memory in global caches for small and medium sizes (<32KiB) + size_t cached; + //! Current amount of memory allocated in huge allocations, i.e larger than LARGE_SIZE_LIMIT which is 2MiB by default (only if ENABLE_STATISTICS=1) + size_t huge_alloc; + //! Peak amount of memory allocated in huge allocations, i.e larger than LARGE_SIZE_LIMIT which is 2MiB by default (only if ENABLE_STATISTICS=1) + size_t huge_alloc_peak; + //! Total amount of memory mapped since initialization (only if ENABLE_STATISTICS=1) + size_t mapped_total; + //! Total amount of memory unmapped since initialization (only if ENABLE_STATISTICS=1) + size_t unmapped_total; + } rpmalloc_global_statistics_t; + + typedef struct rpmalloc_thread_statistics_t + { + //! Current number of bytes available in thread size class caches for small and medium sizes (<32KiB) + size_t sizecache; + //! Current number of bytes available in thread span caches for small and medium sizes (<32KiB) + size_t spancache; + //! Total number of bytes transitioned from thread cache to global cache (only if ENABLE_STATISTICS=1) + size_t thread_to_global; + //! Total number of bytes transitioned from global cache to thread cache (only if ENABLE_STATISTICS=1) + size_t global_to_thread; + //! Per span count statistics (only if ENABLE_STATISTICS=1) + struct + { + //! Currently used number of spans + size_t current; + //! High water mark of spans used + size_t peak; + //! Number of spans transitioned to global cache + size_t to_global; + //! Number of spans transitioned from global cache + size_t from_global; + //! Number of spans transitioned to thread cache + size_t to_cache; + //! Number of spans transitioned from thread cache + size_t from_cache; + //! Number of spans transitioned to reserved state + size_t to_reserved; + //! Number of spans transitioned from reserved state + size_t from_reserved; + //! Number of raw memory map calls (not hitting the reserve spans but resulting in actual OS mmap calls) + size_t map_calls; + } span_use[64]; + //! Per size class statistics (only if ENABLE_STATISTICS=1) + struct + { + //! Current number of allocations + size_t alloc_current; + //! Peak number of allocations + size_t alloc_peak; + //! Total number of allocations + size_t alloc_total; + //! Total number of frees + size_t free_total; + //! Number of spans transitioned to cache + size_t spans_to_cache; + //! Number of spans transitioned from cache + size_t spans_from_cache; + //! Number of spans transitioned from reserved state + size_t spans_from_reserved; + //! Number of raw memory map calls (not hitting the reserve spans but resulting in actual OS mmap calls) + size_t map_calls; + } size_use[128]; + } rpmalloc_thread_statistics_t; + + typedef struct rpmalloc_config_t + { + //! Map memory pages for the given number of bytes. The returned address MUST be + // aligned to the rpmalloc span size, which will always be a power of two. + // Optionally the function can store an alignment offset in the offset variable + // in case it performs alignment and the returned pointer is offset from the + // actual start of the memory region due to this alignment. The alignment offset + // will be passed to the memory unmap function. The alignment offset MUST NOT be + // larger than 65535 (storable in an uint16_t), if it is you must use natural + // alignment to shift it into 16 bits. If you set a memory_map function, you + // must also set a memory_unmap function or else the default implementation will + // be used for both. This function must be thread safe, it can be called by + // multiple threads simultaneously. + void *(*memory_map)(size_t size, size_t *offset); + //! Unmap the memory pages starting at address and spanning the given number of bytes. + // If release is set to non-zero, the unmap is for an entire span range as returned by + // a previous call to memory_map and that the entire range should be released. The + // release argument holds the size of the entire span range. If release is set to 0, + // the unmap is a partial decommit of a subset of the mapped memory range. + // If you set a memory_unmap function, you must also set a memory_map function or + // else the default implementation will be used for both. This function must be thread + // safe, it can be called by multiple threads simultaneously. + void (*memory_unmap)(void *address, size_t size, size_t offset, size_t release); + //! Called when an assert fails, if asserts are enabled. Will use the standard assert() + // if this is not set. + void (*error_callback)(const char *message); + //! Called when a call to map memory pages fails (out of memory). If this callback is + // not set or returns zero the library will return a null pointer in the allocation + // call. If this callback returns non-zero the map call will be retried. The argument + // passed is the number of bytes that was requested in the map call. Only used if + // the default system memory map function is used (memory_map callback is not set). + int (*map_fail_callback)(size_t size); + //! Size of memory pages. The page size MUST be a power of two. All memory mapping + // requests to memory_map will be made with size set to a multiple of the page size. + // Used if RPMALLOC_CONFIGURABLE is defined to 1, otherwise system page size is used. + size_t page_size; + //! Size of a span of memory blocks. MUST be a power of two, and in [4096,262144] + // range (unless 0 - set to 0 to use the default span size). Used if RPMALLOC_CONFIGURABLE + // is defined to 1. + size_t span_size; + //! Number of spans to map at each request to map new virtual memory blocks. This can + // be used to minimize the system call overhead at the cost of virtual memory address + // space. The extra mapped pages will not be written until actually used, so physical + // committed memory should not be affected in the default implementation. Will be + // aligned to a multiple of spans that match memory page size in case of huge pages. + size_t span_map_count; + //! Enable use of large/huge pages. If this flag is set to non-zero and page size is + // zero, the allocator will try to enable huge pages and auto detect the configuration. + // If this is set to non-zero and page_size is also non-zero, the allocator will + // assume huge pages have been configured and enabled prior to initializing the + // allocator. + // For Windows, see https://docs.microsoft.com/en-us/windows/desktop/memory/large-page-support + // For Linux, see https://www.kernel.org/doc/Documentation/vm/hugetlbpage.txt + int enable_huge_pages; + //! Respectively allocated pages and huge allocated pages names for systems + // supporting it to be able to distinguish among anonymous regions. + const char *page_name; + const char *huge_page_name; + } rpmalloc_config_t; + + //! Initialize allocator with default configuration + RPMALLOC_EXPORT int + rpmalloc_initialize(void); + + //! Initialize allocator with given configuration + RPMALLOC_EXPORT int + rpmalloc_initialize_config(const rpmalloc_config_t *config); + + //! Get allocator configuration + RPMALLOC_EXPORT const rpmalloc_config_t * + rpmalloc_config(void); + + //! Finalize allocator + RPMALLOC_EXPORT void + rpmalloc_finalize(void); + + //! Initialize allocator for calling thread + RPMALLOC_EXPORT void + rpmalloc_thread_initialize(void); + + //! Finalize allocator for calling thread + RPMALLOC_EXPORT void + rpmalloc_thread_finalize(int release_caches); + + //! Perform deferred deallocations pending for the calling thread heap + RPMALLOC_EXPORT void + rpmalloc_thread_collect(void); + + //! Query if allocator is initialized for calling thread + RPMALLOC_EXPORT int + rpmalloc_is_thread_initialized(void); + + //! Get per-thread statistics + RPMALLOC_EXPORT void + rpmalloc_thread_statistics(rpmalloc_thread_statistics_t *stats); + + //! Get global statistics + RPMALLOC_EXPORT void + rpmalloc_global_statistics(rpmalloc_global_statistics_t *stats); + + //! Dump all statistics in human readable format to file (should be a FILE*) + RPMALLOC_EXPORT void + rpmalloc_dump_statistics(void *file); + + //! Allocate a memory block of at least the given size + RPMALLOC_EXPORT RPMALLOC_ALLOCATOR void * + rpmalloc(size_t size) RPMALLOC_ATTRIB_MALLOC RPMALLOC_ATTRIB_ALLOC_SIZE(1); + + //! Free the given memory block + RPMALLOC_EXPORT void + rpfree(void *ptr); + + //! Allocate a memory block of at least the given size and zero initialize it + RPMALLOC_EXPORT RPMALLOC_ALLOCATOR void * + rpcalloc(size_t num, size_t size) RPMALLOC_ATTRIB_MALLOC RPMALLOC_ATTRIB_ALLOC_SIZE2(1, 2); + + //! Reallocate the given block to at least the given size + RPMALLOC_EXPORT RPMALLOC_ALLOCATOR void * + rprealloc(void *ptr, size_t size) RPMALLOC_ATTRIB_MALLOC RPMALLOC_ATTRIB_ALLOC_SIZE(2); + + //! Reallocate the given block to at least the given size and alignment, + // with optional control flags (see RPMALLOC_NO_PRESERVE). + // Alignment must be a power of two and a multiple of sizeof(void*), + // and should ideally be less than memory page size. A caveat of rpmalloc + // internals is that this must also be strictly less than the span size (default 64KiB) + RPMALLOC_EXPORT RPMALLOC_ALLOCATOR void * + rpaligned_realloc(void *ptr, size_t alignment, size_t size, size_t oldsize, unsigned int flags) RPMALLOC_ATTRIB_MALLOC RPMALLOC_ATTRIB_ALLOC_SIZE(3); + + //! Allocate a memory block of at least the given size and alignment. + // Alignment must be a power of two and a multiple of sizeof(void*), + // and should ideally be less than memory page size. A caveat of rpmalloc + // internals is that this must also be strictly less than the span size (default 64KiB) + RPMALLOC_EXPORT RPMALLOC_ALLOCATOR void * + rpaligned_alloc(size_t alignment, size_t size) RPMALLOC_ATTRIB_MALLOC RPMALLOC_ATTRIB_ALLOC_SIZE(2); + + //! Allocate a memory block of at least the given size and alignment, and zero initialize it. + // Alignment must be a power of two and a multiple of sizeof(void*), + // and should ideally be less than memory page size. A caveat of rpmalloc + // internals is that this must also be strictly less than the span size (default 64KiB) + RPMALLOC_EXPORT RPMALLOC_ALLOCATOR void * + rpaligned_calloc(size_t alignment, size_t num, size_t size) RPMALLOC_ATTRIB_MALLOC RPMALLOC_ATTRIB_ALLOC_SIZE2(2, 3); + + //! Allocate a memory block of at least the given size and alignment. + // Alignment must be a power of two and a multiple of sizeof(void*), + // and should ideally be less than memory page size. A caveat of rpmalloc + // internals is that this must also be strictly less than the span size (default 64KiB) + RPMALLOC_EXPORT RPMALLOC_ALLOCATOR void * + rpmemalign(size_t alignment, size_t size) RPMALLOC_ATTRIB_MALLOC RPMALLOC_ATTRIB_ALLOC_SIZE(2); + + //! Allocate a memory block of at least the given size and alignment. + // Alignment must be a power of two and a multiple of sizeof(void*), + // and should ideally be less than memory page size. A caveat of rpmalloc + // internals is that this must also be strictly less than the span size (default 64KiB) + RPMALLOC_EXPORT int + rpposix_memalign(void **memptr, size_t alignment, size_t size); + + //! Query the usable size of the given memory block (from given pointer to the end of block) + RPMALLOC_EXPORT size_t + rpmalloc_usable_size(void *ptr); + +#if RPMALLOC_FIRST_CLASS_HEAPS + + //! Heap type + typedef struct heap_t rpmalloc_heap_t; + + //! Acquire a new heap. Will reuse existing released heaps or allocate memory for a new heap + // if none available. Heap API is implemented with the strict assumption that only one single + // thread will call heap functions for a given heap at any given time, no functions are thread safe. + RPMALLOC_EXPORT rpmalloc_heap_t * + rpmalloc_heap_acquire(void); + + //! Release a heap (does NOT free the memory allocated by the heap, use rpmalloc_heap_free_all before destroying the heap). + // Releasing a heap will enable it to be reused by other threads. Safe to pass a null pointer. + RPMALLOC_EXPORT void + rpmalloc_heap_release(rpmalloc_heap_t *heap); + + //! Allocate a memory block of at least the given size using the given heap. + RPMALLOC_EXPORT RPMALLOC_ALLOCATOR void * + rpmalloc_heap_alloc(rpmalloc_heap_t *heap, size_t size) RPMALLOC_ATTRIB_MALLOC RPMALLOC_ATTRIB_ALLOC_SIZE(2); + + //! Allocate a memory block of at least the given size using the given heap. The returned + // block will have the requested alignment. Alignment must be a power of two and a multiple of sizeof(void*), + // and should ideally be less than memory page size. A caveat of rpmalloc + // internals is that this must also be strictly less than the span size (default 64KiB). + RPMALLOC_EXPORT RPMALLOC_ALLOCATOR void * + rpmalloc_heap_aligned_alloc(rpmalloc_heap_t *heap, size_t alignment, size_t size) RPMALLOC_ATTRIB_MALLOC RPMALLOC_ATTRIB_ALLOC_SIZE(3); + + //! Allocate a memory block of at least the given size using the given heap and zero initialize it. + RPMALLOC_EXPORT RPMALLOC_ALLOCATOR void * + rpmalloc_heap_calloc(rpmalloc_heap_t *heap, size_t num, size_t size) RPMALLOC_ATTRIB_MALLOC RPMALLOC_ATTRIB_ALLOC_SIZE2(2, 3); + + //! Allocate a memory block of at least the given size using the given heap and zero initialize it. The returned + // block will have the requested alignment. Alignment must either be zero, or a power of two and a multiple of sizeof(void*), + // and should ideally be less than memory page size. A caveat of rpmalloc + // internals is that this must also be strictly less than the span size (default 64KiB). + RPMALLOC_EXPORT RPMALLOC_ALLOCATOR void * + rpmalloc_heap_aligned_calloc(rpmalloc_heap_t *heap, size_t alignment, size_t num, size_t size) RPMALLOC_ATTRIB_MALLOC RPMALLOC_ATTRIB_ALLOC_SIZE2(2, 3); + + //! Reallocate the given block to at least the given size. The memory block MUST be allocated + // by the same heap given to this function. + RPMALLOC_EXPORT RPMALLOC_ALLOCATOR void * + rpmalloc_heap_realloc(rpmalloc_heap_t *heap, void *ptr, size_t size, unsigned int flags) RPMALLOC_ATTRIB_MALLOC RPMALLOC_ATTRIB_ALLOC_SIZE(3); + + //! Reallocate the given block to at least the given size. The memory block MUST be allocated + // by the same heap given to this function. The returned block will have the requested alignment. + // Alignment must be either zero, or a power of two and a multiple of sizeof(void*), and should ideally be + // less than memory page size. A caveat of rpmalloc internals is that this must also be strictly less than + // the span size (default 64KiB). + RPMALLOC_EXPORT RPMALLOC_ALLOCATOR void * + rpmalloc_heap_aligned_realloc(rpmalloc_heap_t *heap, void *ptr, size_t alignment, size_t size, unsigned int flags) RPMALLOC_ATTRIB_MALLOC RPMALLOC_ATTRIB_ALLOC_SIZE(4); + + //! Free the given memory block from the given heap. The memory block MUST be allocated + // by the same heap given to this function. + RPMALLOC_EXPORT void + rpmalloc_heap_free(rpmalloc_heap_t *heap, void *ptr); + + //! Free all memory allocated by the heap + RPMALLOC_EXPORT void + rpmalloc_heap_free_all(rpmalloc_heap_t *heap); + + //! Set the given heap as the current heap for the calling thread. A heap MUST only be current heap + // for a single thread, a heap can never be shared between multiple threads. The previous + // current heap for the calling thread is released to be reused by other threads. + RPMALLOC_EXPORT void + rpmalloc_heap_thread_set_current(rpmalloc_heap_t *heap); + +#endif + +#ifdef __cplusplus +} +#endif diff --git a/core/memory/heap_allocators/rpmalloc/rpmalloc_compat.cpp b/core/memory/heap_allocators/rpmalloc/rpmalloc_compat.cpp new file mode 100644 index 0000000..c366f51 --- /dev/null +++ b/core/memory/heap_allocators/rpmalloc/rpmalloc_compat.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 +#include +#include +#include +#include + +// #include "rpmalloc.c" +#include "../../../../kernel.h" + +struct heap_t +{ + char pad[56408]; +}; + +static heap_t *__rpmalloc_tls_heap = nullptr; +EXTERNC heap_t **__memory_thread_heap(void) +{ + if (unlikely(!TaskManager || !thisThread)) + { + if (unlikely(!__rpmalloc_tls_heap)) + { + __rpmalloc_tls_heap = (heap_t *)KernelAllocator.RequestPages(TO_PAGES(sizeof(heap_t))); + debug("rpmalloc TLS heap: %#lx", __rpmalloc_tls_heap); + memset(__rpmalloc_tls_heap, 0, sizeof(heap_t)); + assert(__rpmalloc_tls_heap); + } + return &__rpmalloc_tls_heap; + } + return &__rpmalloc_tls_heap; + heap_t *heap = (heap_t *)thisThread->TLS.pBase; + return (heap_t **)heap; +} + +EXTERNC uintptr_t __get_tid(void) +{ + if (unlikely(!TaskManager || !thisThread)) + return (uintptr_t)-1; + return thisThread->ID; +} + +EXTERNC long __rpmalloc_sysconf(int name) +{ + switch (name) + { + case _SC_PAGESIZE: + return PAGE_SIZE; + default: + return -1; + } +} + +EXTERNC void *__rpmalloc_mmap(void *addr, size_t length, int, int, int fd, off_t offset) +{ + assert(addr == 0 && fd == -1 && offset == 0); + + void *ptr = KernelAllocator.RequestPages(TO_PAGES(length)); + debug("Requested %d pages, got %p", TO_PAGES(length), ptr); + if (ptr == nullptr) + return MAP_FAILED; + return ptr; +} + +EXTERNC int __rpmalloc_munmap(void *addr, size_t length) +{ + KernelAllocator.FreePages(addr, TO_PAGES(length)); + debug("Freed %d pages at %p", TO_PAGES(length), addr); + return 0; +} + +EXTERNC int __rpmalloc_posix_madvise(void *addr, size_t length, int advice) +{ + function("%#lx %d %d", addr, length, advice); + return 0; +} diff --git a/core/memory/memory.cpp b/core/memory/memory.cpp index d3dc459..e551880 100644 --- a/core/memory/memory.cpp +++ b/core/memory/memory.cpp @@ -26,6 +26,7 @@ #include "heap_allocators/Xalloc/Xalloc.hpp" #include "heap_allocators/liballoc_1_1/liballoc_1_1.h" +#include "heap_allocators/rpmalloc/rpmalloc.h" #include "../../kernel.h" // #define DEBUG_ALLOCATIONS 1 @@ -72,7 +73,7 @@ NIF void tracepagetable(PageTable *pt) NIF void MapFromZero(PageTable *PT) { debug("Mapping from 0x0 to %#llx", bInfo.Memory.Size); - Virtual va = Virtual(PT); + Virtual vmm = Virtual(PT); size_t MemSize = bInfo.Memory.Size; if (Page1GBSupport && PSESupport) @@ -80,29 +81,29 @@ NIF void MapFromZero(PageTable *PT) /* Map the first 100MB of memory as 4KB pages */ // uintptr_t Physical4KBSectionStart = 0x10000000; - // va.Map((void *)0, + // vmm.Map((void *)0, // (void *)0, // Physical4KBSectionStart, - // PTFlag::RW); + // RW); - // va.Map((void *)Physical4KBSectionStart, + // vmm.Map((void *)Physical4KBSectionStart, // (void *)Physical4KBSectionStart, // MemSize - Physical4KBSectionStart, - // PTFlag::RW, + // RW, // Virtual::MapType::OneGiB); - va.Map((void *)0, (void *)0, MemSize, PTFlag::RW); + vmm.Map((void *)0, (void *)0, MemSize, RW); } else - va.Map((void *)0, (void *)0, MemSize, PTFlag::RW); + vmm.Map((void *)0, (void *)0, MemSize, RW); - va.Unmap((void *)0); + vmm.Unmap((void *)0); } -NIF void MapFramebuffer(PageTable *PT, bool PSE, bool OneGB) +NIF void MapFramebuffer(PageTable *PT) { debug("Mapping Framebuffer"); - Virtual va = Virtual(PT); + Virtual vmm = Virtual(PT); int itrfb = 0; while (1) { @@ -111,17 +112,17 @@ NIF void MapFramebuffer(PageTable *PT, bool PSE, bool OneGB) size_t fbSize = bInfo.Framebuffer[itrfb].Pitch * bInfo.Framebuffer[itrfb].Height; - if (PSE && OneGB) + if (PSESupport && Page1GBSupport) { - va.OptimizedMap(bInfo.Framebuffer[itrfb].BaseAddress, - bInfo.Framebuffer[itrfb].BaseAddress, - fbSize, PTFlag::RW | PTFlag::US | PTFlag::G); + vmm.OptimizedMap(bInfo.Framebuffer[itrfb].BaseAddress, + bInfo.Framebuffer[itrfb].BaseAddress, + fbSize, RW | US | G); } else { - va.Map(bInfo.Framebuffer[itrfb].BaseAddress, - bInfo.Framebuffer[itrfb].BaseAddress, - fbSize, PTFlag::RW | PTFlag::US | PTFlag::G); + vmm.Map(bInfo.Framebuffer[itrfb].BaseAddress, + bInfo.Framebuffer[itrfb].BaseAddress, + fbSize, RW | US | G); } itrfb++; } @@ -176,14 +177,14 @@ NIF void MapKernel(PageTable *PT) uintptr_t BaseKernelMapAddress = (uintptr_t)bInfo.Kernel.PhysicalBase; debug("Base kernel map address: %#lx", BaseKernelMapAddress); uintptr_t k; - Virtual va = Virtual(PT); + Virtual vmm = Virtual(PT); /* Bootstrap section */ if (BaseKernelMapAddress == BootstrapStart) { for (k = BootstrapStart; k < BootstrapEnd; k += PAGE_SIZE) { - va.Map((void *)k, (void *)BaseKernelMapAddress, PTFlag::RW | PTFlag::G); + vmm.Map((void *)k, (void *)BaseKernelMapAddress, RW | G); KernelAllocator.ReservePage((void *)BaseKernelMapAddress); BaseKernelMapAddress += PAGE_SIZE; } @@ -197,7 +198,7 @@ NIF void MapKernel(PageTable *PT) /* Text section */ for (k = KernelTextStart; k < KernelTextEnd; k += PAGE_SIZE) { - va.Map((void *)k, (void *)BaseKernelMapAddress, PTFlag::RW | PTFlag::G); + vmm.Map((void *)k, (void *)BaseKernelMapAddress, RW | G); KernelAllocator.ReservePage((void *)BaseKernelMapAddress); BaseKernelMapAddress += PAGE_SIZE; } @@ -205,7 +206,7 @@ NIF void MapKernel(PageTable *PT) /* Data section */ for (k = KernelDataStart; k < KernelDataEnd; k += PAGE_SIZE) { - va.Map((void *)k, (void *)BaseKernelMapAddress, PTFlag::RW | PTFlag::G); + vmm.Map((void *)k, (void *)BaseKernelMapAddress, RW | G); KernelAllocator.ReservePage((void *)BaseKernelMapAddress); BaseKernelMapAddress += PAGE_SIZE; } @@ -213,7 +214,7 @@ NIF void MapKernel(PageTable *PT) /* Read only data section */ for (k = KernelRoDataStart; k < KernelRoDataEnd; k += PAGE_SIZE) { - va.Map((void *)k, (void *)BaseKernelMapAddress, PTFlag::G); + vmm.Map((void *)k, (void *)BaseKernelMapAddress, G); KernelAllocator.ReservePage((void *)BaseKernelMapAddress); BaseKernelMapAddress += PAGE_SIZE; } @@ -221,7 +222,7 @@ NIF void MapKernel(PageTable *PT) /* Block starting symbol section */ for (k = KernelBssStart; k < KernelBssEnd; k += PAGE_SIZE) { - va.Map((void *)k, (void *)BaseKernelMapAddress, PTFlag::RW | PTFlag::G); + vmm.Map((void *)k, (void *)BaseKernelMapAddress, RW | G); KernelAllocator.ReservePage((void *)BaseKernelMapAddress); BaseKernelMapAddress += PAGE_SIZE; } @@ -233,10 +234,63 @@ NIF void MapKernel(PageTable *PT) { for (k = KernelFileStart; k < KernelFileEnd; k += PAGE_SIZE) { - va.Map((void *)k, (void *)k, PTFlag::G); + vmm.Map((void *)k, (void *)k, G); KernelAllocator.ReservePage((void *)k); } } + else + info("Cannot determine kernel file address. Ignoring."); +} + +NIF void CreatePageTable(PageTable *pt) +{ + static int check_cpuid = 0; + + if (!check_cpuid++) + { + if (strcmp(CPU::Vendor(), x86_CPUID_VENDOR_AMD) == 0) + { + CPU::x86::AMD::CPUID0x80000001 cpuid; + cpuid.Get(); + PSESupport = cpuid.EDX.PSE; + Page1GBSupport = cpuid.EDX.Page1GB; + } + else if (strcmp(CPU::Vendor(), x86_CPUID_VENDOR_INTEL) == 0) + { + CPU::x86::Intel::CPUID0x00000001 cpuid; + cpuid.Get(); + PSESupport = cpuid.EDX.PSE; + } + + if (PSESupport) + { +#if defined(a64) + CPU::x64::CR4 cr4 = CPU::x64::readcr4(); + cr4.PSE = 1; + CPU::x64::writecr4(cr4); +#elif defined(a32) + CPU::x32::CR4 cr4 = CPU::x32::readcr4(); + cr4.PSE = 1; + CPU::x32::writecr4(cr4); +#elif defined(aa64) +#endif + trace("PSE Support Enabled"); + } + +#ifdef DEBUG + if (Page1GBSupport) + debug("1GB Page Support Enabled"); +#endif + } + + /* TODO: Map faster */ + MapFromZero(pt); + MapFramebuffer(pt); + MapKernel(pt); + +#ifdef DEBUG + tracepagetable(pt); +#endif } NIF void InitializeMemoryManagement() @@ -312,58 +366,59 @@ NIF void InitializeMemoryManagement() KernelPageTable = (PageTable *)KernelAllocator.RequestPages(TO_PAGES(PAGE_SIZE + 1)); memset(KernelPageTable, 0, PAGE_SIZE); - if (strcmp(CPU::Vendor(), x86_CPUID_VENDOR_AMD) == 0) - { - CPU::x86::AMD::CPUID0x80000001 cpuid; - cpuid.Get(); - PSESupport = cpuid.EDX.PSE; - Page1GBSupport = cpuid.EDX.Page1GB; - } - else if (strcmp(CPU::Vendor(), x86_CPUID_VENDOR_INTEL) == 0) - { - CPU::x86::Intel::CPUID0x00000001 cpuid; - cpuid.Get(); - PSESupport = cpuid.EDX.PSE; - } + CreatePageTable(KernelPageTable); - if (PSESupport) - { -#if defined(a64) - CPU::x64::CR4 cr4 = CPU::x64::readcr4(); - cr4.PSE = 1; - CPU::x64::writecr4(cr4); -#elif defined(a32) - CPU::x32::CR4 cr4 = CPU::x32::readcr4(); - cr4.PSE = 1; - CPU::x32::writecr4(cr4); -#elif defined(aa64) -#endif - trace("PSE Support Enabled"); - } - -#ifdef DEBUG - if (Page1GBSupport) - debug("1GB Page Support Enabled"); -#endif - - MapFromZero(KernelPageTable); - MapFramebuffer(KernelPageTable, PSESupport, Page1GBSupport); - MapKernel(KernelPageTable); - - trace("Applying new page table from address %#lx", KernelPageTable); -#ifdef DEBUG - tracepagetable(KernelPageTable); -#endif + trace("Applying new page table from address %#lx", + KernelPageTable); CPU::PageTable(KernelPageTable); debug("Page table updated."); - XallocV1Allocator = new Xalloc::V1((void *)KERNEL_HEAP_BASE, false, false); - XallocV2Allocator = new Xalloc::V2((void *)KERNEL_HEAP_BASE); - trace("XallocV1 Allocator initialized at %#lx", XallocV1Allocator); - trace("XallocV2 Allocator initialized at %#lx", XallocV2Allocator); + /* FIXME: Read kernel params */ + AllocatorType = Config.AllocatorType; - /* FIXME: Read kernel config */ - AllocatorType = MemoryAllocatorType::liballoc11; + switch (AllocatorType) + { + case MemoryAllocatorType::Pages: + break; + case MemoryAllocatorType::XallocV1: + { + XallocV1Allocator = new Xalloc::V1((void *)KERNEL_HEAP_BASE, false, false); + trace("XallocV1 Allocator initialized at %#lx", XallocV1Allocator); + break; + } + case MemoryAllocatorType::XallocV2: + { + XallocV2Allocator = new Xalloc::V2((void *)KERNEL_HEAP_BASE); + trace("XallocV2 Allocator initialized at %#lx", XallocV2Allocator); + break; + } + case MemoryAllocatorType::liballoc11: + break; + case MemoryAllocatorType::rpmalloc_: + { + trace("Using rpmalloc allocator"); + rpmalloc_initialize(); + break; + rpmalloc_config_t config = { + .memory_map = nullptr, + .memory_unmap = nullptr, + .error_callback = nullptr, + .map_fail_callback = nullptr, + .page_size = PAGE_SIZE, + .span_size = 4 * 1024, /* 4 KiB */ + .span_map_count = 1, + .enable_huge_pages = 0, + .page_name = nullptr, + .huge_page_name = nullptr}; + rpmalloc_initialize_config(&config); + break; + } + default: + { + error("Unknown allocator type %d", AllocatorType); + CPU::Stop(); + } + } } void *malloc(size_t Size) @@ -371,7 +426,7 @@ void *malloc(size_t Size) assert(Size > 0); memdbg("malloc(%d)->[%s]", Size, - KernelSymbolTable ? KernelSymbolTable->GetSymbolFromAddress((uintptr_t)__builtin_return_address(0)) + KernelSymbolTable ? KernelSymbolTable->GetSymbol((uintptr_t)__builtin_return_address(0)) : "Unknown"); void *ret = nullptr; @@ -397,6 +452,11 @@ void *malloc(size_t Size) ret = PREFIX(malloc)(Size); break; } + case MemoryAllocatorType::rpmalloc_: + { + ret = rpmalloc(Size); + break; + } default: { error("Unknown allocator type %d", AllocatorType); @@ -413,7 +473,7 @@ void *calloc(size_t n, size_t Size) assert(Size > 0); memdbg("calloc(%d, %d)->[%s]", n, Size, - KernelSymbolTable ? KernelSymbolTable->GetSymbolFromAddress((uintptr_t)__builtin_return_address(0)) + KernelSymbolTable ? KernelSymbolTable->GetSymbol((uintptr_t)__builtin_return_address(0)) : "Unknown"); void *ret = nullptr; @@ -439,6 +499,11 @@ void *calloc(size_t n, size_t Size) void *ret = PREFIX(calloc)(n, Size); return ret; } + case MemoryAllocatorType::rpmalloc_: + { + ret = rpcalloc(n, Size); + break; + } default: { error("Unknown allocator type %d", AllocatorType); @@ -455,7 +520,7 @@ void *realloc(void *Address, size_t Size) assert(Size > 0); memdbg("realloc(%#lx, %d)->[%s]", Address, Size, - KernelSymbolTable ? KernelSymbolTable->GetSymbolFromAddress((uintptr_t)__builtin_return_address(0)) + KernelSymbolTable ? KernelSymbolTable->GetSymbol((uintptr_t)__builtin_return_address(0)) : "Unknown"); void *ret = nullptr; @@ -481,6 +546,11 @@ void *realloc(void *Address, size_t Size) void *ret = PREFIX(realloc)(Address, Size); return ret; } + case MemoryAllocatorType::rpmalloc_: + { + ret = rprealloc(Address, Size); + break; + } default: { error("Unknown allocator type %d", AllocatorType); @@ -497,7 +567,7 @@ void free(void *Address) assert(Address != nullptr); memdbg("free(%#lx)->[%s]", Address, - KernelSymbolTable ? KernelSymbolTable->GetSymbolFromAddress((uintptr_t)__builtin_return_address(0)) + KernelSymbolTable ? KernelSymbolTable->GetSymbol((uintptr_t)__builtin_return_address(0)) : "Unknown"); switch (AllocatorType) @@ -523,6 +593,11 @@ void free(void *Address) (Address); break; } + case MemoryAllocatorType::rpmalloc_: + { + rpfree(Address); + break; + } default: { error("Unknown allocator type %d", AllocatorType); @@ -536,7 +611,7 @@ void *operator new(std::size_t Size) assert(Size > 0); memdbg("new(%d)->[%s]", Size, - KernelSymbolTable ? KernelSymbolTable->GetSymbolFromAddress((uintptr_t)__builtin_return_address(0)) + KernelSymbolTable ? KernelSymbolTable->GetSymbol((uintptr_t)__builtin_return_address(0)) : "Unknown"); void *ret = malloc(Size); @@ -548,7 +623,7 @@ void *operator new[](std::size_t Size) assert(Size > 0); memdbg("new[](%d)->[%s]", Size, - KernelSymbolTable ? KernelSymbolTable->GetSymbolFromAddress((uintptr_t)__builtin_return_address(0)) + KernelSymbolTable ? KernelSymbolTable->GetSymbol((uintptr_t)__builtin_return_address(0)) : "Unknown"); void *ret = malloc(Size); @@ -560,7 +635,7 @@ void *operator new(std::size_t Size, std::align_val_t Alignment) assert(Size > 0); memdbg("new(%d, %d)->[%s]", Size, Alignment, - KernelSymbolTable ? KernelSymbolTable->GetSymbolFromAddress((uintptr_t)__builtin_return_address(0)) + KernelSymbolTable ? KernelSymbolTable->GetSymbol((uintptr_t)__builtin_return_address(0)) : "Unknown"); fixme("operator new with alignment(%#lx) is not implemented", @@ -575,7 +650,7 @@ void operator delete(void *Pointer) assert(Pointer != nullptr); memdbg("delete(%#lx)->[%s]", Pointer, - KernelSymbolTable ? KernelSymbolTable->GetSymbolFromAddress((uintptr_t)__builtin_return_address(0)) + KernelSymbolTable ? KernelSymbolTable->GetSymbol((uintptr_t)__builtin_return_address(0)) : "Unknown"); free(Pointer); @@ -586,7 +661,7 @@ void operator delete[](void *Pointer) assert(Pointer != nullptr); memdbg("delete[](%#lx)->[%s]", Pointer, - KernelSymbolTable ? KernelSymbolTable->GetSymbolFromAddress((uintptr_t)__builtin_return_address(0)) + KernelSymbolTable ? KernelSymbolTable->GetSymbol((uintptr_t)__builtin_return_address(0)) : "Unknown"); free(Pointer); @@ -599,7 +674,7 @@ void operator delete(void *Pointer, long unsigned int Size) memdbg("delete(%#lx, %d)->[%s]", Pointer, Size, - KernelSymbolTable ? KernelSymbolTable->GetSymbolFromAddress((uintptr_t)__builtin_return_address(0)) + KernelSymbolTable ? KernelSymbolTable->GetSymbol((uintptr_t)__builtin_return_address(0)) : "Unknown"); free(Pointer); @@ -612,7 +687,7 @@ void operator delete[](void *Pointer, long unsigned int Size) memdbg("delete[](%#lx, %d)->[%s]", Pointer, Size, - KernelSymbolTable ? KernelSymbolTable->GetSymbolFromAddress((uintptr_t)__builtin_return_address(0)) + KernelSymbolTable ? KernelSymbolTable->GetSymbol((uintptr_t)__builtin_return_address(0)) : "Unknown"); free(Pointer); diff --git a/core/memory/page_table.cpp b/core/memory/page_table.cpp index 14e3a02..55e65b1 100644 --- a/core/memory/page_table.cpp +++ b/core/memory/page_table.cpp @@ -1,6 +1,9 @@ #include #include +#include +#include +#include namespace Memory { @@ -13,29 +16,75 @@ namespace Memory #endif } - PageTable PageTable::Fork() + PageTable *PageTable::Fork() { - PageTable NewTable; - memcpy(&NewTable, this, sizeof(PageTable)); + PageTable *NewTable = (PageTable *)KernelAllocator.RequestPages(TO_PAGES(sizeof(PageTable))); + // memset(NewTable, 0, sizeof(PageTable)); + // CreatePageTable(NewTable); + memcpy(NewTable, this, sizeof(PageTable)); + + debug("Forking page table %#lx to %#lx", this, NewTable); +#if defined(a64) + for (size_t i = 0; i < sizeof(Entries) / sizeof(Entries[0]); i++) + { + PageMapLevel4 *PML4 = &Entries[i]; + PageMapLevel4 *NewPML4 = &NewTable->Entries[i]; + if (!PML4->Present) + continue; + + PageDirectoryPointerTableEntryPtr *ptrPDPT = (PageDirectoryPointerTableEntryPtr *)(PML4->GetAddress() << 12); + PageDirectoryPointerTableEntryPtr *ptrNewPDPT = (PageDirectoryPointerTableEntryPtr *)KernelAllocator.RequestPage(); + NewPML4->SetAddress((uintptr_t)ptrNewPDPT >> 12); + for (size_t j = 0; j < sizeof(ptrPDPT->Entries) / sizeof(ptrPDPT->Entries[0]); j++) + { + PageDirectoryPointerTableEntry *PDPT = &ptrPDPT->Entries[j]; + PageDirectoryPointerTableEntry *NewPDPT = &ptrNewPDPT->Entries[j]; + *NewPDPT = *PDPT; + + if (!PDPT->Present) + continue; + if (PDPT->PageSize) + continue; + + PageDirectoryEntryPtr *ptrPDE = (PageDirectoryEntryPtr *)(PDPT->GetAddress() << 12); + PageDirectoryEntryPtr *ptrNewPDE = (PageDirectoryEntryPtr *)KernelAllocator.RequestPage(); + NewPDPT->SetAddress((uintptr_t)ptrNewPDE >> 12); + for (size_t k = 0; k < sizeof(ptrPDE->Entries) / sizeof(ptrPDE->Entries[0]); k++) + { + PageDirectoryEntry *PDE = &ptrPDE->Entries[k]; + PageDirectoryEntry *NewPDE = &ptrNewPDE->Entries[k]; + *NewPDE = *PDE; + + if (!PDE->Present) + continue; + if (PDE->PageSize) + continue; + + PageTableEntryPtr *ptrPTE = (PageTableEntryPtr *)(PDE->GetAddress() << 12); + PageTableEntryPtr *ptrNewPTE = (PageTableEntryPtr *)KernelAllocator.RequestPage(); + NewPDE->SetAddress((uintptr_t)ptrNewPTE >> 12); + for (size_t l = 0; l < sizeof(ptrPTE->Entries) / sizeof(ptrPTE->Entries[0]); l++) + { + PageTableEntry *PTE = &ptrPTE->Entries[l]; + PageTableEntry *NewPTE = &ptrNewPTE->Entries[l]; + *NewPTE = *PTE; + } + } + } + } +#else +#error "PageTable::Fork() not implemented for other architectures" +#endif + + debug("Forked page table %#lx to %#lx", this, NewTable); return NewTable; } - template - T PageTable::Get(T Address) + /* We can't have Memory::Virtual in the header */ + void *PageTable::__getPhysical(void *Address) { - Virtual vmm = Virtual(this); + Virtual vmm(this); void *PhysAddr = vmm.GetPhysical((void *)Address); - uintptr_t Diff = uintptr_t(Address); - Diff &= 0xFFF; - Diff = uintptr_t(PhysAddr) + Diff; - return (T)Diff; + return PhysAddr; } - - /* Templates */ - template struct stat *PageTable::Get(struct stat *); - template const char *PageTable::Get(const char *); - template const void *PageTable::Get(const void *); - template uintptr_t PageTable::Get(uintptr_t); - template void *PageTable::Get(void *); - /* ... */ } diff --git a/core/memory/pmm.cpp b/core/memory/pmm.cpp index b9258e3..85ba50e 100644 --- a/core/memory/pmm.cpp +++ b/core/memory/pmm.cpp @@ -107,9 +107,11 @@ namespace Memory } error("Out of memory! (Free: %ld MiB; Used: %ld MiB; Reserved: %ld MiB)", - TO_MiB(FreeMemory), TO_MiB(UsedMemory), TO_MiB(ReservedMemory)); + TO_MiB(FreeMemory.load()), TO_MiB(UsedMemory.load()), TO_MiB(ReservedMemory.load())); KPrint("Out of memory! (Free: %ld MiB; Used: %ld MiB; Reserved: %ld MiB)", - TO_MiB(FreeMemory), TO_MiB(UsedMemory), TO_MiB(ReservedMemory)); + TO_MiB(FreeMemory.load()), TO_MiB(UsedMemory.load()), TO_MiB(ReservedMemory.load())); + debug("Raw values: free %#lx used %#lx reserved %#lx", + FreeMemory.load(), UsedMemory.load(), ReservedMemory.load()); CPU::Stop(); __builtin_unreachable(); } @@ -157,9 +159,11 @@ namespace Memory } error("Out of memory! (Free: %ld MiB; Used: %ld MiB; Reserved: %ld MiB)", - TO_MiB(FreeMemory), TO_MiB(UsedMemory), TO_MiB(ReservedMemory)); + TO_MiB(FreeMemory.load()), TO_MiB(UsedMemory.load()), TO_MiB(ReservedMemory.load())); KPrint("Out of memory! (Free: %ld MiB; Used: %ld MiB; Reserved: %ld MiB)", - TO_MiB(FreeMemory), TO_MiB(UsedMemory), TO_MiB(ReservedMemory)); + TO_MiB(FreeMemory.load()), TO_MiB(UsedMemory.load()), TO_MiB(ReservedMemory.load())); + debug("Raw values: free %#lx used %#lx reserved %#lx", + FreeMemory.load(), UsedMemory.load(), ReservedMemory.load()); CPU::Halt(true); __builtin_unreachable(); } @@ -185,8 +189,8 @@ namespace Memory if (PageBitmap.Set(Index, false)) { - FreeMemory += PAGE_SIZE; - UsedMemory -= PAGE_SIZE; + FreeMemory.fetch_add(PAGE_SIZE); + UsedMemory.fetch_sub(PAGE_SIZE); if (PageBitmapIndex > Index) PageBitmapIndex = Index; } @@ -215,8 +219,8 @@ namespace Memory if (PageBitmap.Set(Index, true)) { - FreeMemory -= PAGE_SIZE; - UsedMemory += PAGE_SIZE; + FreeMemory.fetch_sub(PAGE_SIZE); + UsedMemory.fetch_add(PAGE_SIZE); } } @@ -243,8 +247,8 @@ namespace Memory if (PageBitmap.Set(Index, true)) { - FreeMemory -= PAGE_SIZE; - ReservedMemory += PAGE_SIZE; + FreeMemory.fetch_sub(PAGE_SIZE); + ReservedMemory.fetch_add(PAGE_SIZE); } } @@ -264,8 +268,8 @@ namespace Memory if (PageBitmap.Set(Index, true)) { - FreeMemory -= PAGE_SIZE; - ReservedMemory += PAGE_SIZE; + FreeMemory.fetch_sub(PAGE_SIZE); + ReservedMemory.fetch_add(PAGE_SIZE); } } } @@ -282,8 +286,8 @@ namespace Memory if (PageBitmap.Set(Index, false)) { - FreeMemory += PAGE_SIZE; - ReservedMemory -= PAGE_SIZE; + FreeMemory.fetch_add(PAGE_SIZE); + ReservedMemory.fetch_sub(PAGE_SIZE); if (PageBitmapIndex > Index) PageBitmapIndex = Index; } @@ -305,8 +309,8 @@ namespace Memory if (PageBitmap.Set(Index, false)) { - FreeMemory += PAGE_SIZE; - ReservedMemory -= PAGE_SIZE; + FreeMemory.fetch_add(PAGE_SIZE); + ReservedMemory.fetch_sub(PAGE_SIZE); if (PageBitmapIndex > Index) PageBitmapIndex = Index; } @@ -320,8 +324,8 @@ namespace Memory uint64_t MemorySize = bInfo.Memory.Size; debug("Memory size: %lld bytes (%ld pages)", MemorySize, TO_PAGES(MemorySize)); - TotalMemory = MemorySize; - FreeMemory = MemorySize; + TotalMemory.store(MemorySize); + FreeMemory.store(MemorySize); size_t BitmapSize = (size_t)(MemorySize / PAGE_SIZE) / 8 + 1; uintptr_t BitmapAddress = 0x0; diff --git a/core/memory/stack_guard.cpp b/core/memory/stack_guard.cpp index 30995b8..e25c1e7 100644 --- a/core/memory/stack_guard.cpp +++ b/core/memory/stack_guard.cpp @@ -80,7 +80,7 @@ namespace Memory if (this->UserMode) { std::vector ParentAllocatedPages = Parent->GetAllocatedPages(); - Virtual vma = Virtual(this->vma->GetTable()); + Virtual vma(this->vma->GetTable()); foreach (auto Page in ParentAllocatedPages) { void *NewPhysical = this->vma->RequestPages(1); @@ -162,6 +162,7 @@ namespace Memory } debug("Allocated stack at %#lx", this->StackBottom); + debug("Stack Range: %#lx - %#lx", this->StackBottom, this->StackTop); } StackGuard::~StackGuard() diff --git a/core/memory/vma.cpp b/core/memory/vma.cpp index 78c533b..61e00cf 100644 --- a/core/memory/vma.cpp +++ b/core/memory/vma.cpp @@ -74,6 +74,8 @@ namespace Memory bool VirtualMemoryArea::Add(void *Address, size_t Count) { SmartLock(MgrLock); + function("%#lx, %lld", Address, Count); + if (Address == nullptr) { error("Address is null!"); @@ -118,7 +120,10 @@ namespace Memory void *VirtualMemoryArea::RequestPages(size_t Count, bool User) { SmartLock(MgrLock); + function("%lld, %s", Count, User ? "true" : "false"); + void *Address = KernelAllocator.RequestPages(Count); + memset(Address, 0, Count * PAGE_SIZE); for (size_t i = 0; i < Count; i++) { int Flags = Memory::PTFlag::RW; @@ -127,23 +132,19 @@ namespace Memory void *AddressToMap = (void *)((uintptr_t)Address + (i * PAGE_SIZE)); - Memory::Virtual vmm = Memory::Virtual(this->Table); - vmm.Remap(AddressToMap, AddressToMap, Flags); + Memory::Virtual vmm(this->Table); + vmm.Map(AddressToMap, AddressToMap, Flags); } AllocatedPagesList.push_back({Address, Count}); - - /* For security reasons, we clear the allocated page - if it's a user page. */ - if (User) - memset(Address, 0, Count * PAGE_SIZE); - return Address; } void VirtualMemoryArea::FreePages(void *Address, size_t Count) { SmartLock(MgrLock); + function("%#lx, %lld", Address, Count); + forItr(itr, AllocatedPagesList) { if (itr->Address == Address) @@ -162,7 +163,7 @@ namespace Memory KernelAllocator.FreePages(Address, Count); - Memory::Virtual vmm = Memory::Virtual(this->Table); + Memory::Virtual vmm(this->Table); for (size_t i = 0; i < Count; i++) { void *AddressToMap = (void *)((uintptr_t)Address + (i * PAGE_SIZE)); @@ -178,6 +179,8 @@ namespace Memory void VirtualMemoryArea::DetachAddress(void *Address) { SmartLock(MgrLock); + function("%#lx", Address); + forItr(itr, AllocatedPagesList) { if (itr->Address == Address) @@ -193,7 +196,14 @@ namespace Memory bool Read, bool Write, bool Exec, bool Fixed, bool Shared) { - Memory::Virtual vmm = Memory::Virtual(this->Table); + function("%#lx, %lld, %s, %s, %s, %s, %s", Address, Length, + Read ? "true" : "false", + Write ? "true" : "false", + Exec ? "true" : "false", + Fixed ? "true" : "false", + Shared ? "true" : "false"); + + Memory::Virtual vmm(this->Table); // FIXME // for (uintptr_t j = uintptr_t(Address); @@ -209,20 +219,21 @@ namespace Memory // } bool AnyAddress = Address == nullptr; + debug("AnyAddress: %s", AnyAddress ? "true" : "false"); if (AnyAddress) { - Address = this->RequestPages(1); - if (Address == nullptr) - return nullptr; - memset(Address, 0, PAGE_SIZE); + Address = this->RequestPages(TO_PAGES(Length), true); + debug("Allocated %#lx-%#lx for pt %#lx", + Address, (uintptr_t)Address + Length, this->Table); + return Address; } + SmartLock(MgrLock); vmm.Unmap(Address, Length); vmm.Map(Address, nullptr, Length, PTFlag::CoW); - - if (AnyAddress) - vmm.Remap(Address, Address, PTFlag::RW | PTFlag::US); + debug("CoW region created at range %#lx-%#lx for pt %#lx", + Address, (uintptr_t)Address + Length, this->Table); SharedRegion sr{ .Address = Address, @@ -235,13 +246,15 @@ namespace Memory .ReferenceCount = 0, }; SharedRegions.push_back(sr); + debug("CoW region created at %#lx for pt %#lx", + Address, this->Table); return Address; } bool VirtualMemoryArea::HandleCoW(uintptr_t PFA) { function("%#lx", PFA); - Memory::Virtual vmm = Memory::Virtual(this->Table); + Memory::Virtual vmm(this->Table); Memory::PageTableEntry *pte = vmm.GetPTE((void *)PFA); if (!pte) @@ -260,6 +273,9 @@ namespace Memory if (PFA >= Start && PFA < End) { + debug("Start: %#lx, End: %#lx (PFA: %#lx)", + Start, End, PFA); + if (sr.Shared) { fixme("Shared CoW"); @@ -272,30 +288,117 @@ namespace Memory return false; memset(pAddr, 0, PAGE_SIZE); - uint64_t Flags = 0; - if (sr.Read) - Flags |= PTFlag::US; - if (sr.Write) - Flags |= PTFlag::RW; - // if (sr.Exec) - // Flags |= PTFlag::XD; + assert(pte->Present == true); + pte->ReadWrite = sr.Write; + pte->UserSupervisor = sr.Read; + pte->ExecuteDisable = sr.Exec; - vmm.Remap((void *)PFA, pAddr, Flags); pte->CopyOnWrite = false; + debug("PFA %#lx is CoW (pt %#lx, flags %#lx)", + PFA, this->Table, pte->raw); +#if defined(a64) + CPU::x64::invlpg((void *)PFA); +#elif defined(a32) + CPU::x32::invlpg((void *)PFA); +#endif return true; } } } } - debug("PFA %#lx is not CoW", PFA); + debug("PFA %#lx is not CoW (pt %#lx)", + PFA, this->Table); return false; } + void VirtualMemoryArea::FreeAllPages() + { + SmartLock(MgrLock); + foreach (auto ap in AllocatedPagesList) + { + KernelAllocator.FreePages(ap.Address, ap.PageCount); + Memory::Virtual vmm(this->Table); + for (size_t i = 0; i < ap.PageCount; i++) + vmm.Remap((void *)((uintptr_t)ap.Address + (i * PAGE_SIZE)), + (void *)((uintptr_t)ap.Address + (i * PAGE_SIZE)), + Memory::PTFlag::RW); + } + AllocatedPagesList.clear(); + } + + void VirtualMemoryArea::Fork(VirtualMemoryArea *Parent) + { + function("%#lx", Parent); + + if (Parent == nullptr) + { + error("Parent is null!"); + return; + } + + if (Parent->Table == nullptr) + { + error("Parent's table is null!"); + return; + } + + Memory::Virtual vmm(this->Table); + SmartLock(MgrLock); + foreach (auto ap in Parent->GetAllocatedPagesList()) + { + MgrLock.Unlock(); + void *Address = this->RequestPages(ap.PageCount); + MgrLock.Lock(__FUNCTION__); + if (Address == nullptr) + return; + + memcpy(Address, ap.Address, ap.PageCount * PAGE_SIZE); + + // map these new allocated pages to be the same as the parent + for (size_t i = 0; i < ap.PageCount; i++) + { + void *AddressToMap = (void *)((uintptr_t)ap.Address + (i * PAGE_SIZE)); + void *RealAddress = (void *)((uintptr_t)Address + (i * PAGE_SIZE)); + +#if defined(a86) + Memory::PageTableEntry *pte = vmm.GetPTE(AddressToMap); + uintptr_t Flags = 0; + Flags |= pte->Present ? 1UL : 0; + Flags |= pte->ReadWrite ? 2UL : 0; + Flags |= pte->UserSupervisor ? 4UL : 0; + Flags |= pte->CopyOnWrite ? 512UL : 0; + + debug("Mapping %#lx to %#lx (flags %s/%s/%s/%s)", + RealAddress, AddressToMap, + Flags & PTFlag::P ? "P" : "-", + Flags & PTFlag::RW ? "RW" : "-", + Flags & PTFlag::US ? "US" : "-", + Flags & PTFlag::CoW ? "CoW" : "-"); + vmm.Map(AddressToMap, RealAddress, Flags); +#else +#warning "Not implemented" +#endif + } + } + + foreach (auto sr in Parent->GetSharedRegions()) + { + MgrLock.Unlock(); + void *Address = this->CreateCoWRegion(sr.Address, sr.Length, + sr.Read, sr.Write, sr.Exec, + sr.Fixed, sr.Shared); + MgrLock.Lock(__FUNCTION__); + if (Address == nullptr) + return; + memcpy(Address, sr.Address, sr.Length); + } + } + VirtualMemoryArea::VirtualMemoryArea(PageTable *Table) { debug("+ %#lx %s", this, - KernelSymbolTable ? KernelSymbolTable->GetSymbolFromAddress((uintptr_t)__builtin_return_address(0)) : ""); + KernelSymbolTable ? KernelSymbolTable->GetSymbol((uintptr_t)__builtin_return_address(0)) : ""); SmartLock(MgrLock); if (Table) @@ -316,12 +419,22 @@ namespace Memory VirtualMemoryArea::~VirtualMemoryArea() { debug("- %#lx %s", this, - KernelSymbolTable ? KernelSymbolTable->GetSymbolFromAddress((uintptr_t)__builtin_return_address(0)) : ""); + KernelSymbolTable ? KernelSymbolTable->GetSymbol((uintptr_t)__builtin_return_address(0)) : ""); + +#ifdef DEBUG + if (this->Table == KernelPageTable) + debug("Not remapping kernel page table allocated pages."); +#endif + SmartLock(MgrLock); + Memory::Virtual vmm(this->Table); foreach (auto ap in AllocatedPagesList) { KernelAllocator.FreePages(ap.Address, ap.PageCount); - Memory::Virtual vmm = Memory::Virtual(this->Table); + + if (this->Table == KernelPageTable) + continue; + for (size_t i = 0; i < ap.PageCount; i++) vmm.Remap((void *)((uintptr_t)ap.Address + (i * PAGE_SIZE)), (void *)((uintptr_t)ap.Address + (i * PAGE_SIZE)), diff --git a/core/memory/vmm.cpp b/core/memory/vmm.cpp index 1d99fca..2688916 100644 --- a/core/memory/vmm.cpp +++ b/core/memory/vmm.cpp @@ -20,15 +20,25 @@ #include #include +#include "../../kernel.h" + namespace Memory { - Virtual::Virtual(PageTable *Table) - { - if (Table) - this->Table = Table; - else - this->Table = (PageTable *)CPU::PageTable(); - } + Virtual::Virtual(PageTable *Table) + { + if (Table) + this->pTable = Table; + else + this->pTable = thisPageTable; - Virtual::~Virtual() {} + // debug("+ %#lx (PT: %#lx) %s", this, this->pTable, + // KernelSymbolTable + // ? KernelSymbolTable->GetSymbol((uintptr_t)__builtin_return_address(0)) + // : "Unknown"); + } + + Virtual::~Virtual() + { + // debug("- %#lx", this); + } } diff --git a/core/module/module.cpp b/core/module/module.cpp deleted file mode 100644 index 1f3e47a..0000000 --- a/core/module/module.cpp +++ /dev/null @@ -1,347 +0,0 @@ -/* - This file is part of Fennix Kernel. - - Fennix Kernel is free software: you can redistribute it and/or - modify it under the terms of the GNU General Public License as - published by the Free Software Foundation, either version 3 of - the License, or (at your option) any later version. - - Fennix Kernel is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Fennix Kernel. If not, see . -*/ - -#include - -#include -#include -#include -#include -#include -#include - -#include "../../modules/mod.hpp" -#include "../../kernel.h" -#include "../../mapi.hpp" -#include "../../Fex.hpp" -#include "api.hpp" - -using vfs::RefNode; - -namespace Module -{ - void Module::Panic() - { - debug("%ld modules loaded, [modUIDs: %ld]", Modules.size(), modUIDs - 1); - - foreach (auto Drv in Modules) - { - KernelCallback callback{}; - callback.Reason = StopReason; - ModuleManager->IOCB(Drv.modUniqueID, &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 Module::UnloadAllModules() - { - debug("%ld modules loaded, [modUIDs: %ld]", Modules.size(), modUIDs - 1); - - foreach (auto Drv in Modules) - { - KernelCallback callback{}; - callback.Reason = StopReason; - debug("Stopping & unloading module %ld [%#lx]", Drv.modUniqueID, Drv.Address); - ModuleManager->IOCB(Drv.modUniqueID, &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.vma) - delete Drv.vma, Drv.vma = nullptr; - } - Modules.clear(); - } - - bool Module::UnloadModule(unsigned long id) - { - debug("Searching for module %ld", id); - - forItr(Drv, Modules) - { - if (Drv->modUniqueID != id) - continue; - - KernelCallback callback{}; - callback.Reason = StopReason; - debug("Stopping & unloading module %ld [%#lx]", Drv->modUniqueID, Drv->Address); - this->IOCB(Drv->modUniqueID, &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->vma) - delete Drv->vma, Drv->vma = nullptr; - - Modules.erase(Drv); - return true; - } - return false; - } - - int Module::IOCB(unsigned long id, void *KCB) - { - foreach (auto Drv in Modules) - { - if (Drv.modUniqueID != id) - continue; - - FexExtended *fexE = (FexExtended *)Drv.ExtendedHeaderAddress; - return ((int (*)(void *))((uintptr_t)fexE->Module.Callback + (uintptr_t)Drv.Address))(KCB); - } - return -1; - } - - ModuleCode Module::CallModuleEntryPoint(void *fex, bool BuiltIn) - { - ModuleCode ret{}; - KernelAPI modKAPI = KernelAPITemplate; - - modKAPI.Info.modUniqueID = modUIDs++; - modKAPI.Info.KernelDebug = DebuggerIsAttached; - - debug("Calling module entry point ( %#lx %ld )", (unsigned long)fex, modKAPI.Info.modUniqueID); - - if (!BuiltIn) - { - modKAPI.Info.Offset = (unsigned long)fex; - - debug("MODULE: %s HAS MODULE ID %ld", - ((FexExtended *)((uintptr_t)fex + EXTENDED_SECTION_ADDRESS))->Module.Name, - modKAPI.Info.modUniqueID); - ret = ((ModuleCode(*)(KernelAPI *))((uintptr_t)((Fex *)fex)->EntryPoint + (uintptr_t)fex))(((KernelAPI *)&modKAPI)); - } - else - { - debug("MODULE: BUILTIN HAS MODULE ID %ld", modKAPI.Info.modUniqueID); - ret = ((ModuleCode(*)(KernelAPI *))((uintptr_t)fex))(((KernelAPI *)&modKAPI)); - } - - if (ModuleCode::OK != ret) - { - modUIDs--; - return ret; - } - return ModuleCode::OK; - } - - ModuleCode Module::LoadModule(vfs::Node *fildes) - { - Fex DrvHdr; - fildes->read((uint8_t *)&DrvHdr, sizeof(Fex), 0); - - if (DrvHdr.Magic[0] != 'F' || DrvHdr.Magic[1] != 'E' || DrvHdr.Magic[2] != 'X' || DrvHdr.Magic[3] != '\0') - return ModuleCode::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_Module) - return ModuleCode::NOT_MODULE; - - FexExtended fexE; - fildes->read((uint8_t *)&fexE, sizeof(FexExtended), EXTENDED_SECTION_ADDRESS); - - debug("Name: \"%s\"; Type: %d; Callback: %#lx", fexE.Module.Name, fexE.Module.Type, fexE.Module.Callback); - - Memory::SmartHeap ModuleAddress(fildes->Size); - fildes->read(ModuleAddress, fildes->Size, 0); - - switch (fexE.Module.Bind.Type) - { - case ModuleBindType::BIND_PCI: - return this->ModuleLoadBindPCI(ModuleAddress, fildes->Size); - case ModuleBindType::BIND_INTERRUPT: - return this->ModuleLoadBindInterrupt(ModuleAddress, fildes->Size); - case ModuleBindType::BIND_PROCESS: - return this->ModuleLoadBindProcess(ModuleAddress, fildes->Size); - case ModuleBindType::BIND_INPUT: - return this->ModuleLoadBindInput(ModuleAddress, fildes->Size); - default: - { - error("Unknown module bind type: %d", fexE.Module.Bind.Type); - return ModuleCode::UNKNOWN_MODULE_BIND_TYPE; - } - } - } - - void Module::LoadModules() - { - SmartCriticalSection(ModuleInitLock); - - const char *ModuleConfigFile = new char[256]; - assert(strlen(Config.ModuleDirectory) < 255 - 12); - strcpy((char *)ModuleConfigFile, Config.ModuleDirectory); - strcat((char *)ModuleConfigFile, "/config.ini"); - fixme("Loading module config file: %s", ModuleConfigFile); - delete[] ModuleConfigFile; - - debug("Loading built-in modules"); - StartBuiltInModules(); - - RefNode *ModuleDirectory = fs->Open(Config.ModuleDirectory); - if (!ModuleDirectory) - { - KPrint("\eE85230Failed to open %s: %d)", - Config.ModuleDirectory, errno); - return; - } - - debug("Loading modules from %s", Config.ModuleDirectory); - foreach (auto DrvFile in ModuleDirectory->node->Children) - { - if (DrvFile->Type != vfs::NodeType::FILE) - continue; - - if (cwk_path_has_extension(DrvFile->Name)) - { - const char *extension; - size_t extension_length; - cwk_path_get_extension(DrvFile->Name, &extension, &extension_length); - debug("File: %s; Extension: %s", DrvFile->Name, extension); - if (strcmp(extension, ".fex") == 0) - { - uintptr_t ret = this->LoadModule(DrvFile); - char *RetString = new char[256]; - if (ret == ModuleCode::OK) - strcpy(RetString, "\e058C19OK"); - else if (ret == ModuleCode::NOT_AVAILABLE) - strcpy(RetString, "\eFF7900NOT AVAILABLE"); - else - strcpy(RetString, "\eE85230FAILED"); - KPrint("%s %s %#lx", DrvFile->Name, RetString, ret); - delete[] RetString; - } - } - } - delete ModuleDirectory; - } - - Module::Module() {} - - Module::~Module() - { - debug("Destructor called"); - this->UnloadAllModules(); - } - -#if defined(a64) - SafeFunction void ModuleInterruptHook::OnInterruptReceived(CPU::x64::TrapFrame *Frame) -#elif defined(a32) - SafeFunction void ModuleInterruptHook::OnInterruptReceived(CPU::x32::TrapFrame *Frame) -#elif defined(aa64) - SafeFunction void ModuleInterruptHook::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 (%#lx, IRQ%d)", - Frame->InterruptNumber, - Frame->InterruptNumber - 32); - 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 module %ld!", - IntNum, Handle.modUniqueID); - 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.edi = Frame->edi; - regs.esi = Frame->esi; - regs.ebp = Frame->ebp; - regs.esp = Frame->esp; - regs.ebx = Frame->ebx; - regs.edx = Frame->edx; - regs.ecx = Frame->ecx; - 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.r3_esp = Frame->r3_esp; - regs.r3_ss = Frame->r3_ss; -#elif defined(aa64) -#endif - ((int (*)(void *))(Handle.InterruptCallback))(®s); - UNUSED(Frame); - } - - ModuleInterruptHook::ModuleInterruptHook(int Interrupt, ModuleFile Handle) : Interrupts::Handler(Interrupt) - { - this->Handle = Handle; -#if defined(a86) - trace("Interrupt %d hooked to module %ld", Interrupt, Handle.modUniqueID); -#elif defined(aa64) - trace("Interrupt %d hooked to module %ld", Interrupt, Handle.modUniqueID); -#endif - } -} diff --git a/core/module/module_api.cpp b/core/module/module_api.cpp deleted file mode 100644 index 30d3bb8..0000000 --- a/core/module/module_api.cpp +++ /dev/null @@ -1,226 +0,0 @@ -/* - This file is part of Fennix Kernel. - - Fennix Kernel is free software: you can redistribute it and/or - modify it under the terms of the GNU General Public License as - published by the Free Software Foundation, either version 3 of - the License, or (at your option) any later version. - - Fennix Kernel is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Fennix Kernel. If not, see . -*/ - -#include - -#include -#include - -#include "../../kernel.h" -#include "../../Fex.hpp" -#include "api.hpp" - -// show debug messages -// #define DEBUG_MODULE_API 1 - -#ifdef DEBUG_MODULE_API -#define modbg(m, ...) debug(m, ##__VA_ARGS__) -#else -#define modbg(m, ...) -#endif - -NewLock(ModuleDisplayPrintLock); - -void ModuleDebugPrint(char *String, __UINT64_TYPE__ modUniqueID) -{ - trace("[%ld] %s", modUniqueID, String); -} - -void ModuleDisplayPrint(char *String) -{ - SmartLock(ModuleDisplayPrintLock); - for (__UINT64_TYPE__ i = 0; i < strlen(String); i++) - Display->Print(String[i], 0, true); -} - -void *RequestPage(__UINT64_TYPE__ Size) -{ - void *ret = KernelAllocator.RequestPages(size_t(Size + 1)); - modbg("Allocated %ld pages (%#lx-%#lx)", - Size, (__UINT64_TYPE__)ret, - (__UINT64_TYPE__)ret + FROM_PAGES(Size)); - return ret; -} - -void FreePage(void *Page, __UINT64_TYPE__ Size) -{ - modbg("Freeing %ld pages (%#lx-%#lx)", - Size, (__UINT64_TYPE__)Page, - (__UINT64_TYPE__)Page + FROM_PAGES(Size)); - KernelAllocator.FreePages(Page, size_t(Size + 1)); -} - -void MapMemory(void *VirtualAddress, void *PhysicalAddress, __UINT64_TYPE__ Flags) -{ - SmartLock(ModuleDisplayPrintLock); - modbg("Mapping %#lx to %#lx with flags %#lx...", - (__UINT64_TYPE__)VirtualAddress, - (__UINT64_TYPE__)PhysicalAddress, Flags); - Memory::Virtual(KernelPageTable).Map(VirtualAddress, PhysicalAddress, Flags); -} - -void UnmapMemory(void *VirtualAddress) -{ - SmartLock(ModuleDisplayPrintLock); - modbg("Unmapping %#lx...", - (__UINT64_TYPE__)VirtualAddress); - Memory::Virtual(KernelPageTable).Unmap(VirtualAddress); -} - -void *Modulememcpy(void *Destination, void *Source, __UINT64_TYPE__ Size) -{ - SmartLock(ModuleDisplayPrintLock); - modbg("Copying %ld bytes from %#lx-%#lx to %#lx-%#lx...", Size, - (__UINT64_TYPE__)Source, (__UINT64_TYPE__)Source + Size, - (__UINT64_TYPE__)Destination, (__UINT64_TYPE__)Destination + Size); - return memcpy(Destination, Source, size_t(Size)); -} - -void *Modulememset(void *Destination, int Value, __UINT64_TYPE__ Size) -{ - SmartLock(ModuleDisplayPrintLock); - modbg("Setting value %#x at %#lx-%#lx (%ld bytes)...", Value, - (__UINT64_TYPE__)Destination, - (__UINT64_TYPE__)Destination + Size, Size); - return memset(Destination, Value, size_t(Size)); -} - -void ModuleNetSend(__UINT32_TYPE__ ModuleID, - __UINT8_TYPE__ *Data, - __UINT16_TYPE__ Size) -{ - // This is useless I guess... - if (NIManager) - NIManager->DrvSend(ModuleID, Data, Size); -} - -void ModuleNetReceive(__UINT32_TYPE__ ModuleID, - __UINT8_TYPE__ *Data, - __UINT16_TYPE__ Size) -{ - if (NIManager) - NIManager->DrvReceive(ModuleID, Data, Size); -} - -void ModuleAHCIDiskRead(__UINT32_TYPE__ ModuleID, - __UINT64_TYPE__ Sector, - __UINT8_TYPE__ *Data, - __UINT32_TYPE__ SectorCount, - __UINT8_TYPE__ Port) -{ - DumpData("ModuleDiskRead", Data, SectorCount * 512); - UNUSED(ModuleID); - UNUSED(Sector); - UNUSED(Port); -} - -void ModuleAHCIDiskWrite(__UINT32_TYPE__ ModuleID, - __UINT64_TYPE__ Sector, - __UINT8_TYPE__ *Data, - __UINT32_TYPE__ SectorCount, - __UINT8_TYPE__ Port) -{ - DumpData("ModuleDiskWrite", - Data, SectorCount * 512); - UNUSED(ModuleID); - UNUSED(Sector); - UNUSED(Port); -} - -char *ModulePCIGetDeviceName(__UINT32_TYPE__ VendorID, - __UINT32_TYPE__ DeviceID) -{ - UNUSED(VendorID); - UNUSED(DeviceID); - return (char *)"Unknown"; -} - -__UINT32_TYPE__ ModuleGetWidth() -{ - return Display->GetBuffer(0)->Width; -} - -__UINT32_TYPE__ ModuleGetHeight() -{ - return Display->GetBuffer(0)->Height; -} - -void ModuleSleep(__UINT64_TYPE__ Milliseconds) -{ - SmartLock(ModuleDisplayPrintLock); - modbg("Sleeping for %ld milliseconds...", Milliseconds); - if (TaskManager) - TaskManager->Sleep(Milliseconds); - else - TimeManager->Sleep(size_t(Milliseconds), - Time::Units::Milliseconds); -} - -int Modulesprintf(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, - .modUniqueID = 0, - .KernelDebug = false, - }, - .Memory = { - .PageSize = PAGE_SIZE, - .RequestPage = RequestPage, - .FreePage = FreePage, - .Map = MapMemory, - .Unmap = UnmapMemory, - }, - .PCI = { - .GetDeviceName = ModulePCIGetDeviceName, - }, - .Util = { - .DebugPrint = ModuleDebugPrint, - .DisplayPrint = ModuleDisplayPrint, - .memcpy = Modulememcpy, - .memset = Modulememset, - .Sleep = ModuleSleep, - .sprintf = Modulesprintf, - }, - .Command = { - .Network = { - .SendPacket = ModuleNetSend, - .ReceivePacket = ModuleNetReceive, - }, - .Disk = { - .AHCI = { - .ReadSector = ModuleAHCIDiskRead, - .WriteSector = ModuleAHCIDiskWrite, - }, - }, - }, - .Display = { - .GetWidth = ModuleGetWidth, - .GetHeight = ModuleGetHeight, - }, -}; diff --git a/core/module/module_binding/bind_interrupt.cpp b/core/module/module_binding/bind_interrupt.cpp deleted file mode 100644 index d2d49a6..0000000 --- a/core/module/module_binding/bind_interrupt.cpp +++ /dev/null @@ -1,118 +0,0 @@ -/* - This file is part of Fennix Kernel. - - Fennix Kernel is free software: you can redistribute it and/or - modify it under the terms of the GNU General Public License as - published by the Free Software Foundation, either version 3 of - the License, or (at your option) any later version. - - Fennix Kernel is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Fennix Kernel. If not, see . -*/ - -#include "../api.hpp" - -#include -#include -#include -#include -#include -#include -#include - -#include "../../../kernel.h" -#include "../../../mapi.hpp" -#include "../../../Fex.hpp" - -namespace Module -{ - ModuleCode Module::ModuleLoadBindInterrupt(uintptr_t ModuleAddress, size_t Size, bool IsBuiltIn) - { - Memory::VirtualMemoryArea *vma = new Memory::VirtualMemoryArea(nullptr); - - BuiltInModuleInfo *bidi = (BuiltInModuleInfo *)ModuleAddress; - Fex *fex = nullptr; - if (!IsBuiltIn) - { - fex = (Fex *)vma->RequestPages(TO_PAGES(Size + 1)); - memcpy(fex, (void *)ModuleAddress, Size); - debug("Module allocated at %#lx-%#lx", fex, (uintptr_t)fex + Size); - } - else - fex = (Fex *)bidi->EntryPoint; - ModuleCode ret = CallModuleEntryPoint(fex, IsBuiltIn); - if (ret != ModuleCode::OK) - { - delete vma; - return ret; - } - - if (IsBuiltIn) - fex = 0x0; /* Addresses are absolute if built-in. */ - - FexExtended *fexE = IsBuiltIn ? (FexExtended *)bidi->ExtendedHeader : (FexExtended *)((uintptr_t)fex + EXTENDED_SECTION_ADDRESS); - - debug("Starting driver %s", fexE->Module.Name); - - switch (fexE->Module.Type) - { - case FexModuleType::FexModuleType_Generic: - case FexModuleType::FexModuleType_Display: - case FexModuleType::FexModuleType_Network: - case FexModuleType::FexModuleType_Storage: - case FexModuleType::FexModuleType_FileSystem: - case FexModuleType::FexModuleType_Input: - case FexModuleType::FexModuleType_Audio: - { - FexExtended *DriverExtendedHeader = (FexExtended *)vma->RequestPages(TO_PAGES(sizeof(FexExtended) + 1)); - memcpy(DriverExtendedHeader, fexE, sizeof(FexExtended)); - - ModuleFile DrvFile = { - .Enabled = true, - .BuiltIn = IsBuiltIn, - .modUniqueID = this->modUIDs - 1, - .Address = (void *)fex, - .ExtendedHeaderAddress = (void *)DriverExtendedHeader, - .InterruptCallback = (void *)((uintptr_t)fex + (uintptr_t)fexE->Module.InterruptCallback), - .vma = vma, - }; - - if (fexE->Module.InterruptCallback) - { - for (uint16_t i = 0; i < sizeof(fexE->Module.Bind.Interrupt.Vector) / sizeof(fexE->Module.Bind.Interrupt.Vector[0]); i++) - { - if (fexE->Module.Bind.Interrupt.Vector[i] == 0) - break; - DrvFile.InterruptHook[i] = new ModuleInterruptHook(fexE->Module.Bind.Interrupt.Vector[i], DrvFile); - } - } - - KernelCallback KCallback{}; - KCallback.RawPtr = nullptr; - KCallback.Reason = CallbackReason::ConfigurationReason; - ModuleCode CallbackRet = ((ModuleCode(*)(KernelCallback *))((uintptr_t)fexE->Module.Callback + (uintptr_t)fex))(&KCallback); - - if (CallbackRet != ModuleCode::OK) - { - error("Module %s returned error %d", fexE->Module.Name, CallbackRet); - delete vma; - return CallbackRet; - } - - Modules.push_back(DrvFile); - return ModuleCode::OK; - } - default: - { - warn("Unknown driver type: %d", fexE->Module.Type); - delete vma; - return ModuleCode::UNKNOWN_MODULE_TYPE; - } - } - } -} diff --git a/core/module/module_binding/bind_pci.cpp b/core/module/module_binding/bind_pci.cpp deleted file mode 100644 index 3427dd4..0000000 --- a/core/module/module_binding/bind_pci.cpp +++ /dev/null @@ -1,145 +0,0 @@ -/* - This file is part of Fennix Kernel. - - Fennix Kernel is free software: you can redistribute it and/or - modify it under the terms of the GNU General Public License as - published by the Free Software Foundation, either version 3 of - the License, or (at your option) any later version. - - Fennix Kernel is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Fennix Kernel. If not, see . -*/ - -#include "../api.hpp" - -#include -#include -#include -#include -#include -#include -#include - -#include "../../../kernel.h" -#include "../../../mapi.hpp" -#include "../../../Fex.hpp" - -namespace Module -{ - ModuleCode Module::ModuleLoadBindPCI(uintptr_t ModuleAddress, size_t Size, bool IsBuiltIn) - { - FexExtended *DrvExtHdr = (FexExtended *)(ModuleAddress + EXTENDED_SECTION_ADDRESS); - if (IsBuiltIn) - DrvExtHdr = (FexExtended *)(((BuiltInModuleInfo *)ModuleAddress)->ExtendedHeader); - - uint16_t SizeOfVendorID = sizeof(DrvExtHdr->Module.Bind.PCI.VendorID) / - sizeof(DrvExtHdr->Module.Bind.PCI.VendorID[0]); - uint16_t SizeOfDeviceID = sizeof(DrvExtHdr->Module.Bind.PCI.DeviceID) / - sizeof(DrvExtHdr->Module.Bind.PCI.DeviceID[0]); - - for (uint16_t vID = 0; vID < SizeOfVendorID; vID++) - { - for (uint16_t dID = 0; dID < SizeOfDeviceID; dID++) - { - if (DrvExtHdr->Module.Bind.PCI.VendorID[vID] == 0 || - DrvExtHdr->Module.Bind.PCI.DeviceID[dID] == 0) - continue; - - std::vector devices = - PCIManager->FindPCIDevice(DrvExtHdr->Module.Bind.PCI.VendorID[vID], - DrvExtHdr->Module.Bind.PCI.DeviceID[dID]); - if (devices.size() == 0) - continue; - - foreach (auto Device in devices) - { - debug("[%ld] VendorID: %#x; DeviceID: %#x", - devices.size(), Device.Header->VendorID, - Device.Header->DeviceID); - - Memory::VirtualMemoryArea *vma = new Memory::VirtualMemoryArea(nullptr); - - BuiltInModuleInfo *bidi = (BuiltInModuleInfo *)ModuleAddress; - Fex *fex = nullptr; - if (!IsBuiltIn) - { - fex = (Fex *)vma->RequestPages(TO_PAGES(Size + 1)); - memcpy(fex, (void *)ModuleAddress, Size); - debug("Module allocated at %#lx-%#lx", fex, (uintptr_t)fex + Size); - } - else - fex = (Fex *)bidi->EntryPoint; - ModuleCode ret = CallModuleEntryPoint(fex, IsBuiltIn); - if (ret != ModuleCode::OK) - { - delete vma; - return ret; - } - - if (IsBuiltIn) - fex = 0x0; /* Addresses are absolute if built-in. */ - - FexExtended *fexE = IsBuiltIn ? (FexExtended *)bidi->ExtendedHeader : (FexExtended *)((uintptr_t)fex + EXTENDED_SECTION_ADDRESS); - debug("Starting driver %s", fexE->Module.Name); - - PCIManager->MapPCIAddresses(Device); - - switch (fexE->Module.Type) - { - case FexModuleType::FexModuleType_Generic: - case FexModuleType::FexModuleType_Display: - case FexModuleType::FexModuleType_Network: - case FexModuleType::FexModuleType_Storage: - case FexModuleType::FexModuleType_FileSystem: - case FexModuleType::FexModuleType_Input: - case FexModuleType::FexModuleType_Audio: - { - FexExtended *DriverExtendedHeader = (FexExtended *)vma->RequestPages(TO_PAGES(sizeof(FexExtended) + 1)); - memcpy(DriverExtendedHeader, fexE, sizeof(FexExtended)); - - ModuleFile DrvFile = { - .Enabled = true, - .BuiltIn = IsBuiltIn, - .modUniqueID = this->modUIDs - 1, - .Address = (void *)fex, - .ExtendedHeaderAddress = (void *)DriverExtendedHeader, - .InterruptCallback = (void *)((uintptr_t)fex + (uintptr_t)fexE->Module.InterruptCallback), - .vma = vma, - }; - - if (fexE->Module.InterruptCallback) - DrvFile.InterruptHook[0] = new ModuleInterruptHook(((int)((PCI::PCIHeader0 *)Device.Header)->InterruptLine), DrvFile); - - KernelCallback KCallback{}; - KCallback.RawPtr = Device.Header; - KCallback.Reason = CallbackReason::ConfigurationReason; - ModuleCode CallbackRet = ((ModuleCode(*)(KernelCallback *))((uintptr_t)fexE->Module.Callback + (uintptr_t)fex))(&KCallback); - - if (CallbackRet != ModuleCode::OK) - { - error("Module %s returned error %d", fexE->Module.Name, CallbackRet); - delete vma; - return CallbackRet; - } - - Modules.push_back(DrvFile); - return ModuleCode::OK; - } - default: - { - warn("Unknown driver type: %d", fexE->Module.Type); - delete vma; - return ModuleCode::UNKNOWN_MODULE_TYPE; - } - } - } - } - } - return ModuleCode::PCI_DEVICE_NOT_FOUND; - } -} diff --git a/core/module/module_binding/bind_process.cpp b/core/module/module_binding/bind_process.cpp deleted file mode 100644 index f3469de..0000000 --- a/core/module/module_binding/bind_process.cpp +++ /dev/null @@ -1,42 +0,0 @@ -/* - This file is part of Fennix Kernel. - - Fennix Kernel is free software: you can redistribute it and/or - modify it under the terms of the GNU General Public License as - published by the Free Software Foundation, either version 3 of - the License, or (at your option) any later version. - - Fennix Kernel is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Fennix Kernel. If not, see . -*/ - -#include "../api.hpp" - -#include -#include -#include -#include -#include -#include -#include - -#include "../../../kernel.h" -#include "../../../mapi.hpp" -#include "../../../Fex.hpp" - -namespace Module -{ - ModuleCode Module::ModuleLoadBindProcess(uintptr_t ModuleAddress, size_t Size, bool IsBuiltIn) - { - stub; - UNUSED(ModuleAddress); - UNUSED(Size); - UNUSED(IsBuiltIn); - return ModuleCode::NOT_IMPLEMENTED; - } -} diff --git a/core/pci.cpp b/core/pci.cpp index 1176059..6b31d37 100644 --- a/core/pci.cpp +++ b/core/pci.cpp @@ -279,6 +279,10 @@ namespace PCI { switch (VendorID) { + case 0x106B: + return "Apple Inc."; + case 0x104B: + return "Bus Logic"; case 0x1000: return "Symbios Logic"; case 0x1B36: @@ -317,12 +321,36 @@ namespace PCI { switch (VendorID) { + case Apple: + { + switch (DeviceID) + { + case 0x3f: + return "KeyLargo/Intrepid USB"; + default: + break; + } + break; + } + case BusLogic: + { + switch (DeviceID) + { + case 0x1040: + return "BT-946C (BA80C30) [MultiMaster 10]"; + default: + break; + } + break; + } case SymbiosLogic: { switch (DeviceID) { case 0x30: return "53c1030 PCI-X Fusion-MPT Dual Ultra320 SCSI"; + case 0x54: + return "SAS1068 PCI-X Fusion-MPT SAS"; case 0x1000: return "63C815"; default: @@ -420,6 +448,12 @@ namespace PCI return "RTL-8029(AS)"; case 0x8139: return "RTL-8139/8139C/8139C+ Ethernet Controller"; + case 0x8161: + return "RTL8111/8168/8411 PCI Express Gigabit Ethernet Controller"; + case 0x8168: + return "RTL8111/8168/8411 PCI Express Gigabit Ethernet Controller"; + case 0xC821: + return "RTL8821CE 802.11ac PCIe Wireless Network Adapter"; default: break; } @@ -503,6 +537,8 @@ namespace PCI return "82557/8/9/0/1 Ethernet Pro 100"; case 0x1209: return "8255xER/82551IT Fast Ethernet Controller"; + case 0x1004: + return "82543GC Gigabit Ethernet Controller (Copper)"; case 0x100E: return "82540EM Gigabit Ethernet Controller"; case 0x7190: @@ -519,6 +555,10 @@ namespace PCI return "7 Series/C210 Series Chipset Family USB xHCI Host Controller"; case 0x100F: return "82545EM Gigabit Ethernet Controller (Copper)"; + case 0x1903: + return "Xeon E3-1200 v5/E3-1500 v5/6th Gen Core Processor Thermal Subsystem"; + case 0x1911: + return "Xeon E3-1200 v5/v6 / E3-1500 v5 / 6th/7th Gen Core Processor Gaussian Mixture Model"; case 0x1371: return "ES1371/ES1373 / Creative Labs CT2518"; case 0x27b9: @@ -537,6 +577,8 @@ namespace PCI return "82801I (ICH9 Family) USB UHCI Controller #1"; case 0x2668: return "82801FB/FBM/FR/FW/FRW (ICH6 Family) High Definition Audio Controller"; + case 0x265C: + return "82801FB/FBM/FR/FW/FRW (ICH6 Family) USB2 EHCI Controller"; case 0x2415: return "82801AA AC'97 Audio Controller"; case 0x10D3: @@ -551,6 +593,40 @@ namespace PCI return "82801IR/IO/IH (ICH9R/DO/DH) 6 port SATA Controller [AHCI mode]"; case 0x2930: return "82801I (ICH9 Family) SMBus Controller"; + case 0x269E: + return "631xESB/632xESB IDE Controller"; + case 0x282A: + return "82801 Mobile SATA Controller [RAID mode]"; + case 0x5914: + return "Xeon E3-1200 v6/7th Gen Core Processor Host Bridge/DRAM Registers"; + case 0x5917: + return "UHD Graphics 620"; + case 0x9D10: + return "Sunrise Point-LP PCI Express Root Port #1"; + case 0x9D11: + return "Sunrise Point-LP PCI Express Root Port #2"; + case 0x9D12: + return "Sunrise Point-LP PCI Express Root Port #1"; + case 0x9D13: + return "Sunrise Point-LP PCI Express Root Port #1"; + case 0x9D14: + return "Sunrise Point-LP PCI Express Root Port #5"; + case 0x9D15: + return "Sunrise Point-LP PCI Express Root Port #6"; + case 0x9D21: + return "Sunrise Point-LP PMC"; + case 0x9D23: + return "Sunrise Point-LP SMBus"; + case 0x9D2F: + return "Sunrise Point-LP USB 3.0 xHCI Controller"; + case 0x9D31: + return "Sunrise Point-LP Thermal subsystem"; + case 0x9D3A: + return "Sunrise Point-LP CSME HECI #1"; + case 0x9D4E: + return "Intel(R) 100 Series Chipset Family LPC Controller/eSPI Controller - 9D4E"; + case 0x9D71: + return "Sunrise Point-LP HD Audio"; default: break; } @@ -567,9 +643,20 @@ namespace PCI } break; } + case NVIDIACorporation: + { + switch (DeviceID) + { + case 0x174D: + return "GM108M [GeForce MX130]"; + default: + break; + } + break; default: break; } + } fixme("Unknown device %04x:%04x", VendorID, DeviceID); return u32ToHexString(DeviceID); } @@ -772,9 +859,12 @@ namespace PCI } #ifdef DEBUG - void e(PCIDeviceHeader *hdr) + void e(PCIDevice dev) { - debug("%#x:%#x\t\t%s / %s / %s / %s / %s", + PCIDeviceHeader *hdr = dev.Header; + + debug("%02x.%02x.%02x - %#x:%#x\t\t%s / %s / %s / %s / %s", + dev.Bus, dev.Device, dev.Function, hdr->VendorID, hdr->DeviceID, Descriptors::GetVendorName(hdr->VendorID), Descriptors::GetDeviceName(hdr->VendorID, hdr->DeviceID), @@ -784,27 +874,31 @@ namespace PCI } #endif - void PCI::MapPCIAddresses(PCIDevice Device, Memory::PageTable *Table) + void Manager::MapPCIAddresses(PCIDevice Device, Memory::PageTable *Table) { debug("Header Type: %d", Device.Header->HeaderType); switch (Device.Header->HeaderType) { + case 128: + warn("Unknown header type %d! Guessing PCI Header 0", + Device.Header->HeaderType); + [[fallthrough]]; case 0: /* PCI Header 0 */ { - uint32_t BAR[6] = {0}; - size_t BARsSize[6] = {0}; + PCIHeader0 *hdr0 = (PCIHeader0 *)Device.Header; - BAR[0] = ((PCIHeader0 *)Device.Header)->BAR0; - BAR[1] = ((PCIHeader0 *)Device.Header)->BAR1; - BAR[2] = ((PCIHeader0 *)Device.Header)->BAR2; - BAR[3] = ((PCIHeader0 *)Device.Header)->BAR3; - BAR[4] = ((PCIHeader0 *)Device.Header)->BAR4; - BAR[5] = ((PCIHeader0 *)Device.Header)->BAR5; + uint32_t BAR[6]; + size_t BARsSize[6]; + + BAR[0] = hdr0->BAR0; + BAR[1] = hdr0->BAR1; + BAR[2] = hdr0->BAR2; + BAR[3] = hdr0->BAR3; + BAR[4] = hdr0->BAR4; + BAR[5] = hdr0->BAR5; debug("Type: %d; IOBase: %#lx; MemoryBase: %#lx", - BAR[0] & 1, - BAR[1] & (~3), - BAR[0] & (~15)); + BAR[0] & 1, BAR[1] & (~3), BAR[0] & (~15)); /* BARs Size */ for (short i = 0; i < 6; i++) @@ -812,25 +906,28 @@ namespace PCI if (BAR[i] == 0) continue; + size_t size; if ((BAR[i] & 1) == 0) /* Memory Base */ { - ((PCIHeader0 *)Device.Header)->BAR0 = 0xFFFFFFFF; - size_t size = ((PCIHeader0 *)Device.Header)->BAR0; - ((PCIHeader0 *)Device.Header)->BAR0 = BAR[i]; + hdr0->BAR0 = 0xFFFFFFFF; + size = hdr0->BAR0; + hdr0->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]); + debug("BAR%d %#lx size: %d", + i, BAR[i], BARsSize[i]); } else if ((BAR[i] & 1) == 1) /* I/O Base */ { - ((PCIHeader0 *)Device.Header)->BAR1 = 0xFFFFFFFF; - size_t size = ((PCIHeader0 *)Device.Header)->BAR1; - ((PCIHeader0 *)Device.Header)->BAR1 = BAR[i]; + hdr0->BAR1 = 0xFFFFFFFF; + size = hdr0->BAR1; + hdr0->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]); + debug("BAR%d %#lx size: %d", + i, BAR[i], BARsSize[i]); } } @@ -845,18 +942,24 @@ namespace PCI uintptr_t BARBase = BAR[i] & (~15); size_t BARSize = BARsSize[i]; - debug("Mapping BAR%d %#lx-%#lx", i, BARBase, BARBase + BARSize); - Memory::Virtual(Table).Map((void *)BARBase, (void *)BARBase, BARSize, - Memory::PTFlag::RW | Memory::PTFlag::PWT); + debug("Mapping BAR%d %#lx-%#lx", + i, BARBase, BARBase + BARSize); + + if (BARSize > 0) + Memory::Virtual(Table).Map((void *)BARBase, (void *)BARBase, + BARSize, Memory::RW | Memory::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(Table).Map((void *)BARBase, (void *)BARBase, BARSize, - Memory::PTFlag::RW | Memory::PTFlag::PWT); + debug("Mapping BAR%d %#x-%#x", + i, BARBase, BARBase + BARSize); + + if (BARSize > 0) + Memory::Virtual(Table).Map((void *)BARBase, (void *)BARBase, + BARSize, Memory::RW | Memory::PWT); } } break; @@ -874,12 +977,12 @@ namespace PCI default: { error("Unknown header type %d", Device.Header->HeaderType); - return; + break; } } } - void PCI::EnumerateFunction(uint64_t DeviceAddress, uint32_t Function, PCIDevice dev) + void Manager::EnumerateFunction(uint64_t DeviceAddress, uint32_t Function, PCIDevice dev) { dev.Function = Function; @@ -896,11 +999,11 @@ namespace PCI Devices.push_back(dev); #ifdef DEBUG - e(PCIDeviceHdr); + e(dev); #endif } - void PCI::EnumerateDevice(uint64_t BusAddress, uint32_t Device, PCIDevice dev) + void Manager::EnumerateDevice(uint64_t BusAddress, uint32_t Device, PCIDevice dev) { dev.Device = Device; @@ -918,7 +1021,7 @@ namespace PCI EnumerateFunction(DeviceAddress, Function, dev); } - void PCI::EnumerateBus(uint64_t BaseAddress, uint32_t Bus, PCIDevice dev) + void Manager::EnumerateBus(uint64_t BaseAddress, uint32_t Bus, PCIDevice dev) { dev.Bus = Bus; @@ -945,9 +1048,9 @@ namespace PCI EnumerateDevice(BusAddress, Device, dev); } - std::vector PCI::FindPCIDevice(uint8_t Class, uint8_t Subclass, uint8_t ProgIF) + std::list Manager::FindPCIDevice(uint8_t Class, uint8_t Subclass, uint8_t ProgIF) { - std::vector DeviceFound; + std::list DeviceFound; foreach (auto dev in Devices) { if (dev.Header->Class == Class && @@ -960,9 +1063,9 @@ namespace PCI return DeviceFound; } - std::vector PCI::FindPCIDevice(int VendorID, int DeviceID) + std::list Manager::FindPCIDevice(uint16_t VendorID, uint16_t DeviceID) { - std::vector DeviceFound; + std::list DeviceFound; foreach (auto dev in Devices) { if (dev.Header->VendorID == VendorID && @@ -974,7 +1077,28 @@ namespace PCI return DeviceFound; } - PCI::PCI() + std::list Manager::FindPCIDevice(std::list VendorIDs, + std::list DeviceIDs) + { + std::list DeviceFound; + foreach (auto dev in Devices) + { + foreach (auto VendorID in VendorIDs) + { + foreach (auto DeviceID in DeviceIDs) + { + if (dev.Header->VendorID == VendorID && + dev.Header->DeviceID == DeviceID) + { + DeviceFound.push_back(dev); + } + } + } + } + return DeviceFound; + } + + Manager::Manager() { #if defined(a86) if (!PowerManager->GetACPI()) @@ -990,7 +1114,7 @@ namespace PCI } int Entries = s_cst(int, ((((ACPI::ACPI *)PowerManager->GetACPI())->MCFG->Header.Length) - sizeof(ACPI::ACPI::MCFGHeader)) / sizeof(DeviceConfig)); - Memory::Virtual vmm = Memory::Virtual(KernelPageTable); + Memory::Virtual vmm(KernelPageTable); for (int t = 0; t < Entries; t++) { DeviceConfig *NewDeviceConfig = (DeviceConfig *)((uintptr_t)((ACPI::ACPI *)PowerManager->GetACPI())->MCFG + sizeof(ACPI::ACPI::MCFGHeader) + (sizeof(DeviceConfig) * t)); @@ -1008,5 +1132,5 @@ namespace PCI #endif } - PCI::~PCI() {} + Manager::~Manager() {} } diff --git a/core/power.cpp b/core/power.cpp index 4f0c2f0..c2c5e3b 100644 --- a/core/power.cpp +++ b/core/power.cpp @@ -32,15 +32,6 @@ namespace Power if (((ACPI::DSDT *)this->dsdt)->ACPIShutdownSupported) ((ACPI::DSDT *)this->dsdt)->Reboot(); - uint8_t val = 0x02; - while (val & 0x02) - val = inb(0x64); - outb(0x64, 0xFE); - - warn("Executing the second attempt to reboot..."); - - // https://wiki.osdev.org/Reboot - /* Second attempt to reboot */ asmv("cli"); uint8_t temp; do @@ -50,24 +41,24 @@ namespace Power inb(0x60); } while (((temp) & (1 << (1))) != 0); outb(0x64, 0xFE); - - CPU::Stop(); } void Power::Shutdown() { if (((ACPI::ACPI *)this->acpi)->FADT) + { if (((ACPI::DSDT *)this->dsdt)->ACPIShutdownSupported) ((ACPI::DSDT *)this->dsdt)->Shutdown(); - /* TODO: If no ACPI, display "It is now safe to turn off your computer" */ - - /* FIXME: Detect emulators and use their shutdown methods */ + else + KPrint("Shutdown not supported"); + /* TODO: If no ACPI, display "It is now safe to turn off your computer"? */ + } + /* FIXME: Detect emulators and use their shutdown methods */ #ifdef DEBUG outl(0xB004, 0x2000); // for qemu outl(0x604, 0x2000); // if qemu not working, bochs and older versions of qemu outl(0x4004, 0x3400); // virtual box #endif - CPU::Stop(); } void Power::InitDSDT() diff --git a/core/random.cpp b/core/random.cpp index a0df724..7ef03bd 100644 --- a/core/random.cpp +++ b/core/random.cpp @@ -20,124 +20,124 @@ namespace Random { - static uint64_t Seed = 0xdeadbeef; + static uint64_t Seed = 0xdeadbeef; - uint16_t rand16() - { + uint16_t rand16() + { #if defined(a86) - static int RDRANDFlag = 0x1A1A; - if (unlikely(RDRANDFlag == 0x1A1A)) - { - if (strcmp(CPU::Hypervisor(), x86_CPUID_VENDOR_TCG) != 0) - { - if (strcmp(CPU::Vendor(), x86_CPUID_VENDOR_AMD) == 0) - { - CPU::x86::AMD::CPUID0x00000001 cpuid; - cpuid.Get(); - RDRANDFlag = cpuid.ECX.RDRAND; - } - else if (strcmp(CPU::Vendor(), x86_CPUID_VENDOR_INTEL) == 0) - { - CPU::x86::Intel::CPUID0x00000001 cpuid; - cpuid.Get(); - RDRANDFlag = cpuid.ECX.RDRAND; - } - } - else - RDRANDFlag = 0; - } + static int RDRANDFlag = 0x1A1A; + if (unlikely(RDRANDFlag == 0x1A1A)) + { + if (strcmp(CPU::Hypervisor(), x86_CPUID_VENDOR_TCG) != 0) + { + if (strcmp(CPU::Vendor(), x86_CPUID_VENDOR_AMD) == 0) + { + CPU::x86::AMD::CPUID0x00000001 cpuid; + cpuid.Get(); + RDRANDFlag = cpuid.ECX.RDRAND; + } + else if (strcmp(CPU::Vendor(), x86_CPUID_VENDOR_INTEL) == 0) + { + CPU::x86::Intel::CPUID0x00000001 cpuid; + cpuid.Get(); + RDRANDFlag = cpuid.ECX.RDRAND; + } + } + else + RDRANDFlag = 0; + } - if (RDRANDFlag) - { - uint16_t RDRANDValue = 0; - asmv("1: rdrand %0; jnc 1b" - : "=r"(RDRANDValue)); - return RDRANDValue; - } + if (RDRANDFlag) + { + uint16_t RDRANDValue = 0; + asmv("1: rdrand %0; jnc 1b" + : "=r"(RDRANDValue)); + return RDRANDValue; + } - Seed = Seed * 1103515245 + 12345; - return (uint16_t)(Seed / 65536) % __UINT16_MAX__; + Seed = Seed * 1103515245 + 12345; + return (uint16_t)(Seed / 65536) % __UINT16_MAX__; #endif - return 0; - } + return 0; + } - uint32_t rand32() - { + uint32_t rand32() + { #if defined(a86) - static int RDRANDFlag = 0x1A1A; - if (unlikely(RDRANDFlag == 0x1A1A)) - { - if (strcmp(CPU::Hypervisor(), x86_CPUID_VENDOR_TCG) != 0) - { - if (strcmp(CPU::Vendor(), x86_CPUID_VENDOR_AMD) == 0) - { - CPU::x86::AMD::CPUID0x00000001 cpuid; - cpuid.Get(); - RDRANDFlag = cpuid.ECX.RDRAND; - } - else if (strcmp(CPU::Vendor(), x86_CPUID_VENDOR_INTEL) == 0) - { - CPU::x86::Intel::CPUID0x00000001 cpuid; - cpuid.Get(); - RDRANDFlag = cpuid.ECX.RDRAND; - } - } - else - RDRANDFlag = 0; - } + static int RDRANDFlag = 0x1A1A; + if (unlikely(RDRANDFlag == 0x1A1A)) + { + if (strcmp(CPU::Hypervisor(), x86_CPUID_VENDOR_TCG) != 0) + { + if (strcmp(CPU::Vendor(), x86_CPUID_VENDOR_AMD) == 0) + { + CPU::x86::AMD::CPUID0x00000001 cpuid; + cpuid.Get(); + RDRANDFlag = cpuid.ECX.RDRAND; + } + else if (strcmp(CPU::Vendor(), x86_CPUID_VENDOR_INTEL) == 0) + { + CPU::x86::Intel::CPUID0x00000001 cpuid; + cpuid.Get(); + RDRANDFlag = cpuid.ECX.RDRAND; + } + } + else + RDRANDFlag = 0; + } - if (RDRANDFlag) - { - uint32_t RDRANDValue = 0; - asmv("1: rdrand %0; jnc 1b" - : "=r"(RDRANDValue)); - return RDRANDValue; - } + if (RDRANDFlag) + { + uint32_t RDRANDValue = 0; + asmv("1: rdrand %0; jnc 1b" + : "=r"(RDRANDValue)); + return RDRANDValue; + } - Seed = Seed * 1103515245 + 12345; - return (uint32_t)(Seed / 65536) % __UINT32_MAX__; + Seed = Seed * 1103515245 + 12345; + return (uint32_t)(Seed / 65536) % __UINT32_MAX__; #endif - return 0; - } + return 0; + } - uint64_t rand64() - { + uint64_t rand64() + { #if defined(a86) - static int RDRANDFlag = 0x1A1A; - if (unlikely(RDRANDFlag == 0x1A1A)) - { - if (strcmp(CPU::Hypervisor(), x86_CPUID_VENDOR_TCG) != 0) - { - if (strcmp(CPU::Vendor(), x86_CPUID_VENDOR_AMD) == 0) - { - CPU::x86::AMD::CPUID0x00000001 cpuid; - cpuid.Get(); - RDRANDFlag = cpuid.ECX.RDRAND; - } - else if (strcmp(CPU::Vendor(), x86_CPUID_VENDOR_INTEL) == 0) - { - CPU::x86::Intel::CPUID0x00000001 cpuid; - cpuid.Get(); - RDRANDFlag = cpuid.ECX.RDRAND; - } - } - else - RDRANDFlag = 0; - } + static int RDRANDFlag = 0x1A1A; + if (unlikely(RDRANDFlag == 0x1A1A)) + { + if (strcmp(CPU::Hypervisor(), x86_CPUID_VENDOR_TCG) != 0) + { + if (strcmp(CPU::Vendor(), x86_CPUID_VENDOR_AMD) == 0) + { + CPU::x86::AMD::CPUID0x00000001 cpuid; + cpuid.Get(); + RDRANDFlag = cpuid.ECX.RDRAND; + } + else if (strcmp(CPU::Vendor(), x86_CPUID_VENDOR_INTEL) == 0) + { + CPU::x86::Intel::CPUID0x00000001 cpuid; + cpuid.Get(); + RDRANDFlag = cpuid.ECX.RDRAND; + } + } + else + RDRANDFlag = 0; + } - if (RDRANDFlag) - { - uintptr_t RDRANDValue = 0; - asmv("1: rdrand %0; jnc 1b" - : "=r"(RDRANDValue)); - return RDRANDValue; - } + if (RDRANDFlag) + { + uintptr_t RDRANDValue = 0; + asmv("1: rdrand %0; jnc 1b" + : "=r"(RDRANDValue)); + return RDRANDValue; + } - Seed = Seed * 1103515245 + 12345; - return (uint64_t)(Seed / 65536) % __UINT64_MAX__; + Seed = Seed * 1103515245 + 12345; + return (uint64_t)(Seed / 65536) % __UINT64_MAX__; #endif - return 0; - } + return 0; + } - void ChangeSeed(uint64_t CustomSeed) { Seed = CustomSeed; } + void ChangeSeed(uint64_t CustomSeed) { Seed = CustomSeed; } } diff --git a/core/smbios.hpp b/core/smbios.hpp index 92af5d3..5fe9769 100644 --- a/core/smbios.hpp +++ b/core/smbios.hpp @@ -22,336 +22,336 @@ namespace SMBIOS { - enum SMBIOSType - { - SMBIOSTypeBIOSInformation = 0, - SMBIOSTypeSystemInformation = 1, - SMBIOSTypeBaseBoardInformation = 2, - SMBIOSTypeSystemEnclosure = 3, - SMBIOSTypeProcessorInformation = 4, - SMBIOSTypeMemoryControllerInformation = 5, - SMBIOSTypeMemoryModuleInformation = 6, - SMBIOSTypeCacheInformation = 7, - SMBIOSTypePortConnectorInformation = 8, - SMBIOSTypeSystemSlots = 9, - SMBIOSTypeOnBoardDevicesInformation = 10, - SMBIOSTypeOEMStrings = 11, - SMBIOSTypeSystemConfigurationOptions = 12, - SMBIOSTypeBIOSLanguageInformation = 13, - SMBIOSTypeGroupAssociations = 14, - SMBIOSTypeSystemEventLog = 15, - SMBIOSTypePhysicalMemoryArray = 16, - SMBIOSTypeMemoryDevice = 17, - SMBIOSType32BitMemoryErrorInformation = 18, - SMBIOSTypeMemoryArrayMappedAddress = 19, - SMBIOSTypeMemoryDeviceMappedAddress = 20, - SMBIOSTypeBuiltInPointingDevice = 21, - SMBIOSTypePortableBattery = 22, - SMBIOSTypeSystemReset = 23, - SMBIOSTypeHardwareSecurity = 24, - SMBIOSTypeSystemPowerControls = 25, - SMBIOSTypeVoltageProbe = 26, - SMBIOSTypeCoolingDevice = 27, - SMBIOSTypeTemperatureProbe = 28, - SMBIOSTypeElectricalCurrentProbe = 29, - SMBIOSTypeOutofBandRemoteAccess = 30, - SMBIOSTypeBootIntegrityServices = 31, - SMBIOSTypeSystemBoot = 32, - SMBIOSType64BitMemoryErrorInformation = 33, - SMBIOSTypeManagementDevice = 34, - SMBIOSTypeManagementDeviceComponent = 35, - SMBIOSTypeManagementDeviceThresholdData = 36, - SMBIOSTypeMemoryChannel = 37, - SMBIOSTypeIPMIDevice = 38, - SMBIOSTypePowerSupply = 39, - SMBIOSTypeAdditionalInformation = 40, - SMBIOSTypeOnboardDevicesExtendedInformation = 41, - SMBIOSTypeManagementControllerHostInterface = 42, - SMBIOSTypeTPMDevice = 43, - SMBIOSTypeProcessorAdditionalInformation = 44, - SMBIOSTypeInactive = 126, - SMBIOSTypeEndOfTable = 127 - }; + enum SMBIOSType + { + SMBIOSTypeBIOSInformation = 0, + SMBIOSTypeSystemInformation = 1, + SMBIOSTypeBaseBoardInformation = 2, + SMBIOSTypeSystemEnclosure = 3, + SMBIOSTypeProcessorInformation = 4, + SMBIOSTypeMemoryControllerInformation = 5, + SMBIOSTypeMemoryModuleInformation = 6, + SMBIOSTypeCacheInformation = 7, + SMBIOSTypePortConnectorInformation = 8, + SMBIOSTypeSystemSlots = 9, + SMBIOSTypeOnBoardDevicesInformation = 10, + SMBIOSTypeOEMStrings = 11, + SMBIOSTypeSystemConfigurationOptions = 12, + SMBIOSTypeBIOSLanguageInformation = 13, + SMBIOSTypeGroupAssociations = 14, + SMBIOSTypeSystemEventLog = 15, + SMBIOSTypePhysicalMemoryArray = 16, + SMBIOSTypeMemoryDevice = 17, + SMBIOSType32BitMemoryErrorInformation = 18, + SMBIOSTypeMemoryArrayMappedAddress = 19, + SMBIOSTypeMemoryDeviceMappedAddress = 20, + SMBIOSTypeBuiltInPointingDevice = 21, + SMBIOSTypePortableBattery = 22, + SMBIOSTypeSystemReset = 23, + SMBIOSTypeHardwareSecurity = 24, + SMBIOSTypeSystemPowerControls = 25, + SMBIOSTypeVoltageProbe = 26, + SMBIOSTypeCoolingDevice = 27, + SMBIOSTypeTemperatureProbe = 28, + SMBIOSTypeElectricalCurrentProbe = 29, + SMBIOSTypeOutofBandRemoteAccess = 30, + SMBIOSTypeBootIntegrityServices = 31, + SMBIOSTypeSystemBoot = 32, + SMBIOSType64BitMemoryErrorInformation = 33, + SMBIOSTypeManagementDevice = 34, + SMBIOSTypeManagementDeviceComponent = 35, + SMBIOSTypeManagementDeviceThresholdData = 36, + SMBIOSTypeMemoryChannel = 37, + SMBIOSTypeIPMIDevice = 38, + SMBIOSTypePowerSupply = 39, + SMBIOSTypeAdditionalInformation = 40, + SMBIOSTypeOnboardDevicesExtendedInformation = 41, + SMBIOSTypeManagementControllerHostInterface = 42, + SMBIOSTypeTPMDevice = 43, + SMBIOSTypeProcessorAdditionalInformation = 44, + SMBIOSTypeInactive = 126, + SMBIOSTypeEndOfTable = 127 + }; - struct SMBIOSHeader - { - unsigned char Type; - unsigned char Length; - unsigned short Handle; - }; + struct SMBIOSHeader + { + unsigned char Type; + unsigned char Length; + unsigned short Handle; + }; - struct SMBIOSEntryPoint - { - char EntryPointString[4]; - unsigned char Checksum; - unsigned char Length; - unsigned char MajorVersion; - unsigned char MinorVersion; - unsigned short MaxStructureSize; - unsigned char EntryPointRevision; - char FormattedArea[5]; - char EntryPointString2[5]; - unsigned char Checksum2; - unsigned short TableLength; - unsigned int TableAddress; - unsigned short NumberOfStructures; - unsigned char BCDRevision; - }; + struct SMBIOSEntryPoint + { + char EntryPointString[4]; + unsigned char Checksum; + unsigned char Length; + unsigned char MajorVersion; + unsigned char MinorVersion; + unsigned short MaxStructureSize; + unsigned char EntryPointRevision; + char FormattedArea[5]; + char EntryPointString2[5]; + unsigned char Checksum2; + unsigned short TableLength; + unsigned int TableAddress; + unsigned short NumberOfStructures; + unsigned char BCDRevision; + }; - static inline char *SMBIOSNextString(char *Str) - { - while (*Str != '\0') - Str++; - return Str + 1; - } + static inline char *SMBIOSNextString(char *Str) + { + while (*Str != '\0') + Str++; + return Str + 1; + } - struct SMBIOSBIOSInformation - { - SMBIOSHeader Header; - unsigned char Vendor; - unsigned char Version; - unsigned short StartingAddressSegment; - unsigned char ReleaseDate; - unsigned char ROMSize; - unsigned long Characteristics; - unsigned char CharacteristicsExtensionBytes[2]; - unsigned char SystemBIOSMajorRelease; - unsigned char SystemBIOSMinorRelease; - unsigned char EmbeddedControllerFirmwareMajorRelease; - unsigned char EmbeddedControllerFirmwareMinorRelease; + struct SMBIOSBIOSInformation + { + SMBIOSHeader Header; + unsigned char Vendor; + unsigned char Version; + unsigned short StartingAddressSegment; + unsigned char ReleaseDate; + unsigned char ROMSize; + unsigned long Characteristics; + unsigned char CharacteristicsExtensionBytes[2]; + unsigned char SystemBIOSMajorRelease; + unsigned char SystemBIOSMinorRelease; + unsigned char EmbeddedControllerFirmwareMajorRelease; + unsigned char EmbeddedControllerFirmwareMinorRelease; - const char *GetString(unsigned char Index) - { - char *Str = (char *)((unsigned long)this + this->Header.Length); - Index--; - if (Index == 0 || Index > 10) - return Str; - for (unsigned char i = 0; i < Index; i++) - Str = SMBIOSNextString(Str); - return Str; - } - }; + const char *GetString(unsigned char Index) + { + char *Str = (char *)((unsigned long)this + this->Header.Length); + Index--; + if (Index == 0 || Index > 10) + return Str; + for (unsigned char i = 0; i < Index; i++) + Str = SMBIOSNextString(Str); + return Str; + } + }; - struct SMBIOSSystemInformation - { - SMBIOSHeader Header; - unsigned char Manufacturer; - unsigned char ProductName; - unsigned char Version; - unsigned char SerialNumber; - unsigned char UUID[16]; - unsigned char WakeUpType; - unsigned char SKU; - unsigned char Family; + struct SMBIOSSystemInformation + { + SMBIOSHeader Header; + unsigned char Manufacturer; + unsigned char ProductName; + unsigned char Version; + unsigned char SerialNumber; + unsigned char UUID[16]; + unsigned char WakeUpType; + unsigned char SKU; + unsigned char Family; - const char *GetString(unsigned char Index) - { - char *Str = (char *)((unsigned long)this + this->Header.Length); - Index--; - if (Index == 0 || Index > 10) - return Str; - for (unsigned char i = 0; i < Index; i++) - Str = SMBIOSNextString(Str); - return Str; - } - }; + const char *GetString(unsigned char Index) + { + char *Str = (char *)((unsigned long)this + this->Header.Length); + Index--; + if (Index == 0 || Index > 10) + return Str; + for (unsigned char i = 0; i < Index; i++) + Str = SMBIOSNextString(Str); + return Str; + } + }; - struct SMBIOSBaseBoardInformation - { - SMBIOSHeader Header; - unsigned char Manufacturer; - unsigned char Product; - unsigned char Version; - unsigned char SerialNumber; - unsigned char AssetTag; - unsigned char FeatureFlags; - unsigned char LocationInChassis; - unsigned short ChassisHandle; - unsigned char BoardType; - unsigned char NumberOfContainedObjectHandles; - unsigned short ContainedObjectHandles[0]; + struct SMBIOSBaseBoardInformation + { + SMBIOSHeader Header; + unsigned char Manufacturer; + unsigned char Product; + unsigned char Version; + unsigned char SerialNumber; + unsigned char AssetTag; + unsigned char FeatureFlags; + unsigned char LocationInChassis; + unsigned short ChassisHandle; + unsigned char BoardType; + unsigned char NumberOfContainedObjectHandles; + unsigned short ContainedObjectHandles[0]; - const char *GetString(unsigned char Index) - { - char *Str = (char *)((unsigned long)this + this->Header.Length); - Index--; - if (Index == 0 || Index > 10) - return Str; - for (unsigned char i = 0; i < Index; i++) - Str = SMBIOSNextString(Str); - return Str; - } - }; + const char *GetString(unsigned char Index) + { + char *Str = (char *)((unsigned long)this + this->Header.Length); + Index--; + if (Index == 0 || Index > 10) + return Str; + for (unsigned char i = 0; i < Index; i++) + Str = SMBIOSNextString(Str); + return Str; + } + }; - struct SMBIOSProcessorInformation - { - SMBIOSHeader Header; - unsigned char SocketDesignation; - unsigned char ProcessorType; - unsigned char ProcessorFamily; - unsigned char ProcessorManufacturer; - unsigned long ProcessorID; - unsigned char ProcessorVersion; - unsigned char Voltage; - unsigned short ExternalClock; - unsigned short MaxSpeed; - unsigned short CurrentSpeed; - unsigned char Status; - unsigned char ProcessorUpgrade; - unsigned short L1CacheHandle; - unsigned short L2CacheHandle; - unsigned short L3CacheHandle; - unsigned char SerialNumber; - unsigned char AssetTag; - unsigned char PartNumber; - unsigned char CoreCount; - unsigned char CoreEnabled; - unsigned char ThreadCount; - unsigned short ProcessorCharacteristics; - unsigned short ProcessorFamily2; - unsigned short CoreCount2; - unsigned short CoreEnabled2; - unsigned short ThreadCount2; + struct SMBIOSProcessorInformation + { + SMBIOSHeader Header; + unsigned char SocketDesignation; + unsigned char ProcessorType; + unsigned char ProcessorFamily; + unsigned char ProcessorManufacturer; + unsigned long ProcessorID; + unsigned char ProcessorVersion; + unsigned char Voltage; + unsigned short ExternalClock; + unsigned short MaxSpeed; + unsigned short CurrentSpeed; + unsigned char Status; + unsigned char ProcessorUpgrade; + unsigned short L1CacheHandle; + unsigned short L2CacheHandle; + unsigned short L3CacheHandle; + unsigned char SerialNumber; + unsigned char AssetTag; + unsigned char PartNumber; + unsigned char CoreCount; + unsigned char CoreEnabled; + unsigned char ThreadCount; + unsigned short ProcessorCharacteristics; + unsigned short ProcessorFamily2; + unsigned short CoreCount2; + unsigned short CoreEnabled2; + unsigned short ThreadCount2; - const char *GetString(unsigned char Index) - { - char *Str = (char *)((unsigned long)this + this->Header.Length); - Index--; - if (Index == 0 || Index > 10) - return Str; - for (unsigned char i = 0; i < Index; i++) - Str = SMBIOSNextString(Str); - return Str; - } - }; + const char *GetString(unsigned char Index) + { + char *Str = (char *)((unsigned long)this + this->Header.Length); + Index--; + if (Index == 0 || Index > 10) + return Str; + for (unsigned char i = 0; i < Index; i++) + Str = SMBIOSNextString(Str); + return Str; + } + }; - struct SMBIOSMemoryDevice - { - SMBIOSHeader Header; - unsigned char PhysicalMemoryArrayHandle; - unsigned char MemoryErrorInformationHandle; - unsigned short TotalWidth; - unsigned short DataWidth; - unsigned short Size; - unsigned char FormFactor; - unsigned char DeviceSet; - unsigned char DeviceLocator; - unsigned char BankLocator; - unsigned char MemoryType; - unsigned short TypeDetail; - unsigned short Speed; - unsigned char Manufacturer; - unsigned char SerialNumber; - unsigned char AssetTag; - unsigned char PartNumber; - unsigned char Attributes; - unsigned short ExtendedSize; - unsigned short ConfiguredMemoryClockSpeed; - unsigned short MinimumVoltage; - unsigned short MaximumVoltage; - unsigned short ConfiguredVoltage; - unsigned char MemoryTechnology; - unsigned char OperatingModeCapability; - unsigned char FirmwareVersion; - unsigned char ModuleManufacturerID; - unsigned char ModuleProductID; - unsigned char MemorySubsystemControllerManufacturerID; - unsigned char MemorySubsystemControllerProductID; - unsigned short NonVolatileSize; - unsigned short VolatileSize; - unsigned short CacheSize; - unsigned short LogicalSize; - unsigned char ExtendedSpeed; - unsigned char ExtendedConfiguredMemorySpeed; + struct SMBIOSMemoryDevice + { + SMBIOSHeader Header; + unsigned char PhysicalMemoryArrayHandle; + unsigned char MemoryErrorInformationHandle; + unsigned short TotalWidth; + unsigned short DataWidth; + unsigned short Size; + unsigned char FormFactor; + unsigned char DeviceSet; + unsigned char DeviceLocator; + unsigned char BankLocator; + unsigned char MemoryType; + unsigned short TypeDetail; + unsigned short Speed; + unsigned char Manufacturer; + unsigned char SerialNumber; + unsigned char AssetTag; + unsigned char PartNumber; + unsigned char Attributes; + unsigned short ExtendedSize; + unsigned short ConfiguredMemoryClockSpeed; + unsigned short MinimumVoltage; + unsigned short MaximumVoltage; + unsigned short ConfiguredVoltage; + unsigned char MemoryTechnology; + unsigned char OperatingModeCapability; + unsigned char FirmwareVersion; + unsigned char ModuleManufacturerID; + unsigned char ModuleProductID; + unsigned char MemorySubsystemControllerManufacturerID; + unsigned char MemorySubsystemControllerProductID; + unsigned short NonVolatileSize; + unsigned short VolatileSize; + unsigned short CacheSize; + unsigned short LogicalSize; + unsigned char ExtendedSpeed; + unsigned char ExtendedConfiguredMemorySpeed; - const char *GetString(unsigned char Index) - { - char *Str = (char *)((unsigned long)this + this->Header.Length); - Index--; - if (Index == 0 || Index > 10) - return Str; - for (unsigned char i = 0; i < Index; i++) - Str = SMBIOSNextString(Str); - return Str; - } - }; + const char *GetString(unsigned char Index) + { + char *Str = (char *)((unsigned long)this + this->Header.Length); + Index--; + if (Index == 0 || Index > 10) + return Str; + for (unsigned char i = 0; i < Index; i++) + Str = SMBIOSNextString(Str); + return Str; + } + }; - struct SMBIOSMemoryArrayMappedAddress - { - SMBIOSHeader Header; - unsigned int StartingAddress; - unsigned int EndingAddress; - unsigned short MemoryArrayHandle; - unsigned char PartitionWidth; + struct SMBIOSMemoryArrayMappedAddress + { + SMBIOSHeader Header; + unsigned int StartingAddress; + unsigned int EndingAddress; + unsigned short MemoryArrayHandle; + unsigned char PartitionWidth; - const char *GetString(unsigned char Index) - { - char *Str = (char *)((unsigned long)this + this->Header.Length); - Index--; - if (Index == 0 || Index > 10) - return Str; - for (unsigned char i = 0; i < Index; i++) - Str = SMBIOSNextString(Str); - return Str; - } - }; + const char *GetString(unsigned char Index) + { + char *Str = (char *)((unsigned long)this + this->Header.Length); + Index--; + if (Index == 0 || Index > 10) + return Str; + for (unsigned char i = 0; i < Index; i++) + Str = SMBIOSNextString(Str); + return Str; + } + }; - struct SMBIOSMemoryDeviceMappedAddress - { - SMBIOSHeader Header; - unsigned int StartingAddress; - unsigned int EndingAddress; - unsigned short MemoryDeviceHandle; - unsigned short MemoryArrayMappedAddressHandle; - unsigned char PartitionRowPosition; - unsigned char InterleavePosition; - unsigned char InterleavedDataDepth; + struct SMBIOSMemoryDeviceMappedAddress + { + SMBIOSHeader Header; + unsigned int StartingAddress; + unsigned int EndingAddress; + unsigned short MemoryDeviceHandle; + unsigned short MemoryArrayMappedAddressHandle; + unsigned char PartitionRowPosition; + unsigned char InterleavePosition; + unsigned char InterleavedDataDepth; - const char *GetString(unsigned char Index) - { - char *Str = (char *)((unsigned long)this + this->Header.Length); - Index--; - if (Index == 0 || Index > 10) - return Str; - for (unsigned char i = 0; i < Index; i++) - Str = SMBIOSNextString(Str); - return Str; - } - }; + const char *GetString(unsigned char Index) + { + char *Str = (char *)((unsigned long)this + this->Header.Length); + Index--; + if (Index == 0 || Index > 10) + return Str; + for (unsigned char i = 0; i < Index; i++) + Str = SMBIOSNextString(Str); + return Str; + } + }; - struct SMBIOSMemoryArray - { - SMBIOSHeader Header; - unsigned char Location; - unsigned char Use; - unsigned char MemoryErrorCorrection; - unsigned int MaximumCapacity; - unsigned short MemoryErrorInformationHandle; - unsigned short NumberOfMemoryDevices; + struct SMBIOSMemoryArray + { + SMBIOSHeader Header; + unsigned char Location; + unsigned char Use; + unsigned char MemoryErrorCorrection; + unsigned int MaximumCapacity; + unsigned short MemoryErrorInformationHandle; + unsigned short NumberOfMemoryDevices; - const char *GetString(unsigned char Index) - { - char *Str = (char *)((unsigned long)this + this->Header.Length); - Index--; - if (Index == 0 || Index > 10) - return Str; - for (unsigned char i = 0; i < Index; i++) - Str = SMBIOSNextString(Str); - return Str; - } - }; + const char *GetString(unsigned char Index) + { + char *Str = (char *)((unsigned long)this + this->Header.Length); + Index--; + if (Index == 0 || Index > 10) + return Str; + for (unsigned char i = 0; i < Index; i++) + Str = SMBIOSNextString(Str); + return Str; + } + }; - bool CheckSMBIOS(); - SMBIOSEntryPoint *GetSMBIOSEntryPoint(); - void *GetSMBIOSHeader(SMBIOSType Type); - SMBIOSBIOSInformation *GetBIOSInformation(); - SMBIOSSystemInformation *GetSystemInformation(); - SMBIOSBaseBoardInformation *GetBaseBoardInformation(); - SMBIOSProcessorInformation *GetProcessorInformation(); - SMBIOSMemoryArray *GetMemoryArray(); - SMBIOSMemoryDevice *GetMemoryDevice(); - SMBIOSMemoryArrayMappedAddress *GetMemoryArrayMappedAddress(); - SMBIOSMemoryDeviceMappedAddress *GetMemoryDeviceMappedAddress(); + bool CheckSMBIOS(); + SMBIOSEntryPoint *GetSMBIOSEntryPoint(); + void *GetSMBIOSHeader(SMBIOSType Type); + SMBIOSBIOSInformation *GetBIOSInformation(); + SMBIOSSystemInformation *GetSystemInformation(); + SMBIOSBaseBoardInformation *GetBaseBoardInformation(); + SMBIOSProcessorInformation *GetProcessorInformation(); + SMBIOSMemoryArray *GetMemoryArray(); + SMBIOSMemoryDevice *GetMemoryDevice(); + SMBIOSMemoryArrayMappedAddress *GetMemoryArrayMappedAddress(); + SMBIOSMemoryDeviceMappedAddress *GetMemoryDeviceMappedAddress(); } #endif // !__FENNIX_KERNEL_SMBIOS_H__ diff --git a/core/stack_check.cpp b/core/stack_check.cpp index f3fce77..a58bed7 100644 --- a/core/stack_check.cpp +++ b/core/stack_check.cpp @@ -25,82 +25,82 @@ EXTERNC __weak __no_stack_protector uintptr_t __stack_chk_guard_init(void) { - int MaxRetries = 0; + int MaxRetries = 0; #if UINTPTR_MAX == UINT32_MAX - uint32_t num; + uint32_t num; Retry: - num = Random::rand32(); - if (num < 0x1000 && MaxRetries++ < 10) - goto Retry; - return num; + num = Random::rand32(); + if (num < 0x1000 && MaxRetries++ < 10) + goto Retry; + return num; #else - uint64_t num; + uint64_t num; Retry: - num = Random::rand64(); - if (num < 0x100000 && MaxRetries++ < 10) - goto Retry; - return num; + num = Random::rand64(); + if (num < 0x100000 && MaxRetries++ < 10) + goto Retry; + return num; #endif } EXTERNC __constructor __no_stack_protector void __guard_setup(void) { - debug("__guard_setup"); - if (__stack_chk_guard == 0) - __stack_chk_guard = __stack_chk_guard_init(); - debug("Stack guard value: %ld", __stack_chk_guard); + debug("__guard_setup"); + if (__stack_chk_guard == 0) + __stack_chk_guard = __stack_chk_guard_init(); + debug("Stack guard value: %ld", __stack_chk_guard); } EXTERNC __weak __noreturn __no_stack_protector void __stack_chk_fail(void) { - TaskingPanic(); - for (short i = 0; i < 10; i++) - error("Stack smashing detected!"); - debug("Current stack check guard value: %#lx", __stack_chk_guard); - KPrint("\eFF0000Stack smashing detected!"); + TaskingPanic(); + for (short i = 0; i < 10; i++) + error("Stack smashing detected!"); + debug("Current stack check guard value: %#lx", __stack_chk_guard); + KPrint("\eFF0000Stack smashing detected!"); - void *Stack = nullptr; + void *Stack = nullptr; #if defined(a86) #if defined(a64) - asmv("movq %%rsp, %0" - : "=r"(Stack)); + asmv("movq %%rsp, %0" + : "=r"(Stack)); #elif defined(a32) - asmv("movl %%esp, %0" - : "=r"(Stack)); + asmv("movl %%esp, %0" + : "=r"(Stack)); #endif #elif defined(aa64) - asmv("mov %%sp, %0" - : "=r"(Stack)); + asmv("mov %%sp, %0" + : "=r"(Stack)); #endif - error("Stack address: %#lx", Stack); + error("Stack address: %#lx", Stack); - if (DebuggerIsAttached) + if (DebuggerIsAttached) #ifdef a86 - asmv("int $0x3"); + asmv("int $0x3"); #elif defined(aa64) - asmv("brk #0"); + asmv("brk #0"); #endif - CPU::Stop(); + CPU::Stop(); } // https://github.com/gcc-mirror/gcc/blob/master/libssp/ssp.c EXTERNC __weak __noreturn __no_stack_protector void __chk_fail(void) { - TaskingPanic(); - for (short i = 0; i < 10; i++) - error("Buffer overflow detected!"); - KPrint("\eFF0000Buffer overflow detected!"); + TaskingPanic(); + for (short i = 0; i < 10; i++) + error("Buffer overflow detected!"); + KPrint("\eFF0000Buffer overflow detected!"); #if defined(a86) - while (1) - asmv("cli; hlt"); + while (1) + asmv("cli; hlt"); #elif defined(aa64) - asmv("wfe"); + asmv("wfe"); #endif } diff --git a/core/symbols.cpp b/core/symbols.cpp index fa87d4b..fc4b348 100644 --- a/core/symbols.cpp +++ b/core/symbols.cpp @@ -25,20 +25,69 @@ namespace SymbolResolver { - const NIF char *Symbols::GetSymbolFromAddress(uintptr_t Address) + const NIF char *Symbols::GetSymbol(uintptr_t Address) { SymbolTable Result{}; - foreach (auto tbl in this->SymTable) + + if (this->SymbolTableExists == false) { - if (tbl.Address <= Address && - tbl.Address > Result.Address) - Result = tbl; + debug("Symbol table does not exist"); + if (this->SymTable.size() > 0) + { + debug("SymbolTableExists is false but SymTable.size() is %d", + this->SymTable.size()); + } + return Result.FunctionName; } - // debug("Address: %#lx, Function: %s", - // Address, Result.FunctionName); + + std::vector rSymTable = this->SymTable; + rSymTable.reverse(); + + foreach (auto st in rSymTable) + { + if (unlikely(st.Address <= Address && + st.Address > Result.Address)) + { + Result = st; + break; + } + } + + // debug("Symbol %#lx: %s", Result.Address, Result.FunctionName); return Result.FunctionName; } + uintptr_t Symbols::GetSymbol(const char *Name) + { + SymbolTable Result{}; + + if (this->SymbolTableExists == false) + { + debug("Symbol table does not exist"); + if (this->SymTable.size() > 0) + { + debug("SymbolTableExists is false but SymTable.size() is %d", + this->SymTable.size()); + } + return Result.Address; + } + + std::vector rSymTable = this->SymTable; + rSymTable.reverse(); + + foreach (auto st in rSymTable) + { + if (unlikely(strcmp(st.FunctionName, Name) == 0)) + { + Result = st; + break; + } + } + + // debug("Symbol %#lx: %s", Result.Address, Result.FunctionName); + return Result.Address; + } + void Symbols::AddSymbol(uintptr_t Address, const char *Name) { SymbolTable tbl{}; @@ -121,11 +170,11 @@ namespace SymbolResolver TotalEntries, TO_KiB(TotalEntries * sizeof(SymbolTable))); Elf_Sym *sym; const char *name; - Memory::Virtual vma = Memory::Virtual(); + Memory::Virtual vmm; for (size_t i = 0, g = TotalEntries; i < g; i++) { sym = &Symbols[i]; - if (!vma.Check(sym)) + if (!vmm.Check(sym)) { error("Symbol %d has invalid address %#lx!", i, sym); @@ -137,7 +186,7 @@ namespace SymbolResolver } name = (const char *)&StringAddress[Symbols[i].st_name]; - if (!vma.Check((void *)name)) + if (!vmm.Check((void *)name)) { error("String %d has invalid address %#lx!", i, name); @@ -168,7 +217,8 @@ namespace SymbolResolver { /* FIXME: Get only the required headers instead of the whole file */ - if (ImageAddress == 0 || Memory::Virtual().Check((void *)ImageAddress) == false) + if (ImageAddress == 0 || + Memory::Virtual().Check((void *)ImageAddress) == false) { error("Invalid image address %#lx", ImageAddress); return; @@ -261,17 +311,27 @@ namespace SymbolResolver // this->SymTable[i].FunctionName); } } + + if (this->SymbolTableExists) + { + debug("Symbol table exists, %d entries (%ld KiB)", + this->SymTable.size(), TO_KiB(this->SymTable.size() * sizeof(SymbolTable))); + } } Symbols::Symbols(uintptr_t ImageAddress) { + debug("+ %#lx", this); this->Image = (void *)ImageAddress; this->AppendSymbols(ImageAddress); } Symbols::~Symbols() { - for (auto tbl : this->SymTable) + debug("- %#lx", this); + debug("Freeing %d symbols", + this->SymTable.size()); + foreach (auto tbl in this->SymTable) delete[] tbl.FunctionName; } } diff --git a/core/time/hpet.cpp b/core/time/hpet.cpp index 5079fc8..44bb699 100644 --- a/core/time/hpet.cpp +++ b/core/time/hpet.cpp @@ -29,13 +29,13 @@ namespace Time bool HighPrecisionEventTimer::Sleep(size_t Duration, Units Unit) { #if defined(a64) - uint64_t Target = mminq(&((HPET *)hpet)->MainCounterValue) + (Duration * ConvertUnit(Unit)) / clk; - while (mminq(&((HPET *)hpet)->MainCounterValue) < Target) + uint64_t Target = mminq(&hpet->MainCounterValue) + (Duration * ConvertUnit(Unit)) / clk; + while (mminq(&hpet->MainCounterValue) < Target) CPU::Pause(); return true; #elif defined(a32) - uint64_t Target = mminl(&((HPET *)hpet)->MainCounterValue) + (Duration * ConvertUnit(Unit)) / clk; - while (mminl(&((HPET *)hpet)->MainCounterValue) < Target) + uint64_t Target = mminl(&hpet->MainCounterValue) + (Duration * ConvertUnit(Unit)) / clk; + while (mminl(&hpet->MainCounterValue) < Target) CPU::Pause(); return true; #endif @@ -45,18 +45,18 @@ namespace Time uint64_t HighPrecisionEventTimer::GetCounter() { #if defined(a64) - return mminq(&((HPET *)hpet)->MainCounterValue); + return mminq(&hpet->MainCounterValue); #elif defined(a32) - return mminl(&((HPET *)hpet)->MainCounterValue); + return mminl(&hpet->MainCounterValue); #endif } uint64_t HighPrecisionEventTimer::CalculateTarget(uint64_t Target, Units Unit) { #if defined(a64) - return mminq(&((HPET *)hpet)->MainCounterValue) + (Target * ConvertUnit(Unit)) / clk; + return mminq(&hpet->MainCounterValue) + (Target * ConvertUnit(Unit)) / clk; #elif defined(a32) - return mminl(&((HPET *)hpet)->MainCounterValue) + (Target * ConvertUnit(Unit)) / clk; + return mminl(&hpet->MainCounterValue) + (Target * ConvertUnit(Unit)) / clk; #endif } @@ -66,7 +66,9 @@ namespace Time uint64_t Subtraction = this->GetCounter() - this->ClassCreationTime; if (Subtraction <= 0 || this->clk <= 0) return 0; - return uint64_t(Subtraction / (this->clk / ConvertUnit(Units::Nanoseconds))); + + Subtraction *= ConvertUnit(Units::Nanoseconds); + return uint64_t(Subtraction / this->clk); #endif } @@ -74,13 +76,16 @@ namespace Time { #if defined(a86) ACPI::ACPI::HPETHeader *HPET_HDR = (ACPI::ACPI::HPETHeader *)hpet; - Memory::Virtual().Map((void *)HPET_HDR->Address.Address, - (void *)HPET_HDR->Address.Address, - Memory::PTFlag::RW | Memory::PTFlag::PCD); + Memory::Virtual vmm; + vmm.Map((void *)HPET_HDR->Address.Address, + (void *)HPET_HDR->Address.Address, + Memory::PTFlag::RW | Memory::PTFlag::PCD); this->hpet = (HPET *)HPET_HDR->Address.Address; - trace("%s timer is at address %016p", HPET_HDR->Header.OEMID, (void *)HPET_HDR->Address.Address); + trace("%s timer is at address %016p", + HPET_HDR->Header.OEMID, + (void *)HPET_HDR->Address.Address); clk = s_cst(uint32_t, (uint64_t)this->hpet->GeneralCapabilities >> 32); - debug("HPET clock is %u Hz", clk); + KPrint("HPET clock is %u Hz", clk); #ifdef a64 mmoutq(&this->hpet->GeneralConfiguration, 0); mmoutq(&this->hpet->MainCounterValue, 0); diff --git a/core/time/time.cpp b/core/time/time.cpp index 1b7dc02..bdb43c0 100644 --- a/core/time/time.cpp +++ b/core/time/time.cpp @@ -1,18 +1,18 @@ /* - This file is part of Fennix Kernel. + 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 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. + 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 . + You should have received a copy of the GNU General Public License + along with Fennix Kernel. If not, see . */ #include @@ -21,91 +21,91 @@ namespace Time { - Clock ReadClock() - { - Clock tm; + Clock ReadClock() + { + Clock tm; #if defined(a86) - uint32_t t = 0; - outb(0x70, 0x00); - t = inb(0x71); - tm.Second = ((t & 0x0F) + ((t >> 4) * 10)); - outb(0x70, 0x02); - t = inb(0x71); - tm.Minute = ((t & 0x0F) + ((t >> 4) * 10)); - outb(0x70, 0x04); - t = inb(0x71); - tm.Hour = ((t & 0x0F) + ((t >> 4) * 10)); - outb(0x70, 0x07); - t = inb(0x71); - tm.Day = ((t & 0x0F) + ((t >> 4) * 10)); - outb(0x70, 0x08); - t = inb(0x71); - tm.Month = ((t & 0x0F) + ((t >> 4) * 10)); - outb(0x70, 0x09); - t = inb(0x71); - tm.Year = ((t & 0x0F) + ((t >> 4) * 10)); - tm.Counter = 0; + uint32_t t = 0; + outb(0x70, 0x00); + t = inb(0x71); + tm.Second = ((t & 0x0F) + ((t >> 4) * 10)); + outb(0x70, 0x02); + t = inb(0x71); + tm.Minute = ((t & 0x0F) + ((t >> 4) * 10)); + outb(0x70, 0x04); + t = inb(0x71); + tm.Hour = ((t & 0x0F) + ((t >> 4) * 10)); + outb(0x70, 0x07); + t = inb(0x71); + tm.Day = ((t & 0x0F) + ((t >> 4) * 10)); + outb(0x70, 0x08); + t = inb(0x71); + tm.Month = ((t & 0x0F) + ((t >> 4) * 10)); + outb(0x70, 0x09); + t = inb(0x71); + tm.Year = ((t & 0x0F) + ((t >> 4) * 10)); + tm.Counter = 0; #elif defined(aa64) - tm.Year = 0; - tm.Month = 0; - tm.Day = 0; - tm.Hour = 0; - tm.Minute = 0; - tm.Second = 0; - tm.Counter = 0; + tm.Year = 0; + tm.Month = 0; + tm.Day = 0; + tm.Hour = 0; + tm.Minute = 0; + tm.Second = 0; + tm.Counter = 0; #endif - return tm; - } + return tm; + } - Clock ConvertFromUnix(int Timestamp) - { - Clock result; + Clock ConvertFromUnix(int Timestamp) + { + Clock result; - uint64_t Seconds = Timestamp; - uint64_t Minutes = Seconds / 60; - uint64_t Hours = Minutes / 60; - uint64_t Days = Hours / 24; + uint64_t Seconds = Timestamp; + uint64_t Minutes = Seconds / 60; + uint64_t Hours = Minutes / 60; + uint64_t Days = Hours / 24; - result.Year = 1970; - while (Days >= 365) - { - if (result.Year % 4 == 0 && - (result.Year % 100 != 0 || - result.Year % 400 == 0)) - { - if (Days >= 366) - { - Days -= 366; - result.Year++; - } - else - break; - } - else - { - Days -= 365; - result.Year++; - } - } + result.Year = 1970; + while (Days >= 365) + { + if (result.Year % 4 == 0 && + (result.Year % 100 != 0 || + result.Year % 400 == 0)) + { + if (Days >= 366) + { + Days -= 366; + result.Year++; + } + else + break; + } + else + { + Days -= 365; + result.Year++; + } + } - int DaysInMonth[] = {31, - result.Year % 4 == 0 - ? 29 - : 28, - 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; - for (result.Month = 0; result.Month < 12; result.Month++) - { - if (Days < s_cst(uint64_t, (DaysInMonth[result.Month]))) - break; - Days -= DaysInMonth[result.Month]; - } - result.Month++; + int DaysInMonth[] = {31, + result.Year % 4 == 0 + ? 29 + : 28, + 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; + for (result.Month = 0; result.Month < 12; result.Month++) + { + if (Days < s_cst(uint64_t, (DaysInMonth[result.Month]))) + break; + Days -= DaysInMonth[result.Month]; + } + result.Month++; - result.Day = s_cst(int, (Days) + 1); - result.Hour = s_cst(int, (Hours % 24)); - result.Minute = s_cst(int, (Minutes % 60)); - result.Second = s_cst(int, (Seconds % 60)); - result.Counter = s_cst(uint64_t, (Timestamp)); - return result; - } + result.Day = s_cst(int, (Days) + 1); + result.Hour = s_cst(int, (Hours % 24)); + result.Minute = s_cst(int, (Minutes % 60)); + result.Second = s_cst(int, (Seconds % 60)); + result.Counter = s_cst(uint64_t, (Timestamp)); + return result; + } } diff --git a/core/time/tsc.cpp b/core/time/tsc.cpp index cf8ae06..4accaf1 100644 --- a/core/time/tsc.cpp +++ b/core/time/tsc.cpp @@ -60,7 +60,7 @@ namespace Time TimeStampCounter::TimeStampCounter() { #if defined(a86) - fixme(""); // FIXME: This is not a good way to measure the clock speed + stub; // FIXME: This is not a good way to measure the clock speed uint64_t Start = CPU::Counter(); TimeManager->Sleep(1, Units::Milliseconds); uint64_t End = CPU::Counter(); diff --git a/core/ubsan.c b/core/ubsan.c index 34f6f35..c7e63a8 100644 --- a/core/ubsan.c +++ b/core/ubsan.c @@ -51,309 +51,309 @@ __ubsan_handle_cfi_check_fail void __asan_report_load1(void *unknown) { - ubsan("load1"); - UNUSED(unknown); + ubsan("load1"); + UNUSED(unknown); } void __asan_report_load2(void *unknown) { - ubsan("load2"); - UNUSED(unknown); + ubsan("load2"); + UNUSED(unknown); } void __asan_report_load4(void *unknown) { - ubsan("load4"); - UNUSED(unknown); + ubsan("load4"); + UNUSED(unknown); } void __asan_report_load8(void *unknown) { - ubsan("load8"); - UNUSED(unknown); + ubsan("load8"); + UNUSED(unknown); } void __asan_report_load16(void *unknown) { - ubsan("load16"); - UNUSED(unknown); + ubsan("load16"); + UNUSED(unknown); } void __asan_report_load_n(void *unknown, uintptr_t size) { - ubsan("loadn"); - UNUSED(unknown); - UNUSED(size); + ubsan("loadn"); + UNUSED(unknown); + UNUSED(size); } void __asan_report_store1(void *unknown) { - ubsan("store1"); - UNUSED(unknown); + ubsan("store1"); + UNUSED(unknown); } void __asan_report_store2(void *unknown) { - ubsan("store2"); - UNUSED(unknown); + ubsan("store2"); + UNUSED(unknown); } void __asan_report_store4(void *unknown) { - ubsan("store4"); - UNUSED(unknown); + ubsan("store4"); + UNUSED(unknown); } void __asan_report_store8(void *unknown) { - ubsan("store8"); - UNUSED(unknown); + ubsan("store8"); + UNUSED(unknown); } void __asan_report_store16(void *unknown) { - ubsan("store16"); - UNUSED(unknown); + ubsan("store16"); + UNUSED(unknown); } void __asan_report_store_n(void *unknown, uintptr_t size) { - ubsan("storen"); - UNUSED(unknown); - UNUSED(size); + ubsan("storen"); + UNUSED(unknown); + UNUSED(size); } void __asan_report_load1_noabort(void *unknown) { - ubsan("load1"); - UNUSED(unknown); + ubsan("load1"); + UNUSED(unknown); } void __asan_report_load2_noabort(void *unknown) { - ubsan("load2"); - UNUSED(unknown); + ubsan("load2"); + UNUSED(unknown); } void __asan_report_load4_noabort(void *unknown) { - ubsan("load4"); - UNUSED(unknown); + ubsan("load4"); + UNUSED(unknown); } void __asan_report_load8_noabort(void *unknown) { - ubsan("load8"); - UNUSED(unknown); + ubsan("load8"); + UNUSED(unknown); } void __asan_report_load16_noabort(void *unknown) { - ubsan("load16"); - UNUSED(unknown); + ubsan("load16"); + UNUSED(unknown); } void __asan_report_load_n_noabort(void *unknown, uintptr_t size) { - ubsan("loadn"); - UNUSED(unknown); - UNUSED(size); + ubsan("loadn"); + UNUSED(unknown); + UNUSED(size); } void __asan_report_store1_noabort(void *unknown) { - ubsan("store1"); - UNUSED(unknown); + ubsan("store1"); + UNUSED(unknown); } void __asan_report_store2_noabort(void *unknown) { - ubsan("store2"); - UNUSED(unknown); + ubsan("store2"); + UNUSED(unknown); } void __asan_report_store4_noabort(void *unknown) { - ubsan("store4"); - UNUSED(unknown); + ubsan("store4"); + UNUSED(unknown); } void __asan_report_store8_noabort(void *unknown) { - ubsan("store8"); - UNUSED(unknown); + ubsan("store8"); + UNUSED(unknown); } void __asan_report_store16_noabort(void *unknown) { - ubsan("store16"); - UNUSED(unknown); + ubsan("store16"); + UNUSED(unknown); } void __asan_report_store_n_noabort(void *unknown, uintptr_t size) { - ubsan("storen"); - UNUSED(unknown); - UNUSED(size); + ubsan("storen"); + UNUSED(unknown); + UNUSED(size); } void __asan_stack_malloc_0(uintptr_t size) { - ubsan("stack malloc 0"); - UNUSED(size); + ubsan("stack malloc 0"); + UNUSED(size); } void __asan_stack_malloc_1(uintptr_t size) { - ubsan("stack malloc 1"); - UNUSED(size); + ubsan("stack malloc 1"); + UNUSED(size); } void __asan_stack_malloc_2(uintptr_t size) { - ubsan("stack malloc 2"); - UNUSED(size); + ubsan("stack malloc 2"); + UNUSED(size); } void __asan_stack_malloc_3(uintptr_t size) { - ubsan("stack malloc 3"); - UNUSED(size); + ubsan("stack malloc 3"); + UNUSED(size); } void __asan_stack_malloc_4(uintptr_t size) { - ubsan("stack malloc 4"); - UNUSED(size); + ubsan("stack malloc 4"); + UNUSED(size); } void __asan_stack_malloc_5(uintptr_t size) { - ubsan("stack malloc 5"); - UNUSED(size); + ubsan("stack malloc 5"); + UNUSED(size); } void __asan_stack_malloc_6(uintptr_t size) { - ubsan("stack malloc 6"); - UNUSED(size); + ubsan("stack malloc 6"); + UNUSED(size); } void __asan_stack_malloc_7(uintptr_t size) { - ubsan("stack malloc 7"); - UNUSED(size); + ubsan("stack malloc 7"); + UNUSED(size); } void __asan_stack_malloc_8(uintptr_t size) { - ubsan("stack malloc 8"); - UNUSED(size); + ubsan("stack malloc 8"); + UNUSED(size); } void __asan_stack_malloc_9(uintptr_t size) { - ubsan("stack malloc 9"); - UNUSED(size); + ubsan("stack malloc 9"); + UNUSED(size); } void __asan_stack_free_0(void *ptr, uintptr_t size) { - ubsan("stack free 0"); - UNUSED(ptr); - UNUSED(size); + ubsan("stack free 0"); + UNUSED(ptr); + UNUSED(size); } void __asan_stack_free_1(void *ptr, uintptr_t size) { - ubsan("stack free 1"); - UNUSED(ptr); - UNUSED(size); + ubsan("stack free 1"); + UNUSED(ptr); + UNUSED(size); } void __asan_stack_free_2(void *ptr, uintptr_t size) { - ubsan("stack free 2"); - UNUSED(ptr); - UNUSED(size); + ubsan("stack free 2"); + UNUSED(ptr); + UNUSED(size); } void __asan_stack_free_3(void *ptr, uintptr_t size) { - ubsan("stack free 3"); - UNUSED(ptr); - UNUSED(size); + ubsan("stack free 3"); + UNUSED(ptr); + UNUSED(size); } void __asan_stack_free_4(void *ptr, uintptr_t size) { - ubsan("stack free 4"); - UNUSED(ptr); - UNUSED(size); + ubsan("stack free 4"); + UNUSED(ptr); + UNUSED(size); } void __asan_stack_free_5(void *ptr, uintptr_t size) { - ubsan("stack free 5"); - UNUSED(ptr); - UNUSED(size); + ubsan("stack free 5"); + UNUSED(ptr); + UNUSED(size); } void __asan_stack_free_6(void *ptr, uintptr_t size) { - ubsan("stack free 6"); - UNUSED(ptr); - UNUSED(size); + ubsan("stack free 6"); + UNUSED(ptr); + UNUSED(size); } void __asan_stack_free_7(void *ptr, uintptr_t size) { - ubsan("stack free 7"); - UNUSED(ptr); - UNUSED(size); + ubsan("stack free 7"); + UNUSED(ptr); + UNUSED(size); } void __asan_stack_free_8(void *ptr, uintptr_t size) { - ubsan("stack free 8"); - UNUSED(ptr); - UNUSED(size); + ubsan("stack free 8"); + UNUSED(ptr); + UNUSED(size); } void __asan_stack_free_9(void *ptr, uintptr_t size) { - ubsan("stack free 9"); - UNUSED(ptr); - UNUSED(size); + ubsan("stack free 9"); + UNUSED(ptr); + UNUSED(size); } void __asan_poison_stack_memory(void *addr, uintptr_t size) { - ubsan("poison stack memory"); - UNUSED(addr); - UNUSED(size); + ubsan("poison stack memory"); + UNUSED(addr); + UNUSED(size); } void __asan_unpoison_stack_memory(void *addr, uintptr_t size) { - ubsan("unpoison stack memory"); - UNUSED(addr); - UNUSED(size); + ubsan("unpoison stack memory"); + UNUSED(addr); + UNUSED(size); } void __asan_before_dynamic_init(const char *module_name) { - ubsan("before dynamic init"); - UNUSED(module_name); + ubsan("before dynamic init"); + UNUSED(module_name); } void __asan_after_dynamic_init(void) { ubsan("after dynamic init"); } void __asan_register_globals(void *unknown, size_t size) { - ubsan("register_globals"); - UNUSED(unknown); - UNUSED(size); + ubsan("register_globals"); + UNUSED(unknown); + UNUSED(size); } void __asan_unregister_globals(void) { ubsan("unregister_globals"); } @@ -364,155 +364,155 @@ void __asan_option_detect_stack_use_after_return(void) { ubsan("stack use after __noreturn void __asan_handle_no_return(void) { - ubsan("no_return"); - while (1) - ; + ubsan("no_return"); + while (1) + ; } #define is_aligned(value, alignment) !(value & (alignment - 1)) const char *Type_Check_Kinds[] = { - "Load of", - "Store to", - "Reference binding to", - "Member access within", - "Member call on", - "Constructor call on", - "Downcast of", - "Downcast of", - "Upcast of", - "Cast to virtual base of", + "Load of", + "Store to", + "Reference binding to", + "Member access within", + "Member call on", + "Constructor call on", + "Downcast of", + "Downcast of", + "Upcast of", + "Cast to virtual base of", }; void __ubsan_handle_type_mismatch_v1(struct type_mismatch_v1_data *type_mismatch, uintptr_t pointer) { - struct source_location *location = &type_mismatch->location; - if (pointer == 0) - { - ubsan("\t\tIn File: %s:%i:%i", location->file, location->line, location->column); - ubsan("Null pointer access."); - } - else if (type_mismatch->alignment != 0 && is_aligned(pointer, type_mismatch->alignment)) - { - ubsan("\t\tIn File: %s:%i:%i", location->file, location->line, location->column); - ubsan("Unaligned memory access %#lx.", pointer); - } - else - { - ubsan("\t\tIn File: %s:%i:%i", location->file, location->line, location->column); - ubsan("%s address %#lx with insufficient space for object of type %s", - Type_Check_Kinds[type_mismatch->type_check_kind], - (void *)pointer, type_mismatch->type->name); - } + struct source_location *location = &type_mismatch->location; + if (pointer == 0) + { + ubsan("\t\tIn File: %s:%i:%i", location->file, location->line, location->column); + ubsan("Null pointer access."); + } + else if (type_mismatch->alignment != 0 && is_aligned(pointer, type_mismatch->alignment)) + { + ubsan("\t\tIn File: %s:%i:%i", location->file, location->line, location->column); + ubsan("Unaligned memory access %#lx.", pointer); + } + else + { + ubsan("\t\tIn File: %s:%i:%i", location->file, location->line, location->column); + ubsan("%s address %#lx with insufficient space for object of type %s", + Type_Check_Kinds[type_mismatch->type_check_kind], + (void *)pointer, type_mismatch->type->name); + } } void __ubsan_handle_add_overflow(struct overflow_data *data) { - ubsan("\t\tIn File: %s:%i:%i", data->location.file, data->location.line, data->location.column); - ubsan("Addition overflow."); + ubsan("\t\tIn File: %s:%i:%i", data->location.file, data->location.line, data->location.column); + ubsan("Addition overflow."); } void __ubsan_handle_sub_overflow(struct overflow_data *data) { - ubsan("\t\tIn File: %s:%i:%i", data->location.file, data->location.line, data->location.column); - ubsan("Subtraction overflow."); + ubsan("\t\tIn File: %s:%i:%i", data->location.file, data->location.line, data->location.column); + ubsan("Subtraction overflow."); } void __ubsan_handle_mul_overflow(struct overflow_data *data) { - ubsan("\t\tIn File: %s:%i:%i", data->location.file, data->location.line, data->location.column); - ubsan("Multiplication overflow."); + ubsan("\t\tIn File: %s:%i:%i", data->location.file, data->location.line, data->location.column); + ubsan("Multiplication overflow."); } void __ubsan_handle_divrem_overflow(struct overflow_data *data) { - ubsan("\t\tIn File: %s:%i:%i", data->location.file, data->location.line, data->location.column); - ubsan("Division overflow."); + ubsan("\t\tIn File: %s:%i:%i", data->location.file, data->location.line, data->location.column); + ubsan("Division overflow."); } void __ubsan_handle_negate_overflow(struct overflow_data *data) { - ubsan("\t\tIn File: %s:%i:%i", data->location.file, data->location.line, data->location.column); - ubsan("Negation overflow."); + ubsan("\t\tIn File: %s:%i:%i", data->location.file, data->location.line, data->location.column); + ubsan("Negation overflow."); } void __ubsan_handle_pointer_overflow(struct overflow_data *data) { - ubsan("\t\tIn File: %s:%i:%i", data->location.file, data->location.line, data->location.column); - ubsan("Pointer overflow."); + ubsan("\t\tIn File: %s:%i:%i", data->location.file, data->location.line, data->location.column); + ubsan("Pointer overflow."); } void __ubsan_handle_shift_out_of_bounds(struct shift_out_of_bounds_data *data) { - ubsan("\t\tIn File: %s:%i:%i", data->location.file, data->location.line, data->location.column); - ubsan("Shift out of bounds."); + ubsan("\t\tIn File: %s:%i:%i", data->location.file, data->location.line, data->location.column); + ubsan("Shift out of bounds."); } void __ubsan_handle_load_invalid_value(struct invalid_value_data *data) { - ubsan("\t\tIn File: %s:%i:%i", data->location.file, data->location.line, data->location.column); - ubsan("Invalid load value."); + ubsan("\t\tIn File: %s:%i:%i", data->location.file, data->location.line, data->location.column); + ubsan("Invalid load value."); } void __ubsan_handle_out_of_bounds(struct array_out_of_bounds_data *data) { - ubsan("\t\tIn File: %s:%i:%i", data->location.file, data->location.line, data->location.column); - ubsan("Array out of bounds."); + ubsan("\t\tIn File: %s:%i:%i", data->location.file, data->location.line, data->location.column); + ubsan("Array out of bounds."); } void __ubsan_handle_vla_bound_not_positive(struct negative_vla_data *data) { - ubsan("\t\tIn File: %s:%i:%i", data->location.file, data->location.line, data->location.column); - ubsan("Variable-length argument is negative."); + ubsan("\t\tIn File: %s:%i:%i", data->location.file, data->location.line, data->location.column); + ubsan("Variable-length argument is negative."); } void __ubsan_handle_nonnull_return(struct nonnull_return_data *data) { - ubsan("\t\tIn File: %s:%i:%i", data->location.file, data->location.line, data->location.column); - ubsan("Non-null return is null."); + ubsan("\t\tIn File: %s:%i:%i", data->location.file, data->location.line, data->location.column); + ubsan("Non-null return is null."); } void __ubsan_handle_nonnull_return_v1(struct nonnull_return_data *data) { - ubsan("\t\tIn File: %s:%i:%i", data->location.file, data->location.line, data->location.column); - ubsan("Non-null return is null."); + ubsan("\t\tIn File: %s:%i:%i", data->location.file, data->location.line, data->location.column); + ubsan("Non-null return is null."); } void __ubsan_handle_nonnull_arg(struct nonnull_arg_data *data) { - ubsan("\t\tIn File: %s:%i:%i", data->location.file, data->location.line, data->location.column); - ubsan("Non-null argument is null."); + ubsan("\t\tIn File: %s:%i:%i", data->location.file, data->location.line, data->location.column); + ubsan("Non-null argument is null."); } void __ubsan_handle_builtin_unreachable(struct unreachable_data *data) { - ubsan("\t\tIn File: %s:%i:%i", data->location.file, data->location.line, data->location.column); - ubsan("Unreachable code reached."); + ubsan("\t\tIn File: %s:%i:%i", data->location.file, data->location.line, data->location.column); + ubsan("Unreachable code reached."); } void __ubsan_handle_invalid_builtin(struct invalid_builtin_data *data) { - ubsan("\t\tIn File: %s:%i:%i", data->location.file, data->location.line, data->location.column); - ubsan("Invalid builtin."); + ubsan("\t\tIn File: %s:%i:%i", data->location.file, data->location.line, data->location.column); + ubsan("Invalid builtin."); } void __ubsan_handle_missing_return(struct unreachable_data *data) { - ubsan("\t\tIn File: %s:%i:%i", data->location.file, data->location.line, data->location.column); - ubsan("Missing return."); + ubsan("\t\tIn File: %s:%i:%i", data->location.file, data->location.line, data->location.column); + ubsan("Missing return."); } void __ubsan_vptr_type_cache(uintptr_t *cache, uintptr_t ptr) { - ubsan("Vptr type cache."); - *cache = ptr; + ubsan("Vptr type cache."); + *cache = ptr; } void __ubsan_handle_dynamic_type_cache_miss(struct dynamic_type_cache_miss_data *data, uintptr_t ptr) { - ubsan("\t\tIn File: %s:%i:%i", data->location.file, data->location.line, data->location.column); - ubsan("Dynamic type cache miss."); - UNUSED(ptr); + ubsan("\t\tIn File: %s:%i:%i", data->location.file, data->location.line, data->location.column); + ubsan("Dynamic type cache miss."); + UNUSED(ptr); } #endif diff --git a/core/ubsan.h b/core/ubsan.h index 00df0ee..17fcaac 100644 --- a/core/ubsan.h +++ b/core/ubsan.h @@ -22,90 +22,90 @@ struct source_location { - const char *file; - uint32_t line; - uint32_t column; + const char *file; + uint32_t line; + uint32_t column; }; struct type_descriptor { - uint16_t kind; - uint16_t info; - char name[]; + uint16_t kind; + uint16_t info; + char name[]; }; struct type_mismatch_v1_data { - struct source_location location; - struct type_descriptor *type; - uint8_t alignment; - uint8_t type_check_kind; + struct source_location location; + struct type_descriptor *type; + uint8_t alignment; + uint8_t type_check_kind; }; struct out_of_bounds_info { - struct source_location location; - struct type_descriptor left_type; - struct type_descriptor right_type; + struct source_location location; + struct type_descriptor left_type; + struct type_descriptor right_type; }; struct overflow_data { - struct source_location location; - struct type_descriptor *type; + struct source_location location; + struct type_descriptor *type; }; struct negative_vla_data { - struct source_location location; - struct type_descriptor *type; + struct source_location location; + struct type_descriptor *type; }; struct invalid_value_data { - struct source_location location; - struct type_descriptor *type; + struct source_location location; + struct type_descriptor *type; }; struct nonnull_return_data { - struct source_location location; + struct source_location location; }; struct nonnull_arg_data { - struct source_location location; + struct source_location location; }; struct unreachable_data { - struct source_location location; + struct source_location location; }; struct invalid_builtin_data { - struct source_location location; - uint8_t kind; + struct source_location location; + uint8_t kind; }; struct array_out_of_bounds_data { - struct source_location location; - struct type_descriptor *array_type; - struct type_descriptor *index_type; + struct source_location location; + struct type_descriptor *array_type; + struct type_descriptor *index_type; }; struct shift_out_of_bounds_data { - struct source_location location; - struct type_descriptor *left_type; - struct type_descriptor *right_type; + struct source_location location; + struct type_descriptor *left_type; + struct type_descriptor *right_type; }; struct dynamic_type_cache_miss_data { - struct source_location location; - struct type_descriptor *type; + struct source_location location; + struct type_descriptor *type; }; #endif // !__FENNIX_KERNEL_UBSAN_H__ diff --git a/core/video/font.cpp b/core/video/font.cpp index 66373f2..e2dd6bf 100644 --- a/core/video/font.cpp +++ b/core/video/font.cpp @@ -21,60 +21,60 @@ namespace Video { - Font::Font(uintptr_t *Start, uintptr_t *End, FontType Type) - { - trace("Initializing font with start %#lx and end %#lx Type: %d", Start, End, Type); - this->Info.StartAddress = Start; - this->Info.EndAddress = End; - this->Info.Type = Type; - size_t FontDataLength = End - Start; + Font::Font(uintptr_t *Start, uintptr_t *End, FontType Type) + { + trace("Initializing font with start %#lx and end %#lx Type: %d", Start, End, Type); + this->Info.StartAddress = Start; + this->Info.EndAddress = End; + this->Info.Type = Type; + size_t FontDataLength = End - Start; - if (Type == FontType::PCScreenFont2) - { - this->Info.PSF2Font = new PSF2_FONT; + if (Type == FontType::PCScreenFont2) + { + this->Info.PSF2Font = new PSF2_FONT; - PSF2_HEADER *font2 = (PSF2_HEADER *)KernelAllocator.RequestPages(TO_PAGES(FontDataLength + 1)); - memcpy((void *)font2, Start, FontDataLength); + PSF2_HEADER *font2 = (PSF2_HEADER *)KernelAllocator.RequestPages(TO_PAGES(FontDataLength + 1)); + memcpy((void *)font2, Start, FontDataLength); - Memory::Virtual().Map((void *)font2, (void *)font2, - FontDataLength, Memory::PTFlag::RW); + Memory::Virtual().Map((void *)font2, (void *)font2, + FontDataLength, Memory::PTFlag::RW); - if (font2->magic[0] != PSF2_MAGIC0 || font2->magic[1] != PSF2_MAGIC1 || - font2->magic[2] != PSF2_MAGIC2 || font2->magic[3] != PSF2_MAGIC3) - { - error("Font2 magic mismatch."); - KernelAllocator.FreePages((void *)font2, TO_PAGES(FontDataLength + 1)); - return; - } + if (font2->magic[0] != PSF2_MAGIC0 || font2->magic[1] != PSF2_MAGIC1 || + font2->magic[2] != PSF2_MAGIC2 || font2->magic[3] != PSF2_MAGIC3) + { + error("Font2 magic mismatch."); + KernelAllocator.FreePages((void *)font2, TO_PAGES(FontDataLength + 1)); + return; + } - this->Info.PSF2Font->Header = font2; - this->Info.PSF2Font->GlyphBuffer = - r_cst(void *, r_cst(uintptr_t, Start) + sizeof(PSF2_HEADER)); - this->Info.Width = font2->width; - this->Info.Height = font2->height; - } - else if (Type == FontType::PCScreenFont1) - { - this->Info.PSF1Font = new PSF1_FONT; - PSF1_HEADER *font1 = (PSF1_HEADER *)Start; - if (font1->magic[0] != PSF1_MAGIC0 || font1->magic[1] != PSF1_MAGIC1) - error("Font1 magic mismatch."); - uint32_t glyphBufferSize = font1->charsize * 256; - if (font1->mode == 1) // 512 glyph mode - glyphBufferSize = font1->charsize * 512; - void *glyphBuffer = - r_cst(void *, r_cst(uintptr_t, Start) + sizeof(PSF1_HEADER)); - this->Info.PSF1Font->Header = font1; - this->Info.PSF1Font->GlyphBuffer = glyphBuffer; - UNUSED(glyphBufferSize); // TODO: Use this in the future? + this->Info.PSF2Font->Header = font2; + this->Info.PSF2Font->GlyphBuffer = + r_cst(void *, r_cst(uintptr_t, Start) + sizeof(PSF2_HEADER)); + this->Info.Width = font2->width; + this->Info.Height = font2->height; + } + else if (Type == FontType::PCScreenFont1) + { + this->Info.PSF1Font = new PSF1_FONT; + PSF1_HEADER *font1 = (PSF1_HEADER *)Start; + if (font1->magic[0] != PSF1_MAGIC0 || font1->magic[1] != PSF1_MAGIC1) + error("Font1 magic mismatch."); + uint32_t glyphBufferSize = font1->charsize * 256; + if (font1->mode == 1) // 512 glyph mode + glyphBufferSize = font1->charsize * 512; + void *glyphBuffer = + r_cst(void *, r_cst(uintptr_t, Start) + sizeof(PSF1_HEADER)); + this->Info.PSF1Font->Header = font1; + this->Info.PSF1Font->GlyphBuffer = glyphBuffer; + UNUSED(glyphBufferSize); // TODO: Use this in the future? - // TODO: Get font size. - this->Info.Width = 16; - this->Info.Height = 8; - } - } + // TODO: Get font size. + this->Info.Width = 16; + this->Info.Height = 8; + } + } - Font::~Font() - { - } + Font::~Font() + { + } } diff --git a/driver.h b/driver.h new file mode 100644 index 0000000..b072c0c --- /dev/null +++ b/driver.h @@ -0,0 +1,326 @@ +/* + 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_API_DRIVER_FUNCTIONS_H__ +#define __FENNIX_API_DRIVER_FUNCTIONS_H__ + +#include + +typedef enum +{ + _drf_Entry, + _drf_Final, + _drf_Panic, + _drf_Probe, +} __driverRegFunc; + +typedef union +{ + struct + { + uint8_t LeftButton : 1; + uint8_t RightButton : 1; + uint8_t MiddleButton : 1; + uint8_t Button4 : 1; + uint8_t Button5 : 1; + uint8_t Button6 : 1; + uint8_t Button7 : 1; + uint8_t Button8 : 1; + }; + uint8_t Value; +} __MouseButtons; + +typedef struct +{ + /* PCIDevice */ void *Device; + /* __PCIArray */ void *Next; +} __PCIArray; + +/* ========================================== */ + +#define PCI_END 0x0000 +#define KEY_NULL 0x00 + +typedef enum +{ + KEY_1, + KEY_2, + KEY_3, + KEY_4, + KEY_5, + KEY_6, + KEY_7, + KEY_8, + KEY_9, + KEY_0, + + KEY_Q, + KEY_W, + KEY_E, + KEY_R, + KEY_T, + KEY_Y, + KEY_U, + KEY_I, + KEY_O, + KEY_P, + KEY_A, + KEY_S, + KEY_D, + KEY_F, + KEY_G, + KEY_H, + KEY_J, + KEY_K, + KEY_L, + KEY_Z, + KEY_X, + KEY_C, + KEY_V, + KEY_B, + KEY_N, + KEY_M, + + KEY_F1, + KEY_F2, + KEY_F3, + KEY_F4, + KEY_F5, + KEY_F6, + KEY_F7, + KEY_F8, + KEY_F9, + KEY_F10, + KEY_F11, + KEY_F12, + + KEYPAD_7, + KEYPAD_8, + KEYPAD_9, + KEYPAD_MINUS, + KEYPAD_4, + KEYPAD_5, + KEYPAD_6, + KEYPAD_PLUS, + KEYPAD_1, + KEYPAD_2, + KEYPAD_3, + KEYPAD_0, + KEYPAD_PERIOD, + KEYPAD_RETURN, + KEYPAD_ASTERISK, + KEYPAD_SLASH, + + KEY_LEFT_CTRL, + KEY_RIGHT_CTRL, + KEY_LEFT_SHIFT, + KEY_RIGHT_SHIFT, + KEY_LEFT_ALT, + KEY_RIGHT_ALT, + KEY_ESCAPE, + KEY_MINUS, + KEY_EQUAL, + KEY_BACKSPACE, + KEY_TAB, + KEY_LEFT_BRACKET, + KEY_RIGHT_BRACKET, + KEY_RETURN, + KEY_SEMICOLON, + KEY_APOSTROPHE, + KEY_BACK_TICK, + KEY_BACKSLASH, + KEY_COMMA, + KEY_PERIOD, + KEY_SLASH, + KEY_SPACE, + KEY_CAPS_LOCK, + KEY_NUM_LOCK, + KEY_SCROLL_LOCK, + KEY_PRINT_SCREEN, + + KEY_HOME, + KEY_UP_ARROW, + KEY_LEFT_ARROW, + KEY_RIGHT_ARROW, + KEY_DOWN_ARROW, + KEY_PAGE_UP, + KEY_PAGE_DOWN, + KEY_END, + KEY_INSERT, + KEY_DELETE, + KEY_LEFT_GUI, + KEY_RIGHT_GUI, + KEY_APPS, + + KEY_MULTIMEDIA_PREV_TRACK, + KEY_MULTIMEDIA_NEXT_TRACK, + KEY_MULTIMEDIA_MUTE, + KEY_MULTIMEDIA_CALCULATOR, + KEY_MULTIMEDIA_PLAY, + KEY_MULTIMEDIA_STOP, + KEY_MULTIMEDIA_VOL_DOWN, + KEY_MULTIMEDIA_VOL_UP, + KEY_MULTIMEDIA_WWW_HOME, + KEY_MULTIMEDIA_WWW_SEARCH, + KEY_MULTIMEDIA_WWW_FAVORITES, + KEY_MULTIMEDIA_WWW_REFRESH, + KEY_MULTIMEDIA_WWW_STOP, + KEY_MULTIMEDIA_WWW_FORWARD, + KEY_MULTIMEDIA_WWW_BACK, + KEY_MULTIMEDIA_MY_COMPUTER, + KEY_MULTIMEDIA_EMAIL, + KEY_MULTIMEDIA_MEDIA_SELECT, + + KEY_ACPI_POWER, + KEY_ACPI_SLEEP, + KEY_ACPI_WAKE, + + KEY_PRESSED = 0x80, +} KeyScanCodes; + +typedef enum +{ + ddt_Keyboard, + ddt_Mouse, + ddt_Joystick, + ddt_Gamepad, + ddt_Touchpad, + ddt_Touchscreen, + + ddt_SATA, + ddt_ATA, + ddt_NVMe, + + ddt_Audio, + + ddt_Network, +} DeviceDriverType; + +typedef enum +{ + IOCTL_AUDIO_GET_VOLUME, + IOCTL_AUDIO_SET_VOLUME, + + IOCTL_AUDIO_GET_MUTE, + IOCTL_AUDIO_SET_MUTE, + + IOCTL_AUDIO_GET_SAMPLE_RATE, + IOCTL_AUDIO_SET_SAMPLE_RATE, + + IOCTL_AUDIO_GET_CHANNELS, + IOCTL_AUDIO_SET_CHANNELS, +} AudioIoctl; + +typedef enum +{ + IOCTL_NET_GET_MAC, +} NetIoctl; + +typedef enum +{ + MAP_PRESENT = 1 << 0, + MAP_WRITE = 1 << 1, + MAP_USER = 1 << 2, + MAP_WRITE_THROUGH = 1 << 3, + MAP_CACHE_DISABLE = 1 << 4, +} PageMapFlags; + +typedef struct +{ + struct + { + uint8_t Major; + uint8_t Minor; + uint8_t Patch; + } APIVersion; + + dev_t MajorID; + uintptr_t Base; + + /* Internal */ + int (*RegisterFunction)(dev_t MajorID, void *Function, __driverRegFunc Type); + int (*GetDriverInfo)(dev_t MajorID, const char *Name, const char *Description, const char *Author, const char *Version, const char *License); + + /* Interrupts */ + int (*RegisterInterruptHandler)(dev_t MajorID, uint8_t IRQ, void *Handler); + int (*OverrideInterruptHandler)(dev_t MajorID, uint8_t IRQ, void *Handler); + int (*UnregisterInterruptHandler)(dev_t MajorID, uint8_t IRQ, void *Handler); + int (*UnregisterAllInterruptHandlers)(dev_t MajorID, void *Handler); + + /* Input */ + dev_t (*RegisterInputDevice)(dev_t MajorID, DeviceDriverType Type); + int (*UnregisterInputDevice)(dev_t MajorID, dev_t MinorID, DeviceDriverType Type); + int (*ReportKeyboardEvent)(dev_t MajorID, dev_t MinorID, uint8_t ScanCode); + int (*ReportRelativeMouseEvent)(dev_t MajorID, dev_t MinorID, __MouseButtons Button, int X, int Y, int8_t Z); + int (*ReportAbsoluteMouseEvent)(dev_t MajorID, dev_t MinorID, __MouseButtons Button, uintptr_t X, uintptr_t Y, int8_t Z); + + /* Storage */ + dev_t (*RegisterBlockDevice)(dev_t MajorID, DeviceDriverType Type, void *Open, void *Close, void *Read, void *Write, void *Ioctl); + int (*UnregisterBlockDevice)(dev_t MajorID, dev_t MinorID, DeviceDriverType Type); + + /* Audio */ + dev_t (*RegisterAudioDevice)(dev_t MajorID, DeviceDriverType Type, void *Open, void *Close, void *Read, void *Write, void *Ioctl); + int (*UnregisterAudioDevice)(dev_t MajorID, dev_t MinorID, DeviceDriverType Type); + + /* Network */ + dev_t (*RegisterNetDevice)(dev_t MajorID, DeviceDriverType Type, void *Open, void *Close, void *Read, void *Write, void *Ioctl); + int (*UnregisterNetDevice)(dev_t MajorID, dev_t MinorID, DeviceDriverType Type); + int (*ReportNetworkPacket)(dev_t MajorID, dev_t MinorID, void *Buffer, size_t Size); + + /* Logging */ + void (*KPrint)(dev_t MajorID, const char *Format, va_list args); + void (*KernelLog)(dev_t MajorID, const char *Format, va_list args); + + /* Memory */ + void *(*RequestPages)(dev_t MajorID, size_t Pages); + void (*FreePages)(dev_t MajorID, void *Pointer, size_t Pages); + + /* Mapping */ + void (*AppendMapFlag)(dev_t MajorID, void *Address, PageMapFlags Flag); + void (*RemoveMapFlag)(dev_t MajorID, void *Address, PageMapFlags Flag); + void (*MapPages)(dev_t MajorID, void *PhysicalAddress, void *VirtualAddress, size_t Pages, uint32_t Flags); + void (*UnmapPages)(dev_t MajorID, void *VirtualAddress, size_t Pages); + + /* Scheduling */ + pid_t (*CreateKernelProcess)(dev_t MajorID, const char *Name); + pid_t (*CreateKernelThread)(dev_t MajorID, pid_t pId, const char *Name, void *EntryPoint, void *Argument); + int (*KillProcess)(dev_t MajorID, pid_t pId, int ExitCode); + int (*KillThread)(dev_t MajorID, pid_t tId, int ExitCode); + void (*Yield)(dev_t MajorID); + void (*Sleep)(dev_t MajorID, uint64_t Milliseconds); + + /* PCI */ + __PCIArray *(*GetPCIDevices)(dev_t MajorID, uint16_t Vendors[], uint16_t Devices[]); + void (*InitializePCI)(dev_t MajorID, void *Header); + uint32_t (*GetBAR)(dev_t MajorID, uint8_t Index, void *Header); + + /* Kernel std API */ + void *(*memcpy)(dev_t MajorID, void *Destination, const void *Source, size_t Length); + void *(*memset)(dev_t MajorID, void *Destination, int Value, size_t Length); + void *(*memmove)(dev_t MajorID, void *Destination, const void *Source, size_t Length); + int (*memcmp)(dev_t MajorID, const void *Left, const void *Right, size_t Length); + size_t (*strlen)(dev_t MajorID, const char *String); + char *(*strcpy)(dev_t MajorID, char *Destination, const char *Source); + char *(*strcat)(dev_t MajorID, char *Destination, const char *Source); + int (*strcmp)(dev_t MajorID, const char *Left, const char *Right); + int (*strncmp)(dev_t MajorID, const char *Left, const char *Right, size_t Length); + char *(*strchr)(dev_t MajorID, const char *String, int Character); + char *(*strrchr)(dev_t MajorID, const char *String, int Character); + char *(*strstr)(dev_t MajorID, const char *Haystack, const char *Needle); +} __driverAPI; + +#endif // !__FENNIX_API_DRIVER_FUNCTIONS_H__ diff --git a/exec/binary_parse.cpp b/exec/binary_parse.cpp index 02ad1e8..f30c6f1 100644 --- a/exec/binary_parse.cpp +++ b/exec/binary_parse.cpp @@ -19,52 +19,34 @@ #include -#include "../kernel.h" -#include "../Fex.hpp" - namespace Execute { BinaryType GetBinaryType(const char *Path) { + debug("Checking binary type of %s(ptr: %#lx)", + Path, Path); BinaryType Type; int fd = fopen(Path, "r"); if (fd < 0) + { + debug("Failed to open file %s: %s", + Path, strerror(fd)); return (BinaryType)fd; + } debug("File opened: %s, descriptor %d", Path, fd); Memory::SmartHeap sh = Memory::SmartHeap(1024); fread(fd, sh, 128); - Fex *FexHdr = (Fex *)sh.Get(); Elf32_Ehdr *ELFHeader = (Elf32_Ehdr *)sh.Get(); IMAGE_DOS_HEADER *MZHeader = (IMAGE_DOS_HEADER *)sh.Get(); - /* Check Fex header. */ - if (FexHdr->Magic[0] == 'F' && - FexHdr->Magic[1] == 'E' && - FexHdr->Magic[2] == 'X' && - FexHdr->Magic[3] == '\0') - { - /* If the fex type is driver, we shouldn't return as Fex. */ - if (FexHdr->Type == FexFormatType_Executable) - { - debug("Image - Fex"); - Type = BinaryType::BinTypeFex; - goto Success; - } - else if (FexHdr->Type == FexFormatType_Module) - { - fixme("Fex Module is not supposed to be executed."); - /* TODO: Module installation pop-up. */ - } - } - /* Check ELF header. */ - else if (ELFHeader->e_ident[EI_MAG0] == ELFMAG0 && - ELFHeader->e_ident[EI_MAG1] == ELFMAG1 && - ELFHeader->e_ident[EI_MAG2] == ELFMAG2 && - ELFHeader->e_ident[EI_MAG3] == ELFMAG3) + if (ELFHeader->e_ident[EI_MAG0] == ELFMAG0 && + ELFHeader->e_ident[EI_MAG1] == ELFMAG1 && + ELFHeader->e_ident[EI_MAG2] == ELFMAG2 && + ELFHeader->e_ident[EI_MAG3] == ELFMAG3) { debug("Image - ELF"); Type = BinaryType::BinTypeELF; diff --git a/exec/elf/elf_loader.cpp b/exec/elf/elf_loader.cpp index 0a692d8..8c2f1d3 100644 --- a/exec/elf/elf_loader.cpp +++ b/exec/elf/elf_loader.cpp @@ -26,7 +26,6 @@ #include #include "../../kernel.h" -#include "../../Fex.hpp" using namespace Tasking; using namespace vfs; @@ -162,8 +161,9 @@ namespace Execute uintptr_t EntryPoint = ELFHeader.e_entry; debug("Entry point is %#lx", EntryPoint); - Memory::Virtual vmm = Memory::Virtual(TargetProcess->PageTable); + Memory::Virtual vmm(TargetProcess->PageTable); Memory::VirtualMemoryArea *vma = TargetProcess->vma; + debug("Target process page table is %#lx", TargetProcess->PageTable); LoadPhdrs_x86_64(fd, ELFHeader, vma, TargetProcess); @@ -188,9 +188,10 @@ namespace Execute vmm.Map(vAddr, pAddr, ProgramHeader.p_memsz, - Memory::P | Memory::RW | Memory::US); + Memory::RW | Memory::US); - debug("Mapped %#lx to %#lx", vAddr, pAddr); + debug("Mapped %#lx to %#lx (%ld bytes)", + vAddr, pAddr, ProgramHeader.p_memsz); debug("Segment Offset is %#lx", SegDestOffset); debug("Copying segment to p: %#lx-%#lx; v: %#lx-%#lx (%ld file bytes, %ld mem bytes)", @@ -202,6 +203,8 @@ namespace Execute if (ProgramHeader.p_filesz > 0) { + debug("%d %#lx %d", ProgramHeader.p_offset, + (uint8_t *)pAddr + SegDestOffset, ProgramHeader.p_filesz); lseek(fd, ProgramHeader.p_offset, SEEK_SET); fread(fd, (uint8_t *)pAddr + SegDestOffset, ProgramHeader.p_filesz); } @@ -209,11 +212,100 @@ namespace Execute if (ProgramHeader.p_memsz - ProgramHeader.p_filesz > 0) { void *zAddr = (void *)(uintptr_t(pAddr) + SegDestOffset + ProgramHeader.p_filesz); + + debug("Zeroing %d bytes at %#lx", + ProgramHeader.p_memsz - ProgramHeader.p_filesz, zAddr); + memset(zAddr, 0, ProgramHeader.p_memsz - ProgramHeader.p_filesz); } ProgramBreakHeader = ProgramHeader; break; } + case PT_NOTE: + { + Elf64_Nhdr NoteHeader; + lseek(fd, ProgramHeader.p_offset, SEEK_SET); + fread(fd, (uint8_t *)&NoteHeader, sizeof(Elf64_Nhdr)); + + switch (NoteHeader.n_type) + { + case NT_PRSTATUS: + { + Elf64_Prstatus prstatus; + lseek(fd, ProgramHeader.p_offset + sizeof(Elf64_Nhdr), SEEK_SET); + fread(fd, (uint8_t *)&prstatus, sizeof(Elf64_Prstatus)); + debug("PRSTATUS: %#lx", prstatus.pr_reg[0]); + break; + } + case NT_PRPSINFO: + { + Elf64_Prpsinfo prpsinfo; + lseek(fd, ProgramHeader.p_offset + sizeof(Elf64_Nhdr), SEEK_SET); + fread(fd, (uint8_t *)&prpsinfo, sizeof(Elf64_Prpsinfo)); + debug("PRPSINFO: %s", prpsinfo.pr_fname); + break; + } + case NT_PLATFORM: + { + char platform[256]; + lseek(fd, ProgramHeader.p_offset + sizeof(Elf64_Nhdr), SEEK_SET); + fread(fd, (uint8_t *)&platform, 256); + debug("PLATFORM: %s", platform); + break; + } + case NT_AUXV: + { + Elf64_auxv_t auxv; + lseek(fd, ProgramHeader.p_offset + sizeof(Elf64_Nhdr), SEEK_SET); + fread(fd, (uint8_t *)&auxv, sizeof(Elf64_auxv_t)); + debug("AUXV: %#lx", auxv.a_un.a_val); + break; + } + default: + { + fixme("Unhandled note type: %#lx", NoteHeader.n_type); + break; + } + } + break; + } + case PT_TLS: + { + size_t tlsSize = ProgramHeader.p_memsz; + debug("TLS Size: %ld (%ld pages)", + tlsSize, TO_PAGES(tlsSize)); + void *tlsMemory = vma->RequestPages(TO_PAGES(tlsSize)); + lseek(fd, ProgramHeader.p_offset, SEEK_SET); + fread(fd, (uint8_t *)tlsMemory, tlsSize); + TargetProcess->TLS = { + .pBase = uintptr_t(tlsMemory), + .vBase = ProgramHeader.p_vaddr, + .Align = ProgramHeader.p_align, + .Size = ProgramHeader.p_memsz, + .fSize = ProgramHeader.p_filesz, + }; + break; + } + case 0x6474E550: /* PT_GNU_EH_FRAME */ + { + fixme("PT_GNU_EH_FRAME"); + break; + } + case 0x6474e551: /* PT_GNU_STACK */ + { + fixme("PT_GNU_STACK"); + break; + } + case 0x6474e552: /* PT_GNU_RELRO */ + { + fixme("PT_GNU_RELRO"); + break; + } + case 0x6474e553: /* PT_GNU_PROPERTY */ + { + fixme("PT_GNU_PROPERTY"); + break; + } default: { fixme("Unhandled program header type: %#lx", @@ -238,6 +330,11 @@ namespace Execute fread(fd, sh, statbuf.st_size); TargetProcess->ELFSymbolTable->AppendSymbols(uintptr_t(sh.Get())); +#ifdef DEBUG + if (!TargetProcess->ELFSymbolTable->SymTableExists) + debug("NO SYMBOL TABLE FOUND?"); +#endif + debug("Entry Point: %#lx", EntryPoint); this->GenerateAuxiliaryVector_x86_64(vma, fd, ELFHeader, @@ -299,7 +396,7 @@ namespace Execute uintptr_t EntryPoint = ELFHeader.e_entry; debug("Entry point is %#lx", EntryPoint); - Memory::Virtual vmm = Memory::Virtual(TargetProcess->PageTable); + Memory::Virtual vmm(TargetProcess->PageTable); Memory::VirtualMemoryArea *vma = TargetProcess->vma; uintptr_t BaseAddress = 0; @@ -396,6 +493,26 @@ namespace Execute } break; } + case 0x6474E550: /* PT_GNU_EH_FRAME */ + { + fixme("PT_GNU_EH_FRAME"); + break; + } + case 0x6474e551: /* PT_GNU_STACK */ + { + fixme("PT_GNU_STACK"); + break; + } + case 0x6474e552: /* PT_GNU_RELRO */ + { + fixme("PT_GNU_RELRO"); + break; + } + case 0x6474e553: /* PT_GNU_PROPERTY */ + { + fixme("PT_GNU_PROPERTY"); + break; + } default: { fixme("Unhandled program header type: %#lx", @@ -417,240 +534,209 @@ namespace Execute EntryPoint += BaseAddress; debug("The new ep is %#lx", EntryPoint); - std::vector JmpRel = ELFGetDynamicTag_x86_64(fd, DT_JMPREL); - std::vector SymTab = ELFGetDynamicTag_x86_64(fd, DT_SYMTAB); - std::vector StrTab = ELFGetDynamicTag_x86_64(fd, DT_STRTAB); - std::vector RelaDyn = ELFGetDynamicTag_x86_64(fd, DT_RELA); - std::vector RelaDynSize = ELFGetDynamicTag_x86_64(fd, DT_RELASZ); - - size_t JmpRelSize = JmpRel.size(); - size_t SymTabSize = SymTab.size(); - size_t StrTabSize = StrTab.size(); - size_t RelaDynSize_v = RelaDyn.size(); - - if (JmpRelSize < 1) - { - debug("No DT_JMPREL"); - } - - if (SymTabSize < 1) - { - debug("No DT_SYMTAB"); - } - - if (StrTabSize < 1) - { - debug("No DT_STRTAB"); - } - - if (RelaDynSize_v < 1) - { - debug("No DT_RELA"); - } - - if (RelaDynSize[0].d_un.d_val < 1) - { - debug("DT_RELASZ is < 1"); - } - - if (JmpRelSize > 0 && SymTabSize > 0 && StrTabSize > 0) - { - debug("JmpRel: %#lx, SymTab: %#lx, StrTab: %#lx", - JmpRel[0].d_un.d_ptr, SymTab[0].d_un.d_ptr, - StrTab[0].d_un.d_ptr); - - Elf64_Rela *_JmpRel = (Elf64_Rela *)((uintptr_t)BaseAddress + JmpRel[0].d_un.d_ptr); - Elf64_Sym *_SymTab = (Elf64_Sym *)((uintptr_t)BaseAddress + SymTab[0].d_un.d_ptr); - char *_DynStr = (char *)((uintptr_t)BaseAddress + StrTab[0].d_un.d_ptr); - Elf64_Rela *_RelaDyn = (Elf64_Rela *)((uintptr_t)BaseAddress + RelaDyn[0].d_un.d_ptr); - - Elf64_Shdr shdr; - for (Elf64_Half i = 0; i < ELFHeader.e_shnum; i++) - { - lseek(fd, ELFHeader.e_shoff + i * sizeof(Elf64_Shdr), SEEK_SET); - fread(fd, (uint8_t *)&shdr, sizeof(Elf64_Shdr)); - - char sectionName[32]; - Elf64_Shdr n_shdr; - lseek(fd, ELFHeader.e_shoff + ELFHeader.e_shstrndx * sizeof(Elf64_Shdr), SEEK_SET); - fread(fd, (uint8_t *)&n_shdr, sizeof(Elf64_Shdr)); - lseek(fd, n_shdr.sh_offset + shdr.sh_name, SEEK_SET); - fread(fd, (uint8_t *)sectionName, 32); - debug("shdr: %s", sectionName); - - if (strcmp(sectionName, ".rela.plt") == 0) - { - // .rela.plt - // R_X86_64_JUMP_SLOT - Elf64_Xword numEntries = shdr.sh_size / shdr.sh_entsize; - for (Elf64_Xword i = 0; i < numEntries; i++) - { - Elf64_Addr *GOTEntry = (Elf64_Addr *)(shdr.sh_addr + - BaseAddress + - i * sizeof(Elf64_Addr)); - Elf64_Rela *Rel = _JmpRel + i; - Elf64_Xword RelType = ELF64_R_TYPE(Rel->r_info); - - switch (RelType) - { - case R_X86_64_JUMP_SLOT: - { - Elf64_Xword SymIndex = ELF64_R_SYM(Rel->r_info); - Elf64_Sym *Sym = _SymTab + SymIndex; - - if (Sym->st_name) - { - char *SymName = _DynStr + Sym->st_name; - debug("SymName: %s", SymName); - - Elf64_Sym LibSym = ELFLookupSymbol(fd, SymName); - if (LibSym.st_value) - { - *GOTEntry = (Elf64_Addr)(BaseAddress + LibSym.st_value); - debug("GOT[%ld](%#lx): %#lx", - i, uintptr_t(GOTEntry) - BaseAddress, - *GOTEntry); - } - } - continue; - } - default: - { - fixme("Unhandled relocation type: %#lx", RelType); - break; - } - } - } - } - else if (strcmp(sectionName, ".rela.dyn") == 0) - { - // .rela.dyn - // R_X86_64_RELATIVE - // R_X86_64_GLOB_DAT - if (RelaDynSize_v < 1 || RelaDynSize[0].d_un.d_val < 1) - continue; - Elf64_Xword numRelaDynEntries = RelaDynSize[0].d_un.d_val / sizeof(Elf64_Rela); - for (Elf64_Xword i = 0; i < numRelaDynEntries; i++) - { - Elf64_Rela *Rel = _RelaDyn + i; - Elf64_Addr *GOTEntry = (Elf64_Addr *)(Rel->r_offset + BaseAddress); - Elf64_Xword RelType = ELF64_R_TYPE(Rel->r_info); - - switch (RelType) - { - case R_X86_64_RELATIVE: - { - *GOTEntry = (Elf64_Addr)(BaseAddress + Rel->r_addend); - debug("GOT[%ld](%#lx): %#lx (R_X86_64_RELATIVE)", - i, uintptr_t(GOTEntry) - BaseAddress, - *GOTEntry); - break; - } - case R_X86_64_GLOB_DAT: - { - Elf64_Xword SymIndex = ELF64_R_SYM(Rel->r_info); - Elf64_Sym *Sym = _SymTab + SymIndex; - - if (Sym->st_name) - { - char *SymName = _DynStr + Sym->st_name; - debug("SymName: %s", SymName); - - Elf64_Sym LibSym = ELFLookupSymbol(fd, SymName); - if (LibSym.st_value) - { - *GOTEntry = (Elf64_Addr)(BaseAddress + LibSym.st_value); - debug("GOT[%ld](%#lx): %#lx (R_X86_64_GLOB_DAT)", - i, uintptr_t(GOTEntry) - BaseAddress, - *GOTEntry); - } - } - break; - } - default: - { - fixme("Unhandled relocation type: %#lx", RelType); - break; - } - } - } - } - else if (strcmp(sectionName, ".dynsym") == 0) - { - // .dynsym - // STT_OBJECT - - Elf64_Sym *SymArray = (Elf64_Sym *)(shdr.sh_addr + BaseAddress); - Elf64_Xword numEntries = shdr.sh_size / shdr.sh_entsize; - debug("start %#lx (off %#lx), entries %ld", - SymArray, shdr.sh_addr, numEntries); - for (Elf64_Xword j = 0; j < numEntries; j++) - { - Elf64_Sym Sym = SymArray[j]; - - if (Sym.st_shndx == SHN_UNDEF) - continue; - - if (Sym.st_value == 0) - continue; - - unsigned char SymType = ELF64_ST_TYPE(Sym.st_info); - - if (SymType == STT_OBJECT) - { - Elf64_Addr *GOTEntry = (Elf64_Addr *)(Sym.st_value + BaseAddress); - *GOTEntry = (Elf64_Addr)(BaseAddress + Sym.st_value); - - debug("%ld: \"%s\" %#lx -> %#lx", j, - _DynStr + Sym.st_name, - uintptr_t(GOTEntry) - BaseAddress, - *GOTEntry); - } - } - } - else if (strcmp(sectionName, ".symtab") == 0) - { - // .symtab - // STT_OBJECT - - Elf64_Xword numEntries = shdr.sh_size / shdr.sh_entsize; - Elf64_Sym *SymArray = new Elf64_Sym[numEntries]; - lseek(fd, shdr.sh_offset, SEEK_SET); - fread(fd, (uint8_t *)SymArray, shdr.sh_size); - - debug("start %#lx (off %#lx), entries %ld", - SymArray, shdr.sh_addr, numEntries); - for (Elf64_Xword j = 0; j < numEntries; j++) - { - Elf64_Sym Sym = SymArray[j]; - - if (Sym.st_shndx == SHN_UNDEF) - continue; - - if (Sym.st_value == 0) - continue; - - unsigned char SymType = ELF64_ST_TYPE(Sym.st_info); - - if (SymType == STT_OBJECT) - { - Elf64_Addr *GOTEntry = (Elf64_Addr *)(Sym.st_value + BaseAddress); - *GOTEntry = (Elf64_Addr)(BaseAddress + Sym.st_value); - - debug("%ld: \"\" %#lx -> %#lx", j, - /*_DynStr + Sym.st_name,*/ - uintptr_t(GOTEntry) - BaseAddress, - *GOTEntry); - } - } - delete[] SymArray; - } - - // if (shdr.sh_type == SHT_PROGBITS && - // (shdr.sh_flags & SHF_WRITE) && - // (shdr.sh_flags & SHF_ALLOC)) - } - } + // std::vector JmpRel = ELFGetDynamicTag_x86_64(fd, DT_JMPREL); + // std::vector SymTab = ELFGetDynamicTag_x86_64(fd, DT_SYMTAB); + // std::vector StrTab = ELFGetDynamicTag_x86_64(fd, DT_STRTAB); + // std::vector RelaDyn = ELFGetDynamicTag_x86_64(fd, DT_RELA); + // std::vector RelaDynSize = ELFGetDynamicTag_x86_64(fd, DT_RELASZ); + // size_t JmpRelSize = JmpRel.size(); + // size_t SymTabSize = SymTab.size(); + // size_t StrTabSize = StrTab.size(); + // size_t RelaDynSize_v = RelaDyn.size(); + // if (JmpRelSize < 1) + // { + // debug("No DT_JMPREL"); + // } + // if (SymTabSize < 1) + // { + // debug("No DT_SYMTAB"); + // } + // if (StrTabSize < 1) + // { + // debug("No DT_STRTAB"); + // } + // if (RelaDynSize_v < 1) + // { + // debug("No DT_RELA"); + // } + // if (RelaDynSize[0].d_un.d_val < 1) + // { + // debug("DT_RELASZ is < 1"); + // } + // if (JmpRelSize > 0 && SymTabSize > 0 && StrTabSize > 0) + // { + // debug("JmpRel: %#lx, SymTab: %#lx, StrTab: %#lx", + // JmpRel[0].d_un.d_ptr, SymTab[0].d_un.d_ptr, + // StrTab[0].d_un.d_ptr); + // Elf64_Rela *_JmpRel = (Elf64_Rela *)((uintptr_t)BaseAddress + JmpRel[0].d_un.d_ptr); + // Elf64_Sym *_SymTab = (Elf64_Sym *)((uintptr_t)BaseAddress + SymTab[0].d_un.d_ptr); + // char *_DynStr = (char *)((uintptr_t)BaseAddress + StrTab[0].d_un.d_ptr); + // Elf64_Rela *_RelaDyn = (Elf64_Rela *)((uintptr_t)BaseAddress + RelaDyn[0].d_un.d_ptr); + // Elf64_Shdr shdr; + // for (Elf64_Half i = 0; i < ELFHeader.e_shnum; i++) + // { + // lseek(fd, ELFHeader.e_shoff + i * sizeof(Elf64_Shdr), SEEK_SET); + // fread(fd, (uint8_t *)&shdr, sizeof(Elf64_Shdr)); + // char sectionName[32]; + // Elf64_Shdr n_shdr; + // lseek(fd, ELFHeader.e_shoff + ELFHeader.e_shstrndx * sizeof(Elf64_Shdr), SEEK_SET); + // fread(fd, (uint8_t *)&n_shdr, sizeof(Elf64_Shdr)); + // lseek(fd, n_shdr.sh_offset + shdr.sh_name, SEEK_SET); + // fread(fd, (uint8_t *)sectionName, 32); + // debug("shdr: %s", sectionName); + // if (strcmp(sectionName, ".rela.plt") == 0) + // { + // // .rela.plt + // // R_X86_64_JUMP_SLOT + // Elf64_Xword numEntries = shdr.sh_size / shdr.sh_entsize; + // for (Elf64_Xword i = 0; i < numEntries; i++) + // { + // Elf64_Addr *GOTEntry = (Elf64_Addr *)(shdr.sh_addr + + // BaseAddress + + // i * sizeof(Elf64_Addr)); + // Elf64_Rela *Rel = _JmpRel + i; + // Elf64_Xword RelType = ELF64_R_TYPE(Rel->r_info); + // switch (RelType) + // { + // case R_X86_64_JUMP_SLOT: + // { + // Elf64_Xword SymIndex = ELF64_R_SYM(Rel->r_info); + // Elf64_Sym *Sym = _SymTab + SymIndex; + // if (Sym->st_name) + // { + // char *SymName = _DynStr + Sym->st_name; + // debug("SymName: %s", SymName); + // Elf64_Sym LibSym = ELFLookupSymbol(fd, SymName); + // if (LibSym.st_value) + // { + // *GOTEntry = (Elf64_Addr)(BaseAddress + LibSym.st_value); + // debug("GOT[%ld](%#lx): %#lx", + // i, uintptr_t(GOTEntry) - BaseAddress, + // *GOTEntry); + // } + // } + // continue; + // } + // default: + // { + // fixme("Unhandled relocation type: %#lx", RelType); + // break; + // } + // } + // } + // } + // else if (strcmp(sectionName, ".rela.dyn") == 0) + // { + // // .rela.dyn + // // R_X86_64_RELATIVE + // // R_X86_64_GLOB_DAT + // if (RelaDynSize_v < 1 || RelaDynSize[0].d_un.d_val < 1) + // continue; + // Elf64_Xword numRelaDynEntries = RelaDynSize[0].d_un.d_val / sizeof(Elf64_Rela); + // for (Elf64_Xword i = 0; i < numRelaDynEntries; i++) + // { + // Elf64_Rela *Rel = _RelaDyn + i; + // Elf64_Addr *GOTEntry = (Elf64_Addr *)(Rel->r_offset + BaseAddress); + // Elf64_Xword RelType = ELF64_R_TYPE(Rel->r_info); + // switch (RelType) + // { + // case R_X86_64_RELATIVE: + // { + // *GOTEntry = (Elf64_Addr)(BaseAddress + Rel->r_addend); + // debug("GOT[%ld](%#lx): %#lx (R_X86_64_RELATIVE)", + // i, uintptr_t(GOTEntry) - BaseAddress, + // *GOTEntry); + // break; + // } + // case R_X86_64_GLOB_DAT: + // { + // Elf64_Xword SymIndex = ELF64_R_SYM(Rel->r_info); + // Elf64_Sym *Sym = _SymTab + SymIndex; + // if (Sym->st_name) + // { + // char *SymName = _DynStr + Sym->st_name; + // debug("SymName: %s", SymName); + // Elf64_Sym LibSym = ELFLookupSymbol(fd, SymName); + // if (LibSym.st_value) + // { + // *GOTEntry = (Elf64_Addr)(BaseAddress + LibSym.st_value); + // debug("GOT[%ld](%#lx): %#lx (R_X86_64_GLOB_DAT)", + // i, uintptr_t(GOTEntry) - BaseAddress, + // *GOTEntry); + // } + // } + // break; + // } + // default: + // { + // fixme("Unhandled relocation type: %#lx", RelType); + // break; + // } + // } + // } + // } + // else if (strcmp(sectionName, ".dynsym") == 0) + // { + // // .dynsym + // // STT_OBJECT + // Elf64_Sym *SymArray = (Elf64_Sym *)(shdr.sh_addr + BaseAddress); + // Elf64_Xword numEntries = shdr.sh_size / shdr.sh_entsize; + // debug("start %#lx (off %#lx), entries %ld", + // SymArray, shdr.sh_addr, numEntries); + // for (Elf64_Xword j = 0; j < numEntries; j++) + // { + // Elf64_Sym Sym = SymArray[j]; + // if (Sym.st_shndx == SHN_UNDEF) + // continue; + // if (Sym.st_value == 0) + // continue; + // unsigned char SymType = ELF64_ST_TYPE(Sym.st_info); + // if (SymType == STT_OBJECT) + // { + // Elf64_Addr *GOTEntry = (Elf64_Addr *)(Sym.st_value + BaseAddress); + // *GOTEntry = (Elf64_Addr)(BaseAddress + Sym.st_value); + // debug("%ld: \"%s\" %#lx -> %#lx", j, + // _DynStr + Sym.st_name, + // uintptr_t(GOTEntry) - BaseAddress, + // *GOTEntry); + // } + // } + // } + // else if (strcmp(sectionName, ".symtab") == 0) + // { + // // .symtab + // // STT_OBJECT + // Elf64_Xword numEntries = shdr.sh_size / shdr.sh_entsize; + // Elf64_Sym *SymArray = new Elf64_Sym[numEntries]; + // lseek(fd, shdr.sh_offset, SEEK_SET); + // fread(fd, (uint8_t *)SymArray, shdr.sh_size); + // debug("start %#lx (off %#lx), entries %ld", + // SymArray, shdr.sh_addr, numEntries); + // for (Elf64_Xword j = 0; j < numEntries; j++) + // { + // Elf64_Sym Sym = SymArray[j]; + // if (Sym.st_shndx == SHN_UNDEF) + // continue; + // if (Sym.st_value == 0) + // continue; + // unsigned char SymType = ELF64_ST_TYPE(Sym.st_info); + // if (SymType == STT_OBJECT) + // { + // Elf64_Addr *GOTEntry = (Elf64_Addr *)(Sym.st_value + BaseAddress); + // *GOTEntry = (Elf64_Addr)(BaseAddress + Sym.st_value); + // debug("%ld: \"\" %#lx -> %#lx", j, + // /*_DynStr + Sym.st_name,*/ + // uintptr_t(GOTEntry) - BaseAddress, + // *GOTEntry); + // } + // } + // delete[] SymArray; + // } + // // if (shdr.sh_type == SHT_PROGBITS && + // // (shdr.sh_flags & SHF_WRITE) && + // // (shdr.sh_flags & SHF_ALLOC)) + // } + // } /* ------------------------------------------------------------------------ */ @@ -661,6 +747,11 @@ namespace Execute fread(fd, sh, statbuf.st_size); TargetProcess->ELFSymbolTable->AppendSymbols(uintptr_t(sh.Get()), BaseAddress); + if (!TargetProcess->ELFSymbolTable->SymTableExists) + { + debug("NO SYMBOL TABLE FOUND?"); + } + debug("Entry Point: %#lx", EntryPoint); this->GenerateAuxiliaryVector_x86_64(vma, fd, ELFHeader, @@ -759,6 +850,7 @@ namespace Execute error("Failed to open %s, errno: %d", AbsolutePath, fd); return; } + debug("Opened %s", AbsolutePath); int argc = 0; int envc = 0; @@ -769,23 +861,23 @@ namespace Execute envc++; // ELFargv = new const char *[argc + 2]; - size_t argv_size = TO_PAGES(argc + 2 * sizeof(char *)); - ELFargv = (const char **)TargetProcess->vma->RequestPages(argv_size); + size_t argv_size = argc + 2 * sizeof(char *); + ELFargv = (const char **)TargetProcess->vma->RequestPages(TO_PAGES(argv_size)); for (int i = 0; i < argc; i++) { - size_t arg_size = TO_PAGES(strlen(argv[i]) + 1); - ELFargv[i] = (const char *)TargetProcess->vma->RequestPages(arg_size); + size_t arg_size = strlen(argv[i]) + 1; + ELFargv[i] = (const char *)TargetProcess->vma->RequestPages(TO_PAGES(arg_size)); strcpy((char *)ELFargv[i], argv[i]); } ELFargv[argc] = nullptr; // ELFenvp = new const char *[envc + 1]; - size_t envp_size = TO_PAGES(envc + 1 * sizeof(char *)); - ELFenvp = (const char **)TargetProcess->vma->RequestPages(envp_size); + size_t envp_size = envc + 1 * sizeof(char *); + ELFenvp = (const char **)TargetProcess->vma->RequestPages(TO_PAGES(envp_size)); for (int i = 0; i < envc; i++) { - size_t env_size = TO_PAGES(strlen(envp[i]) + 1); - ELFenvp[i] = (const char *)TargetProcess->vma->RequestPages(env_size); + size_t env_size = strlen(envp[i]) + 1; + ELFenvp[i] = (const char *)TargetProcess->vma->RequestPages(TO_PAGES(env_size)); strcpy((char *)ELFenvp[i], envp[i]); } ELFenvp[envc] = nullptr; diff --git a/exec/elf/elf_parse.cpp b/exec/elf/elf_parse.cpp index a7cd724..8d12ba5 100644 --- a/exec/elf/elf_parse.cpp +++ b/exec/elf/elf_parse.cpp @@ -20,7 +20,6 @@ #include #include "../../kernel.h" -#include "../../Fex.hpp" namespace Execute { diff --git a/exec/elf/elf_rel.cpp b/exec/elf/elf_rel.cpp index fd6b35c..96b2d37 100644 --- a/exec/elf/elf_rel.cpp +++ b/exec/elf/elf_rel.cpp @@ -20,83 +20,82 @@ #include #include "../../kernel.h" -#include "../../Fex.hpp" namespace Execute { - /* Originally from https://wiki.osdev.org/ELF_Tutorial */ + /* Originally from https://wiki.osdev.org/ELF_Tutorial */ - void ELFLoadRel(void *BaseImage, - const char *Name, - Tasking::PCB *Process) - { + void ELFLoadRel(void *BaseImage, + const char *Name, + Tasking::PCB *Process) + { #if defined(a64) - UNUSED(Name); - debug("Relocatable"); - /* TODO: I have to fully implement this, but for now I will leave it as it is now. */ - warn("Relocatable ELF is not fully supported yet"); - Elf64_Shdr *shdr = GetELFSheader(((Elf64_Ehdr *)BaseImage)); - for (Elf64_Half i = 0; i < ((Elf64_Ehdr *)BaseImage)->e_shnum; i++) - { - Elf64_Shdr *Section = &shdr[i]; - if (Section->sh_type == SHT_NOBITS) - { - if (!Section->sh_size) - continue; - if (Section->sh_flags & SHF_ALLOC) - { - void *Buffer = KernelAllocator.RequestPages(TO_PAGES(Section->sh_size + 1)); - memset(Buffer, 0, Section->sh_size); + UNUSED(Name); + debug("Relocatable"); + /* TODO: I have to fully implement this, but for now I will leave it as it is now. */ + warn("Relocatable ELF is not fully supported yet"); + Elf64_Shdr *shdr = GetELFSheader(((Elf64_Ehdr *)BaseImage)); + for (Elf64_Half i = 0; i < ((Elf64_Ehdr *)BaseImage)->e_shnum; i++) + { + Elf64_Shdr *Section = &shdr[i]; + if (Section->sh_type == SHT_NOBITS) + { + if (!Section->sh_size) + continue; + if (Section->sh_flags & SHF_ALLOC) + { + void *Buffer = KernelAllocator.RequestPages(TO_PAGES(Section->sh_size + 1)); + memset(Buffer, 0, Section->sh_size); - Memory::Virtual(Process->PageTable).Map((void *)Buffer, (void *)Buffer, Section->sh_size, Memory::PTFlag::RW | Memory::PTFlag::US); + Memory::Virtual(Process->PageTable).Map((void *)Buffer, (void *)Buffer, Section->sh_size, Memory::PTFlag::RW | Memory::PTFlag::US); - Section->sh_offset = (uintptr_t)Buffer - (uintptr_t)BaseImage; - debug("Section %ld", Section->sh_size); - } - } - } + Section->sh_offset = (uintptr_t)Buffer - (uintptr_t)BaseImage; + debug("Section %ld", Section->sh_size); + } + } + } - for (Elf64_Half i = 0; i < ((Elf64_Ehdr *)BaseImage)->e_shnum; i++) - { - Elf64_Shdr *Section = &shdr[i]; - if (Section->sh_type == SHT_REL) - { - for (size_t Index = 0; Index < Section->sh_size / Section->sh_entsize; Index++) - { - Elf64_Rel *RelTable = &((Elf64_Rel *)((uintptr_t)BaseImage + Section->sh_offset))[Index]; - Elf64_Shdr *Target = GetELFSection(((Elf64_Ehdr *)BaseImage), Section->sh_info); + for (Elf64_Half i = 0; i < ((Elf64_Ehdr *)BaseImage)->e_shnum; i++) + { + Elf64_Shdr *Section = &shdr[i]; + if (Section->sh_type == SHT_REL) + { + for (size_t Index = 0; Index < Section->sh_size / Section->sh_entsize; Index++) + { + Elf64_Rel *RelTable = &((Elf64_Rel *)((uintptr_t)BaseImage + Section->sh_offset))[Index]; + Elf64_Shdr *Target = GetELFSection(((Elf64_Ehdr *)BaseImage), Section->sh_info); - uintptr_t *RelAddress = (uintptr_t *)(((uintptr_t)BaseImage + Target->sh_offset) + RelTable->r_offset); - uint64_t SymbolValue = 0; + uintptr_t *RelAddress = (uintptr_t *)(((uintptr_t)BaseImage + Target->sh_offset) + RelTable->r_offset); + uint64_t SymbolValue = 0; - if (ELF64_R_SYM(RelTable->r_info) != SHN_UNDEF) - { - SymbolValue = ELFGetSymbolValue(((Elf64_Ehdr *)BaseImage), Section->sh_link, ELF64_R_SYM(RelTable->r_info)); - if (SymbolValue == 0xdead) - return; - } + if (ELF64_R_SYM(RelTable->r_info) != SHN_UNDEF) + { + SymbolValue = ELFGetSymbolValue(((Elf64_Ehdr *)BaseImage), Section->sh_link, ELF64_R_SYM(RelTable->r_info)); + if (SymbolValue == 0xdead) + return; + } - switch (ELF64_R_TYPE(RelTable->r_info)) - { - case R_386_NONE: - break; - case R_386_32: - *RelAddress = DO_64_64(SymbolValue, *RelAddress); - break; - case R_386_PC32: - *RelAddress = DO_64_PC32(SymbolValue, *RelAddress, (uintptr_t)RelAddress); - break; - default: - { - error("Unsupported relocation type: %d", ELF64_R_TYPE(RelTable->r_info)); - return; - } - } - debug("Symbol value: %#lx", SymbolValue); - } - } - } + switch (ELF64_R_TYPE(RelTable->r_info)) + { + case R_386_NONE: + break; + case R_386_32: + *RelAddress = DO_64_64(SymbolValue, *RelAddress); + break; + case R_386_PC32: + *RelAddress = DO_64_PC32(SymbolValue, *RelAddress, (uintptr_t)RelAddress); + break; + default: + { + error("Unsupported relocation type: %d", ELF64_R_TYPE(RelTable->r_info)); + return; + } + } + debug("Symbol value: %#lx", SymbolValue); + } + } + } #elif defined(a32) #endif - } + } } diff --git a/exec/spawn.cpp b/exec/spawn.cpp index 248e683..ad124ba 100644 --- a/exec/spawn.cpp +++ b/exec/spawn.cpp @@ -25,14 +25,13 @@ #include #include "../kernel.h" -#include "../Fex.hpp" using namespace Tasking; namespace Execute { int Spawn(char *Path, const char **argv, const char **envp, - Tasking::PCB *Parent, + Tasking::PCB *Parent, bool Fork, Tasking::TaskCompatibility Compatibility, bool Critical) { @@ -50,19 +49,6 @@ namespace Execute switch (GetBinaryType(Path)) { - case BinaryType::BinTypeFex: - { - Fex FexHdr; - fread(fd, (uint8_t *)&FexHdr, sizeof(Fex)); - if (FexHdr.Type == FexFormatType::FexFormatType_Executable) - { - stub; - assert(false); - } - - fclose(fd); - return -ENOEXEC; - } case BinaryType::BinTypeELF: { TaskArchitecture Arch = TaskArchitecture::UnknownArchitecture; @@ -118,20 +104,44 @@ namespace Execute debug("Loaded elf %s at %#lx with the length of %ld", Path, ElfFile, statbuf.st_size); - if (Parent == nullptr) - Parent = thisProcess; + PCB *Process; + if (Fork) + { + assert(Parent != nullptr); + CriticalSection cs; - PCB *Process = TaskManager->CreateProcess(Parent, - BaseName, - TaskExecutionMode::User, - ElfFile, false, - 0, 0); + Process = Parent; + foreach (auto tcb in Process->Threads) + { + debug("Deleting thread %d", tcb->ID); + // delete tcb; + tcb->SetState(Tasking::Terminated); + } - KernelAllocator.FreePages(ElfFile, TO_PAGES(statbuf.st_size + 1)); + fixme("free allocated memory"); + fixme("change symbol table"); + // Process->vma->FreeAllPages(); + delete Process->ELFSymbolTable; + Process->ELFSymbolTable = new SymbolResolver::Symbols((uintptr_t)ElfFile); + } + else + { + if (Parent == nullptr) + Parent = thisProcess; + + Process = TaskManager->CreateProcess(Parent, + BaseName, + TaskExecutionMode::User, + ElfFile, false, + 0, 0); + Process->Info.Compatibility = Compatibility; + Process->Info.Architecture = Arch; + } Process->SetWorkingDirectory(fs->GetNodeFromPath(Path)->Parent); - Process->Info.Compatibility = TaskCompatibility::Native; - Process->Info.Architecture = TaskArchitecture::x64; + Process->SetExe(Path); + + KernelAllocator.FreePages(ElfFile, TO_PAGES(statbuf.st_size + 1)); ELFObject *obj = new ELFObject(Path, Process, argv, envp); if (!obj->IsValid) @@ -142,14 +152,40 @@ namespace Execute return -ENOEXEC; } - /* FIXME: implement stdio fildes */ + vfs::FileDescriptorTable *pfdt = Parent->FileDescriptors; vfs::FileDescriptorTable *fdt = Process->FileDescriptors; - // stdin - fdt->_open("/dev/tty", O_RDWR, 0666); - // stdout - fdt->_open("/dev/tty", O_RDWR, 0666); - // stderr - fdt->_open("/dev/tty", O_RDWR, 0666); + + auto ForkStdio = [pfdt, fdt](Node *SearchNode) + { + if (unlikely(SearchNode == nullptr)) + return false; + + std::vector + pfds = pfdt->GetFileDescriptors(); + + foreach (auto ffd in pfds) + { + if (ffd.Flags & O_CLOEXEC) + continue; + + if (ffd.Handle->node == SearchNode) + { + fdt->_open(ffd.Handle->node->FullPath, + ffd.Flags, ffd.Mode); + return true; + } + } + return false; + }; + + if (!ForkStdio(Parent->stdin)) + fdt->_open("/dev/kcon", O_RDWR, 0666); + + if (!ForkStdio(Parent->stdout)) + fdt->_open("/dev/kcon", O_RDWR, 0666); + + if (!ForkStdio(Parent->stderr)) + fdt->_open("/dev/kcon", O_RDWR, 0666); TCB *Thread = nullptr; { diff --git a/include/acpi.hpp b/include/acpi.hpp index 6a28a43..31c531a 100644 --- a/include/acpi.hpp +++ b/include/acpi.hpp @@ -20,6 +20,7 @@ #include +#include #include #include #include @@ -27,272 +28,359 @@ 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; + 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 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; + enum DBG2PortType + { + TYPE_SERIAL = 0x8000, + TYPE_1394 = 0x8001, + TYPE_USB = 0x8002, + TYPE_NET = 0x8003 + }; - 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; + enum DBG2PortSubtype + { + SUBTYPE_SERIAL_16550_COMPATIBLE = 0x0000, + SUBTYPE_SERIAL_16550_SUBSET = 0x0001, + SUBTYPE_SERIAL_MAX311xE_SPI_UART = 0x0002, + SUBTYPE_SERIAL_Arm_PL011_UART = 0x0003, + SUBTYPE_SERIAL_MSM8x60 = 0x0004, + SUBTYPE_SERIAL_Nvidia_16550 = 0x0005, + SUBTYPE_SERIAL_TI_OMAP = 0x0006, + SUBTYPE_SERIAL_APM88xxxx = 0x0008, + SUBTYPE_SERIAL_MSM8974 = 0x0009, + SUBTYPE_SERIAL_SAM5250 = 0x000A, + SUBTYPE_SERIAL_Intel_USIF = 0x000B, + SUBTYPE_SERIAL_iMX6 = 0x000C, + SUBTYPE_SERIAL_Arm_SBSA_UART = 0x000D, + SUBTYPE_SERIAL_Arm_SBSA_Generic_UART = 0x000E, + SUBTYPE_SERIAL_Arm_DCC = 0x000F, + SUBTYPE_SERIAL_BCM2835 = 0x0010, + SUBTYPE_SERIAL_SDM845_At_1_8432MHz = 0x0011, + SUBTYPE_SERIAL_16550_With_Generic_Address_Structure = 0x0012, + SUBTYPE_SERIAL_SDM845_At_7_372MHz = 0x0013, + SUBTYPE_SERIAL_Intel_LPSS = 0x0014, + SUBTYPE_SERIAL_RISC_V_SBI_Console = 0x0015, - 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; + SUBTYPE_1394_IEEE1394_HCI = 0x0000, + + SUBTYPE_USB_XHCI = 0x0000, + SUBTYPE_USB_EHCI = 0x0001, - struct BGRTHeader - { - ACPIHeader Header; - uint16_t Version; - uint8_t Status; - uint8_t ImageType; - uint64_t ImageAddress; - uint32_t ImageOffsetX; - uint32_t ImageOffsetY; - }; + SUBTYPE_NET_NNNN = 0x0000, + }; - struct SRATHeader - { - ACPIHeader Header; - uint32_t TableRevision; // Must be value 1 - uint64_t Reserved; // Reserved, must be zero - }; + struct DBG2Device + { + uint8_t Revision; + uint16_t Length; + uint8_t NumberofGenericAddressRegisters; + uint16_t NamespaceStringLength; + uint16_t NamespaceStringOffset; + uint16_t OemDataLength; + uint16_t OemDataOffset; + uint16_t PortType; + uint16_t PortSubtype; + uint16_t Reserved; + uint16_t BaseAddressRegisterOffset; + uint16_t AddressSizeOffset; + /* BaseAddressRegister[NumberofGenericAddressRegisters * 12] at offset BaseAddressRegisterOffset */ + /* AddressSize[NumberofGenericAddressRegisters * 4] at offset AddressSizeOffset */ + /* NamespaceString[NamespaceStringLength] at offset NamespaceStringOffset */ + /* OemData[OemDataLength] at offset OemDataOffset */ + } __packed; - struct TPM2Header - { - ACPIHeader Header; - uint32_t Flags; - uint64_t ControlAddress; - uint32_t StartMethod; - }; + struct MCFGHeader + { + struct ACPIHeader Header; + uint64_t Reserved; + } __packed; - struct TCPAHeader - { - ACPIHeader Header; - uint16_t Reserved; - uint32_t MaxLogLength; - uint64_t LogAddress; - }; + 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 WAETHeader - { - ACPIHeader Header; - uint32_t Flags; - }; + 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 HESTHeader - { - ACPIHeader Header; - uint32_t ErrorSourceCount; - }; + struct BGRTHeader + { + ACPIHeader Header; + uint16_t Version; + uint8_t Status; + uint8_t ImageType; + uint64_t ImageAddress; + uint32_t ImageOffsetX; + uint32_t ImageOffsetY; + } __packed; - struct MADTHeader - { - ACPIHeader Header; - uint32_t LocalControllerAddress; - uint32_t Flags; - char Entries[]; - } __packed; + struct SRATHeader + { + ACPIHeader Header; + uint32_t TableRevision; // Must be value 1 + uint64_t Reserved; // Reserved, must be zero + } __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; + struct TPM2Header + { + ACPIHeader Header; + uint32_t Flags; + uint64_t ControlAddress; + uint32_t StartMethod; + } __packed; - void *FindTable(ACPIHeader *ACPIHeader, char *Signature); - void SearchTables(ACPIHeader *Header); - ACPI(); - ~ACPI(); - }; + struct TCPAHeader + { + ACPIHeader Header; + uint16_t Reserved; + uint32_t MaxLogLength; + uint64_t LogAddress; + } __packed; - class MADT - { - public: - struct APICHeader - { - uint8_t Type; - uint8_t Length; - } __packed; + struct WAETHeader + { + ACPIHeader Header; + uint32_t Flags; + } __packed; - struct MADTIOApic - { - struct APICHeader Header; - uint8_t APICID; - uint8_t reserved; - uint32_t Address; - uint32_t GSIBase; - } __packed; + struct HESTHeader + { + ACPIHeader Header; + uint32_t ErrorSourceCount; + } __packed; - struct MADTIso - { - struct APICHeader Header; - uint8_t BuSSource; - uint8_t IRQSource; - uint32_t GSI; - uint16_t Flags; - } __packed; + struct MADTHeader + { + ACPIHeader Header; + uint32_t LocalControllerAddress; + uint32_t Flags; + char Entries[]; + } __packed; - struct MADTNmi - { - struct APICHeader Header; - uint8_t processor; - uint16_t flags; - uint8_t lint; - } __packed; + struct SSDTHeader + { + ACPIHeader Header; + char DefinitionBlock[]; + } __packed; - struct LocalAPIC - { - struct APICHeader Header; - uint8_t ACPIProcessorId; - uint8_t APICId; - uint32_t Flags; - } __packed; + struct DBGPHeader + { + ACPIHeader Header; + /** + * 0 - 16550 compatible + * 1 - Subset of 16550 + */ + uint8_t InterfaceType; + uint8_t Reserved[3]; + GenericAddressStructure BaseAddress; + } __packed; - struct LAPIC - { - uint8_t id; - uintptr_t PhysicalAddress; - void *VirtualAddress; - }; + struct DBG2Header + { + ACPIHeader Header; + uint32_t OffsetDbgDeviceInfo; + uint32_t NumberDbgDeviceInfo; + /* DBG2Device[NumberDbgDeviceInfo] at offset OffsetDbgDeviceInfo */ + } __packed; - std::vector ioapic; - std::vector iso; - std::vector nmi; - std::vector lapic; - struct LAPIC *LAPICAddress; - uint16_t CPUCores; + 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; + SSDTHeader *SSDT = nullptr; + DBGPHeader *DBGP = nullptr; + DBG2Header *DBG2 = nullptr; + bool XSDTSupported = false; - MADT(ACPI::MADTHeader *madt); - ~MADT(); - }; + std::unordered_map Tables; - 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; + void *FindTable(ACPIHeader *ACPIHeader, char *Signature); + void SearchTables(ACPIHeader *Header); + ACPI(); + ~ACPI(); + }; - ACPI *acpi; -#if defined(a64) - void OnInterruptReceived(CPU::x64::TrapFrame *Frame); -#elif defined(a32) - void OnInterruptReceived(CPU::x32::TrapFrame *Frame); -#endif + class MADT + { + public: + struct APICHeader + { + uint8_t Type; + uint8_t Length; + } __packed; - public: - bool ACPIShutdownSupported = false; + struct MADTIOApic + { + struct APICHeader Header; + uint8_t APICID; + uint8_t reserved; + uint32_t Address; + uint32_t GSIBase; + } __packed; - void Reboot(); - void Shutdown(); + struct MADTIso + { + struct APICHeader Header; + uint8_t BuSSource; + uint8_t IRQSource; + uint32_t GSI; + uint16_t Flags; + } __packed; - DSDT(ACPI *acpi); - ~DSDT(); - }; + 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::TrapFrame *Frame); + + public: + bool ACPIShutdownSupported = false; + + void Reboot(); + void Shutdown(); + + DSDT(ACPI *acpi); + ~DSDT(); + }; } #endif // !__FENNIX_KERNEL_ACPI_H__ diff --git a/include/boot/protocol/multiboot.h b/include/boot/protocol/multiboot.h index 42dd7d3..4850401 100644 --- a/include/boot/protocol/multiboot.h +++ b/include/boot/protocol/multiboot.h @@ -38,7 +38,7 @@ /* Alignment of the multiboot info structure. */ #define MULTIBOOT_INFO_ALIGN 0x00000004 -/* Flags set in the ’flags’ member of the multiboot header. */ +/* Flags set in the 'flags' member of the multiboot header. */ /* Align all boot modules on i386 page (4KB) boundaries. */ #define MULTIBOOT_PAGE_ALIGN 0x00000001 @@ -52,7 +52,7 @@ /* This flag indicates the use of the address fields in the header. */ #define MULTIBOOT_AOUT_KLUDGE 0x00010000 -/* Flags to be set in the ’flags’ member of the multiboot info structure. */ +/* Flags to be set in the 'flags' member of the multiboot info structure. */ /* is there basic lower/upper memory information? */ #define MULTIBOOT_INFO_MEMORY 0x00000001 @@ -243,7 +243,7 @@ typedef struct multiboot_mmap_entry multiboot_memory_map_t; struct multiboot_mod_list { - /* the memory used goes from bytes ’mod_start’ to ’mod_end-1’ inclusive */ + /* the memory used goes from bytes 'mod_start' to 'mod_end-1' inclusive */ multiboot_uint32_t mod_start; multiboot_uint32_t mod_end; diff --git a/include/cargs.h b/include/cargs.h index ff0a481..eb3fcd7 100644 --- a/include/cargs.h +++ b/include/cargs.h @@ -63,122 +63,122 @@ extern "C" { #endif - /** - * An option is used to describe a flag/argument option submitted when the - * program is run. - */ - typedef struct cag_option - { - const char identifier; - const char *access_letters; - const char *access_name; - const char *value_name; - const char *description; - } cag_option; + /** + * An option is used to describe a flag/argument option submitted when the + * program is run. + */ + typedef struct cag_option + { + const char identifier; + const char *access_letters; + const char *access_name; + const char *value_name; + const char *description; + } cag_option; - /** - * A context is used to iterate over all options provided. It stores the parsing - * state. - */ - typedef struct cag_option_context - { - const struct cag_option *options; - size_t option_count; - int argc; - char **argv; - int index; - int inner_index; - bool forced_end; - char identifier; - char *value; - } cag_option_context; + /** + * A context is used to iterate over all options provided. It stores the parsing + * state. + */ + typedef struct cag_option_context + { + const struct cag_option *options; + size_t option_count; + int argc; + char **argv; + int index; + int inner_index; + bool forced_end; + char identifier; + char *value; + } cag_option_context; /** * This is just a small macro which calculates the size of an array. */ #define CAG_ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0])) - /** - * @brief Prints all options to the terminal. - * - * This function prints all options to the terminal. This can be used to - * generate the output for a "--help" option. - * - * @param options The options which will be printed. - * @param option_count The option count which will be printed. - * @param destination The destination where the output will be printed. - */ - CAG_PUBLIC void cag_option_print(const cag_option *options, size_t option_count, - FILE *destination); + /** + * @brief Prints all options to the terminal. + * + * This function prints all options to the terminal. This can be used to + * generate the output for a "--help" option. + * + * @param options The options which will be printed. + * @param option_count The option count which will be printed. + * @param destination The destination where the output will be printed. + */ + CAG_PUBLIC void cag_option_print(const cag_option *options, size_t option_count, + FILE *destination); - /** - * @brief Prepare argument options context for parsing. - * - * This function prepares the context for iteration and initializes the context - * with the supplied options and arguments. After the context has been prepared, - * it can be used to fetch arguments from it. - * - * @param context The context which will be initialized. - * @param options The registered options which are available for the program. - * @param option_count The amount of options which are available for the - * program. - * @param argc The amount of arguments the user supplied in the main function. - * @param argv A pointer to the arguments of the main function. - */ - CAG_PUBLIC void cag_option_prepare(cag_option_context *context, - const cag_option *options, size_t option_count, int argc, char **argv); + /** + * @brief Prepare argument options context for parsing. + * + * This function prepares the context for iteration and initializes the context + * with the supplied options and arguments. After the context has been prepared, + * it can be used to fetch arguments from it. + * + * @param context The context which will be initialized. + * @param options The registered options which are available for the program. + * @param option_count The amount of options which are available for the + * program. + * @param argc The amount of arguments the user supplied in the main function. + * @param argv A pointer to the arguments of the main function. + */ + CAG_PUBLIC void cag_option_prepare(cag_option_context *context, + const cag_option *options, size_t option_count, int argc, char **argv); - /** - * @brief Fetches an option from the argument list. - * - * This function fetches a single option from the argument list. The context - * will be moved to that item. Information can be extracted from the context - * after the item has been fetched. - * The arguments will be re-ordered, which means that non-option arguments will - * be moved to the end of the argument list. After all options have been - * fetched, all non-option arguments will be positioned after the index of - * the context. - * - * @param context The context from which we will fetch the option. - * @return Returns true if there was another option or false if the end is - * reached. - */ - CAG_PUBLIC bool cag_option_fetch(cag_option_context *context); + /** + * @brief Fetches an option from the argument list. + * + * This function fetches a single option from the argument list. The context + * will be moved to that item. Information can be extracted from the context + * after the item has been fetched. + * The arguments will be re-ordered, which means that non-option arguments will + * be moved to the end of the argument list. After all options have been + * fetched, all non-option arguments will be positioned after the index of + * the context. + * + * @param context The context from which we will fetch the option. + * @return Returns true if there was another option or false if the end is + * reached. + */ + CAG_PUBLIC bool cag_option_fetch(cag_option_context *context); - /** - * @brief Gets the identifier of the option. - * - * This function gets the identifier of the option, which should be unique to - * this option and can be used to determine what kind of option this is. - * - * @param context The context from which the option was fetched. - * @return Returns the identifier of the option. - */ - CAG_PUBLIC char cag_option_get(const cag_option_context *context); + /** + * @brief Gets the identifier of the option. + * + * This function gets the identifier of the option, which should be unique to + * this option and can be used to determine what kind of option this is. + * + * @param context The context from which the option was fetched. + * @return Returns the identifier of the option. + */ + CAG_PUBLIC char cag_option_get(const cag_option_context *context); - /** - * @brief Gets the value from the option. - * - * This function gets the value from the option, if any. If the option does not - * contain a value, this function will return NULL. - * - * @param context The context from which the option was fetched. - * @return Returns a pointer to the value or NULL if there is no value. - */ - CAG_PUBLIC const char *cag_option_get_value(const cag_option_context *context); + /** + * @brief Gets the value from the option. + * + * This function gets the value from the option, if any. If the option does not + * contain a value, this function will return NULL. + * + * @param context The context from which the option was fetched. + * @return Returns a pointer to the value or NULL if there is no value. + */ + CAG_PUBLIC const char *cag_option_get_value(const cag_option_context *context); - /** - * @brief Gets the current index of the context. - * - * This function gets the index within the argv arguments of the context. The - * context always points to the next item which it will inspect. This is - * particularly useful to inspect the original argument array, or to get - * non-option arguments after option fetching has finished. - * - * @param context The context from which the option was fetched. - * @return Returns the current index of the context. - */ - CAG_PUBLIC int cag_option_get_index(const cag_option_context *context); + /** + * @brief Gets the current index of the context. + * + * This function gets the index within the argv arguments of the context. The + * context always points to the next item which it will inspect. This is + * particularly useful to inspect the original argument array, or to get + * non-option arguments after option fetching has finished. + * + * @param context The context from which the option was fetched. + * @return Returns the current index of the context. + */ + CAG_PUBLIC int cag_option_get_index(const cag_option_context *context); #ifdef __cplusplus } // extern "C" diff --git a/include/convert.h b/include/convert.h index a37e19f..5f3cf0f 100644 --- a/include/convert.h +++ b/include/convert.h @@ -23,90 +23,99 @@ extern "C" { #endif - typedef struct mbstate_t - { - int count; - unsigned int value; - } mbstate_t; + typedef struct mbstate_t + { + int count; + unsigned int value; + } mbstate_t; #define NAN (__builtin_nanf("")) - int isdigit(int c); - int isspace(int c); - int isempty(char *str); - int isalpha(int c); - int isupper(int c); - unsigned int isdelim(char c, const char *delim); - long abs(long i); - void swap(char *x, char *y); - char *reverse(char *Buffer, int i, int j); + int isdigit(int c); + int isspace(int c); + int isempty(char *str); + int isalpha(int c); + int isupper(int c); + unsigned int isdelim(char c, const char *delim); + long abs(long i); + void swap(char *x, char *y); + char *reverse(char *Buffer, int i, int j); - float sqrtf(float x); - double clamp(double x, double low, double high); + float sqrtf(float x); + double clamp(double x, double low, double high); - float lerp(float a, float b, float t); - float smoothstep(float a, float b, float t); - float cubicInterpolate(float a, float b, float t); + float lerp(float a, float b, float t); + float smoothstep(float a, float b, float t); + float cubicInterpolate(float a, float b, float t); - void backspace(char s[]); - void append(char s[], char n); + void backspace(char s[]); + void append(char s[], char n); - int atoi(const char *String); - double atof(const char *String); - char *itoa(int Value, char *Buffer, int Base); - char *ltoa(long Value, char *Buffer, int Base); - char *ultoa(unsigned long Value, char *Buffer, int Base); - unsigned long int strtoul(const char *str, char **endptr, int base); + int atoi(const char *String); + double atof(const char *String); + char *itoa(int Value, char *Buffer, int Base); + char *ltoa(long Value, char *Buffer, int Base); + char *ultoa(unsigned long Value, char *Buffer, int Base); + unsigned long int strtoul(const char *str, char **endptr, int base); - void *memcpy_unsafe(void *dest, const void *src, size_t n); - void *memset_unsafe(void *dest, int c, size_t n); - void *memmove_unsafe(void *dest, const void *src, size_t n); - int memcmp(const void *vl, const void *vr, size_t n); + void *memcpy_unsafe(void *dest, const void *src, size_t n); + void *memset_unsafe(void *dest, int c, size_t n); + void *memmove_unsafe(void *dest, const void *src, size_t n); + int memcmp(const void *vl, const void *vr, size_t n); - void *memcpy_sse(void *dest, const void *src, size_t n); - void *memcpy_sse2(void *dest, const void *src, size_t n); - void *memcpy_sse3(void *dest, const void *src, size_t n); - void *memcpy_ssse3(void *dest, const void *src, size_t n); - void *memcpy_sse4_1(void *dest, const void *src, size_t n); - void *memcpy_sse4_2(void *dest, const void *src, size_t n); + void *memcpy_sse(void *dest, const void *src, size_t n); + void *memcpy_sse2(void *dest, const void *src, size_t n); + void *memcpy_sse3(void *dest, const void *src, size_t n); + void *memcpy_ssse3(void *dest, const void *src, size_t n); + void *memcpy_sse4_1(void *dest, const void *src, size_t n); + void *memcpy_sse4_2(void *dest, const void *src, size_t n); - void *memset_sse(void *dest, int c, size_t n); - void *memset_sse2(void *dest, int c, size_t n); - void *memset_sse3(void *dest, int c, size_t n); - void *memset_ssse3(void *dest, int c, size_t n); - void *memset_sse4_1(void *dest, int c, size_t n); - void *memset_sse4_2(void *dest, int c, size_t n); + void *memset_sse(void *dest, int c, size_t n); + void *memset_sse2(void *dest, int c, size_t n); + void *memset_sse3(void *dest, int c, size_t n); + void *memset_ssse3(void *dest, int c, size_t n); + void *memset_sse4_1(void *dest, int c, size_t n); + void *memset_sse4_2(void *dest, int c, size_t n); - void *memmove_sse(void *dest, const void *src, size_t n); - void *memmove_sse2(void *dest, const void *src, size_t n); - void *memmove_sse3(void *dest, const void *src, size_t n); - void *memmove_ssse3(void *dest, const void *src, size_t n); - void *memmove_sse4_1(void *dest, const void *src, size_t n); - void *memmove_sse4_2(void *dest, const void *src, size_t n); + void *memmove_sse(void *dest, const void *src, size_t n); + void *memmove_sse2(void *dest, const void *src, size_t n); + void *memmove_sse3(void *dest, const void *src, size_t n); + void *memmove_ssse3(void *dest, const void *src, size_t n); + void *memmove_sse4_1(void *dest, const void *src, size_t n); + void *memmove_sse4_2(void *dest, const void *src, size_t n); - long unsigned strlen(const char s[]); - int strncmp(const char *s1, const char *s2, unsigned long n); - char *strcat_unsafe(char *destination, const char *source); - char *strcpy_unsafe(char *destination, const char *source); - char *strncpy(char *destination, const char *source, unsigned long num); - int strcmp(const char *l, const char *r); - char *strstr(const char *haystack, const char *needle); - char *strdup(const char *String); - char *strchr(const char *String, int Char); - char *strrchr(const char *String, int Char); - int strncasecmp(const char *lhs, const char *rhs, long unsigned int Count); - int strcasecmp(const char *s1, const char *s2); - char *strtok(char *src, const char *delim); - long int strtol(const char *str, char **endptr, int base); - size_t wcslen(const wchar_t *s); - size_t wcsrtombs(char *dst, const wchar_t **src, size_t len, mbstate_t *ps); - int log2(unsigned int n); + long unsigned __strlen(const char s[]); - void *__memcpy_chk(void *dest, const void *src, size_t len, size_t slen); - void *__memset_chk(void *dest, int val, size_t len, size_t slen); - void *__memmove_chk(void *dest, const void *src, size_t len, size_t slen); - char *__strcat_chk(char *dest, const char *src, size_t slen); - char *__strcpy_chk(char *dest, const char *src, size_t slen); + long unsigned strlen_sse(const char s[]); + long unsigned strlen_sse2(const char s[]); + long unsigned strlen_sse3(const char s[]); + long unsigned strlen_ssse3(const char s[]); + long unsigned strlen_sse4_1(const char s[]); + long unsigned strlen_sse4_2(const char s[]); + + long unsigned strlen(const char s[]); + int strncmp(const char *s1, const char *s2, unsigned long n); + char *strcat_unsafe(char *destination, const char *source); + char *strcpy_unsafe(char *destination, const char *source); + char *strncpy(char *destination, const char *source, unsigned long num); + int strcmp(const char *l, const char *r); + char *strstr(const char *haystack, const char *needle); + char *strdup(const char *String); + char *strchr(const char *String, int Char); + char *strrchr(const char *String, int Char); + int strncasecmp(const char *string1, const char *string2, size_t count); + int strcasecmp(const char *s1, const char *s2); + char *strtok(char *src, const char *delim); + long int strtol(const char *str, char **endptr, int base); + size_t wcslen(const wchar_t *s); + size_t wcsrtombs(char *dst, const wchar_t **src, size_t len, mbstate_t *ps); + int log2(unsigned int n); + + void *__memcpy_chk(void *dest, const void *src, size_t len, size_t slen); + void *__memset_chk(void *dest, int val, size_t len, size_t slen); + void *__memmove_chk(void *dest, const void *src, size_t len, size_t slen); + char *__strcat_chk(char *dest, const char *src, size_t slen); + char *__strcpy_chk(char *dest, const char *src, size_t slen); #ifdef __cplusplus } @@ -114,20 +123,20 @@ extern "C" #undef memcpy #define memcpy(dest, src, n) \ - __memcpy_chk(dest, src, n, __builtin_object_size(dest, 0)) + __memcpy_chk(dest, src, n, __builtin_object_size(dest, 0)) #undef memset #define memset(dest, c, n) \ - __memset_chk(dest, c, n, __builtin_object_size(dest, 0)) + __memset_chk(dest, c, n, __builtin_object_size(dest, 0)) #undef memmove #define memmove(dest, src, n) \ - __memmove_chk(dest, src, n, __builtin_object_size(dest, 0)) + __memmove_chk(dest, src, n, __builtin_object_size(dest, 0)) #undef strcat #define strcat(dest, src) \ - __strcat_chk(dest, src, __builtin_object_size(dest, 0)) + __strcat_chk(dest, src, __builtin_object_size(dest, 0)) #undef strcpy #define strcpy(dest, src) \ - __strcpy_chk(dest, src, __builtin_object_size(dest, 0)) + __strcpy_chk(dest, src, __builtin_object_size(dest, 0)) diff --git a/include/cpu.hpp b/include/cpu.hpp index a6fed5c..ce729c9 100644 --- a/include/cpu.hpp +++ b/include/cpu.hpp @@ -161,7 +161,7 @@ namespace CPU "cli\n" "hlt\n" "jmp CPUStopLoop"); -#elif defined(aa64) // annoying warning: "‘noreturn’ function does return" and "‘naked’ attribute directive ignored" +#elif defined(aa64) // annoying warning: "'noreturn' function does return" and "'naked' attribute directive ignored" SafeFunction __used inline void Stop() { asmv("CPUStopLoop:\n" @@ -198,10 +198,13 @@ namespace CPU * @brief Get/Set the CPU's page table * * @param PT The new page table, if empty, the current page table will be returned - * @return void* The current page table + * @return Get: The current page table + * @return Set: The old page table */ void *PageTable(void *PT = nullptr); +#define thisPageTable (Memory::PageTable *)CPU::PageTable() + /** @brief To be used only once. */ void InitializeFeatures(int Core); @@ -826,7 +829,7 @@ namespace CPU uint8_t st[8][16]; /** @brief XMM registers */ uint8_t xmm[16][16]; - } __packed; + } __packed __aligned(16); SafeFunction static inline void lgdt(void *gdt) { @@ -950,6 +953,29 @@ namespace CPU uint64_t InterruptNumber /* iar_el1 */; // Interrupt Acknowledge Register } TrapFrame; } + +#if defined(a64) + /** + * CPU trap frame for the current architecture + * + * @note This is for x86_64 + */ + typedef x64::TrapFrame TrapFrame; +#elif defined(a32) + /** + * CPU trap frame for the current architecture + * + * @note This is for x86_32 + */ + typedef x32::TrapFrame TrapFrame; +#elif defined(aa64) +/** + * CPU trap frame for the current architecture + * + * @note This is for aarch64 + */ +typedef aarch64::TrapFrame TrapFrame; +#endif } #endif // !__FENNIX_KERNEL_CPU_H__ diff --git a/include/cpu/x86/interrupts.hpp b/include/cpu/x86/interrupts.hpp index 5e6f90e..bc0ac10 100644 --- a/include/cpu/x86/interrupts.hpp +++ b/include/cpu/x86/interrupts.hpp @@ -1,18 +1,18 @@ /* - This file is part of Fennix Kernel. + 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 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. + 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 . + You should have received a copy of the GNU General Public License + along with Fennix Kernel. If not, see . */ #ifndef __FENNIX_KERNEL_CPU_x86_INTERRUPTS_H__ @@ -82,7 +82,7 @@ namespace CPU /* Reserved by OS */ - IRQ16 = 0x30, // Reserved for multitasking + IRQ16 = 0x30, /* Reserved for multitasking */ IRQ17 = 0x31, IRQ18 = 0x32, IRQ19 = 0x33, @@ -95,12 +95,11 @@ namespace CPU IRQ26 = 0x3a, IRQ27 = 0x3b, IRQ28 = 0x3c, - IRQ29 = 0x3d, // Reserved for icr stop core + IRQ29 = 0x3d, + IRQ30 = 0x3e, + IRQ31 = 0x3f, /* Halt core interrupt */ /* Free */ - - IRQ30 = 0x3e, - IRQ31 = 0x3f, IRQ32 = 0x40, IRQ33 = 0x41, IRQ34 = 0x42, diff --git a/include/debug.h b/include/debug.h index 4ca0970..4d6ce79 100644 --- a/include/debug.h +++ b/include/debug.h @@ -117,4 +117,6 @@ void SysDbgLockedWriteLine(enum DebugLevel Level, const char *File, int Line, co #endif // __cplusplus +EXTERNC void uart_wrapper(char c, void *unused); + #endif // !__FENNIX_KERNEL_DEBUGGER_H__ diff --git a/include/driver.hpp b/include/driver.hpp new file mode 100644 index 0000000..b5bdc0c --- /dev/null +++ b/include/driver.hpp @@ -0,0 +1,208 @@ +/* + 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_DRIVER_H__ +#define __FENNIX_KERNEL_DRIVER_H__ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace Driver +{ + char GetScanCode(uint8_t ScanCode, bool Upper); + bool IsValidChar(uint8_t ScanCode); + + class SlaveDeviceFile : public vfs::Node + { + private: + int /* DeviceDriverType */ DeviceType; + + std::list KeyQueue; + + public: + typedef int (*drvOpen_t)(dev_t, dev_t, int, mode_t); + typedef int (*drvClose_t)(dev_t, dev_t); + typedef size_t (*drvRead_t)(dev_t, dev_t, uint8_t *, size_t, off_t); + typedef size_t (*drvWrite_t)(dev_t, dev_t, uint8_t *, size_t, off_t); + typedef int (*drvIoctl_t)(dev_t, dev_t, unsigned long, void *); + + drvOpen_t Open; + drvClose_t Close; + drvRead_t Read; + drvWrite_t Write; + drvIoctl_t Ioctl; + + int open(int Flags, mode_t Mode) final; + int close() final; + size_t read(uint8_t *Buffer, + size_t Size, + off_t Offset) final; + size_t write(uint8_t *Buffer, + size_t Size, + off_t Offset) final; + int ioctl(unsigned long Request, + void *Argp) final; + + void ClearBuffers(); + + int ReportKeyEvent(uint8_t ScanCode); + + SlaveDeviceFile(const char *Name, vfs::Node *Parent, int Type, vfs::NodeType NType); + ~SlaveDeviceFile(); + }; + + class MasterDeviceFile : private vfs::Node + { + private: + typedef dev_t maj_t; + typedef dev_t min_t; + char SlaveName[16]; + vfs::Node *SlaveParent; + int /* DeviceDriverType */ DeviceType; + min_t SlaveIDCounter = 0; + + typedef std::unordered_map *Slaves; + std::unordered_map SlavesMap; + + std::list RawKeyQueue; + std::list KeyQueue; + bool UpperCase = false; + bool CapsLock = false; + + public: + typedef int (*drvOpen_t)(dev_t, dev_t, int, mode_t); + typedef int (*drvClose_t)(dev_t, dev_t); + typedef size_t (*drvRead_t)(dev_t, dev_t, uint8_t *, size_t, off_t); + typedef size_t (*drvWrite_t)(dev_t, dev_t, uint8_t *, size_t, off_t); + typedef int (*drvIoctl_t)(dev_t, dev_t, unsigned long, void *); + + int open(int Flags, mode_t Mode) final; + int close() final; + size_t read(uint8_t *Buffer, + size_t Size, + off_t Offset) final; + size_t write(uint8_t *Buffer, + size_t Size, + off_t Offset) final; + int ioctl(unsigned long Request, + void *Argp) final; + + void ClearBuffers(); + + int ReportKeyEvent(maj_t ID, min_t MinorID, uint8_t ScanCode); + int ReportMouseEvent(maj_t ID, min_t MinorID, + bool LeftButton, bool RightButton, bool MiddleButton, + bool Button4, bool Button5, bool Button6, + bool Button7, bool Button8, + uintptr_t X, uintptr_t Y, int8_t Z, bool Relative); + + int ReportNetworkPacket(maj_t ID, min_t MinorID, void *Buffer, size_t Size); + + int NewBlock(maj_t ID, min_t MinorID, drvOpen_t Open, drvClose_t Close, + drvRead_t Read, drvWrite_t Write, drvIoctl_t Ioctl); + + int NewAudio(maj_t ID, min_t MinorID, drvOpen_t Open, drvClose_t Close, + drvRead_t Read, drvWrite_t Write, drvIoctl_t Ioctl); + + int NewNet(maj_t ID, min_t MinorID, drvOpen_t Open, drvClose_t Close, + drvRead_t Read, drvWrite_t Write, drvIoctl_t Ioctl); + + dev_t Register(maj_t ID); + int Unregister(maj_t ID, min_t MinorID); + + MasterDeviceFile(const char *MasterName, + const char *SlaveName, + vfs::Node *Parent, + int Type); + ~MasterDeviceFile(); + }; + + struct DriverObject + { + uintptr_t BaseAddress = 0; + uintptr_t EntryPoint = 0; + Memory::VirtualMemoryArea *vma = nullptr; + + /* Path has the same pointer as in the Node */ + const char *Path = nullptr; + std::unordered_map *InterruptHandlers; + + char Name[32] = {'\0'}; + char Description[64] = {'\0'}; + char Author[32] = {'\0'}; + char Version[16] = {'\0'}; + char License[32] = {'\0'}; + bool Initialized = false; + int ErrorCode = 0; + + int (*Entry)() = nullptr; + int (*Final)() = nullptr; + int (*Panic)() = nullptr; + int (*Probe)() = nullptr; + }; + + class Manager + { + private: + NewLock(ModuleInitLock); + std::unordered_map Drivers; + dev_t MajorIDCounter = 0; + + int LoadDriverFile(uintptr_t &EntryPoint, + uintptr_t &BaseAddress, + Memory::VirtualMemoryArea *dVma, + vfs::RefNode *rDrv); + + public: + MasterDeviceFile *InputMouseDev = nullptr; + MasterDeviceFile *InputKeyboardDev = nullptr; + + MasterDeviceFile *BlockSATADev = nullptr; + MasterDeviceFile *BlockHDDev = nullptr; + MasterDeviceFile *BlockNVMeDev = nullptr; + + MasterDeviceFile *AudioDev = nullptr; + + MasterDeviceFile *NetDev = nullptr; + + std::unordered_map & + GetDrivers() { return Drivers; } + + void LoadAllDrivers(); + void UnloadAllDrivers(); + void Panic(); + + Manager(); + ~Manager(); + }; + + void PopulateDriverAPI(void *API); +} + +#endif // !__FENNIX_KERNEL_DRIVER_H__ diff --git a/include/elf.h b/include/elf.h index 300fd4b..6e86f09 100644 --- a/include/elf.h +++ b/include/elf.h @@ -26,6 +26,7 @@ typedef uint16_t Elf32_Half; typedef uint32_t Elf32_Off; typedef int32_t Elf32_Sword; typedef uint32_t Elf32_Word; +typedef Elf32_Sword Elf32_pid_t; /* 64-bit ELF base types. */ typedef uint64_t Elf64_Addr; @@ -36,6 +37,11 @@ typedef int32_t Elf64_Sword; typedef uint32_t Elf64_Word; typedef uint64_t Elf64_Xword; typedef int64_t Elf64_Sxword; +typedef Elf64_Sword Elf64_pid_t; + +#define ELF_NGREG 23 +typedef Elf32_Word Elf32_greg_t[ELF_NGREG]; +typedef Elf64_Xword Elf64_greg_t[ELF_NGREG]; enum IdentificationIndex { @@ -227,8 +233,6 @@ enum SegmentTypes PT_TLS = 7, PT_LOPROC = 0x70000000, PT_HIPROC = 0x7fffffff, - PT_GNU_EH_FRAME = 0x6474e550, - PT_GNU_STACK = 0x6474e551, }; enum DynamicArrayTags @@ -305,15 +309,15 @@ enum DynamicArrayTags /* Used for Elf64_Sym st_info */ #define ELF32_ST_BIND(info) ((info) >> 4) -#define ELF32_ST_TYPE(info) ((info)&0xf) -#define ELF32_ST_INFO(bind, type) (((bind) << 4) + ((type)&0xf)) +#define ELF32_ST_TYPE(info) ((info) & 0xf) +#define ELF32_ST_INFO(bind, type) (((bind) << 4) + ((type) & 0xf)) #define ELF64_ST_BIND(info) ((info) >> 4) -#define ELF64_ST_TYPE(info) ((info)&0xf) -#define ELF64_ST_INFO(bind, type) (((bind) << 4) + ((type)&0xf)) +#define ELF64_ST_TYPE(info) ((info) & 0xf) +#define ELF64_ST_INFO(bind, type) (((bind) << 4) + ((type) & 0xf)) /* Used for Elf64_Sym st_other */ -#define ELF32_ST_VISIBILITY(o) ((o)&0x3) -#define ELF64_ST_VISIBILITY(o) ((o)&0x3) +#define ELF32_ST_VISIBILITY(o) ((o) & 0x3) +#define ELF64_ST_VISIBILITY(o) ((o) & 0x3) #define DO_386_32(S, A) ((S) + (A)) #define DO_386_PC32(S, A, P) ((S) + (A) - (P)) @@ -326,8 +330,8 @@ enum DynamicArrayTags #define ELF32_R_INFO(s, t) (((s) << 8) + (unsigned char)(t)) #define ELF64_R_SYM(i) ((i) >> 32) -#define ELF64_R_TYPE(i) ((i)&0xffffffffL) -#define ELF64_R_INFO(s, t) (((s) << 32) + ((t)&0xffffffffL)) +#define ELF64_R_TYPE(i) ((i) & 0xffffffffL) +#define ELF64_R_INFO(s, t) (((s) << 32) + ((t) & 0xffffffffL)) #define SHN_UNDEF 0 #define SHN_ABS 0xfff1 @@ -576,6 +580,80 @@ enum SpecialSections SHT_HIUSER = 0x8fffffff }; +#define NT_PRSTATUS 1 +#define NT_PRFPREG 2 +#define NT_FPREGSET 2 +#define NT_PRPSINFO 3 +#define NT_PRXREG 4 +#define NT_TASKSTRUCT 4 +#define NT_PLATFORM 5 +#define NT_AUXV 6 +#define NT_GWINDOWS 7 +#define NT_ASRS 8 +#define NT_PSTATUS 10 +#define NT_PSINFO 13 +#define NT_PRCRED 14 +#define NT_UTSNAME 15 +#define NT_LWPSTATUS 16 +#define NT_LWPSINFO 17 +#define NT_PRFPXREG 20 +#define NT_SIGINFO 0x53494749 +#define NT_FILE 0x46494c45 +#define NT_PRXFPREG 0x46e62b7f +#define NT_PPC_VMX 0x100 +#define NT_PPC_SPE 0x101 +#define NT_PPC_VSX 0x102 +#define NT_PPC_TAR 0x103 +#define NT_PPC_PPR 0x104 +#define NT_PPC_DSCR 0x105 +#define NT_PPC_EBB 0x106 +#define NT_PPC_PMU 0x107 +#define NT_PPC_TM_CGPR 0x108 +#define NT_PPC_TM_CFPR 0x109 +#define NT_PPC_TM_CVMX 0x10a +#define NT_PPC_TM_CVSX 0x10b +#define NT_PPC_TM_SPR 0x10c +#define NT_PPC_TM_CTAR 0x10d +#define NT_PPC_TM_CPPR 0x10e +#define NT_PPC_TM_CDSCR 0x10f +#define NT_386_TLS 0x200 +#define NT_386_IOPERM 0x201 +#define NT_X86_XSTATE 0x202 +#define NT_S390_HIGH_GPRS 0x300 +#define NT_S390_TIMER 0x301 +#define NT_S390_TODCMP 0x302 +#define NT_S390_TODPREG 0x303 +#define NT_S390_CTRS 0x304 +#define NT_S390_PREFIX 0x305 +#define NT_S390_LAST_BREAK 0x306 +#define NT_S390_SYSTEM_CALL 0x307 +#define NT_S390_TDB 0x308 +#define NT_S390_VXRS_LOW 0x309 +#define NT_S390_VXRS_HIGH 0x30a +#define NT_S390_GS_CB 0x30b +#define NT_S390_GS_BC 0x30c +#define NT_S390_RI_CB 0x30d +#define NT_ARM_VFP 0x400 +#define NT_ARM_TLS 0x401 +#define NT_ARM_HW_BREAK 0x402 +#define NT_ARM_HW_WATCH 0x403 +#define NT_ARM_SYSTEM_CALL 0x404 +#define NT_ARM_SVE 0x405 +#define NT_ARM_PAC_MASK 0x406 +#define NT_ARM_PACA_KEYS 0x407 +#define NT_ARM_PACG_KEYS 0x408 +#define NT_ARM_TAGGED_ADDR_CTRL 0x409 +#define NT_ARM_PAC_ENABLED_KEYS 0x40a +#define NT_METAG_CBUF 0x500 +#define NT_METAG_RPIPE 0x501 +#define NT_METAG_TLS 0x502 +#define NT_ARC_V2 0x600 +#define NT_VMCOREDD 0x700 +#define NT_MIPS_DSP 0x800 +#define NT_MIPS_FP_MODE 0x801 +#define NT_MIPS_MSA 0x802 +#define NT_VERSION 1 + typedef struct elf32_hdr { unsigned char e_ident[EI_NIDENT]; @@ -730,6 +808,117 @@ typedef struct Elf64_Sxword r_addend; } Elf64_Rela; +struct Elf32_Nhdr +{ + Elf32_Word n_namesz; + Elf32_Word n_descsz; + Elf32_Word n_type; +}; + +struct Elf64_Nhdr +{ + Elf64_Word n_namesz; + Elf64_Word n_descsz; + Elf64_Word n_type; +}; + +typedef struct +{ + Elf32_Sword si_signo; + Elf32_Sword si_code; + Elf32_Sword si_errno; +} Elf32_Siginfo; + +typedef struct +{ + Elf64_Sword si_signo; + Elf64_Sword si_code; + Elf64_Sword si_errno; +} Elf64_Siginfo; + +typedef struct +{ + Elf32_Sword tv_sec; + Elf32_Sword tv_usec; +} Elf32_Prtimeval; + +typedef struct +{ + Elf64_Sxword tv_sec; + Elf64_Sxword tv_usec; +} Elf64_Prtimeval; + +typedef struct +{ + Elf32_Siginfo pr_info; + Elf32_Half pr_cursig; + Elf32_Word pr_sigpend; + Elf32_Word pr_sighold; + Elf32_pid_t pr_pid; + Elf32_pid_t pr_ppid; + Elf32_pid_t pr_pgrp; + Elf32_pid_t pr_sid; + Elf32_Prtimeval pr_utime; + Elf32_Prtimeval pr_stime; + Elf32_Prtimeval pr_cutime; + Elf32_Prtimeval pr_cstime; + Elf32_greg_t pr_reg; + Elf32_Word pr_fpvalid; +} Elf32_Prstatus; + +typedef struct +{ + Elf64_Siginfo pr_info; + Elf64_Half pr_cursig; + Elf64_Word pr_sigpend; + Elf64_Word pr_sighold; + Elf64_pid_t pr_pid; + Elf64_pid_t pr_ppid; + Elf64_pid_t pr_pgrp; + Elf64_pid_t pr_sid; + Elf64_Prtimeval pr_utime; + Elf64_Prtimeval pr_stime; + Elf64_Prtimeval pr_cutime; + Elf64_Prtimeval pr_cstime; + Elf64_greg_t pr_reg; + Elf64_Word pr_fpvalid; +} Elf64_Prstatus; + +#define ELF_PRARGSZ 80 +typedef struct +{ + char pr_state; + char pr_sname; + char pr_zomb; + char pr_nice; + Elf32_Word pr_flag; + Elf32_Half pr_uid; + Elf32_Half pr_gid; + Elf32_pid_t pr_pid; + Elf32_pid_t pr_ppid; + Elf32_pid_t pr_pgrp; + Elf32_pid_t pr_sid; + char pr_fname[16]; + char pr_psargs[ELF_PRARGSZ]; +} Elf32_Prpsinfo; + +typedef struct +{ + char pr_state; + char pr_sname; + char pr_zomb; + char pr_nice; + Elf64_Xword pr_flag; + Elf64_Half pr_uid; + Elf64_Half pr_gid; + Elf64_pid_t pr_pid; + Elf64_pid_t pr_ppid; + Elf64_pid_t pr_pgrp; + Elf64_pid_t pr_sid; + char pr_fname[16]; + char pr_psargs[ELF_PRARGSZ]; +} Elf64_Prpsinfo; + #if defined(a64) || defined(aa64) typedef Elf64_Addr Elf_Addr; typedef Elf64_Half Elf_Half; diff --git a/include/exec.hpp b/include/exec.hpp index 5255ba8..fa56bb9 100644 --- a/include/exec.hpp +++ b/include/exec.hpp @@ -32,7 +32,6 @@ namespace Execute enum BinaryType : int { BinTypeInvalid, - BinTypeFex, BinTypeELF, BinTypePE, BinTypeNE, @@ -122,7 +121,7 @@ namespace Execute BinaryType GetBinaryType(const char *Path); int Spawn(char *Path, const char **argv, const char **envp, - Tasking::PCB *Parent = nullptr, + Tasking::PCB *Parent = nullptr, bool Fork = false, Tasking::TaskCompatibility Compatibility = Tasking::TaskCompatibility::Native, bool Critical = false); diff --git a/include/filesystem.hpp b/include/filesystem.hpp index 902fff9..f0e6c96 100644 --- a/include/filesystem.hpp +++ b/include/filesystem.hpp @@ -84,40 +84,81 @@ #define S_ISLNK(mode) (((mode) & S_IFMT) == S_IFLNK) #define S_ISSOCK(mode) (((mode) & S_IFMT) == S_IFSOCK) +/** + * @struct stat + * @brief Structure holding information about a file, as returned by the stat function. + * + * The 'stat' structure provides information about a file, including its size, ownership, permissions, + * and other attributes. It is used with the stat function to query file status. + */ struct stat { + /** Device ID of the file. */ dev_t st_dev; + /** Inode number. */ ino_t st_ino; + /** File type and mode. */ mode_t st_mode; + /** Number of hard links. */ nlink_t st_nlink; - + /** User ID of the file's owner. */ uid_t st_uid; + /** Group ID of the file's owner. */ gid_t st_gid; + /** Device ID for special files. */ dev_t st_rdev; + /** Size of the file in bytes. */ off_t st_size; + /** Time of last access. */ time_t st_atime; + /** Time of last modification. */ time_t st_mtime; + /** Time of last status change. */ time_t st_ctime; + /** Optimal I/O block size. */ blksize_t st_blksize; + /** Number of blocks allocated. */ blkcnt_t st_blocks; + /** Additional file attributes. */ mode_t st_attr; }; +/** + * @struct stat64 + * @brief Extended structure for large file support, holding information about a file. + * + * The 'stat64' structure is similar to 'struct stat' but is extended to support large files on 32-bit systems. + * It is used with the stat64 function for large file support. + */ struct stat64 { + /** Device ID of the file. */ dev_t st_dev; + /** Inode number. */ ino64_t st_ino; + /** File type and mode. */ mode_t st_mode; + /** Number of hard links. */ nlink_t st_nlink; + /** User ID of the file's owner. */ uid_t st_uid; + /** Group ID of the file's owner. */ gid_t st_gid; + /** Device ID for special files. */ dev_t st_rdev; + /** Size of the file in bytes. */ off64_t st_size; + /** Time of last access. */ time_t st_atime; + /** Time of last modification. */ time_t st_mtime; + /** Time of last status change. */ time_t st_ctime; + /** Optimal I/O block size. */ blksize_t st_blksize; + /** Number of blocks allocated. */ blkcnt64_t st_blocks; + /** Additional file attributes. */ mode_t st_attr; }; @@ -165,6 +206,12 @@ namespace vfs }; class RefNode; + + /** + * Virtual filesystem node + * + * @note https://isocpp.org/wiki/faq/freestore-mgmt#delete-this + */ class Node { private: @@ -173,15 +220,35 @@ namespace vfs public: virtual int open(int Flags, mode_t Mode); virtual int close(); - virtual size_t read(uint8_t *Buffer, - size_t Size, - off_t Offset); - virtual size_t write(uint8_t *Buffer, - size_t Size, - off_t Offset); - virtual int ioctl(unsigned long Request, - void *Argp); - virtual ~Node(); + virtual size_t read(uint8_t *Buffer, size_t Size, off_t Offset); + virtual size_t write(uint8_t *Buffer, size_t Size, off_t Offset); + virtual int ioctl(unsigned long Request, void *Argp); + // virtual int stat(struct stat *Stat); + // virtual int lstat(struct stat *Stat); + // virtual int fstat(struct stat *Stat); + // virtual int unlink(); + // virtual int mkdir(mode_t Mode); + // virtual int rmdir(); + // virtual int rename(const char *NewName); + // virtual int chmod(mode_t Mode); + // virtual int chown(uid_t User, gid_t Group); + // virtual int truncate(off_t Size); + // virtual int symlink(const char *Target); + // virtual int readlink(char *Buffer, size_t Size); + // virtual int mount(Node *Target); + // virtual int umount(); + + typedef int (*open_t)(int, mode_t); + typedef int (*close_t)(); + typedef size_t (*read_t)(uint8_t *, size_t, off_t); + typedef size_t (*write_t)(uint8_t *, size_t, off_t); + typedef int (*ioctl_t)(unsigned long, void *); + + open_t open_ptr = nullptr; + close_t close_ptr = nullptr; + read_t read_ptr = nullptr; + write_t write_ptr = nullptr; + ioctl_t ioctl_ptr = nullptr; class Virtual *vFS = nullptr; Node *Parent = nullptr; @@ -211,21 +278,13 @@ namespace vfs RefNode *CreateReference(); void RemoveReference(RefNode *Reference); - /** - * Delete all children of this node - * - * @note The function will self-delete - * if there are no errors. - */ - int Delete(bool Recursive = false); - /** * Create a new node * * @param Parent The parent node * @param Name The name of the node * @param Type The type of the node - * @param NoParent If true, the @param Parent will + * @param NoParent If true, the Parent will * be used as a hint for the parent node, but it * won't be set as the parent node. * @param fs The virtual filesystem (only if @@ -239,6 +298,8 @@ namespace vfs bool NoParent = false, Virtual *fs = nullptr, int *Err = nullptr); + + virtual ~Node(); }; class RefNode @@ -250,6 +311,8 @@ namespace vfs RefNode *SymlinkTo; public: + void *SpecialData; + decltype(FileSize) &Size = FileSize; decltype(n) &node = n; @@ -287,6 +350,7 @@ namespace vfs bool PathExists(const char *Path, Node *Parent = nullptr); Node *Create(const char *Path, NodeType Type, Node *Parent = nullptr); + Node *CreateLink(const char *Path, const char *Target, Node *Parent); int Delete(const char *Path, bool Recursive = false, Node *Parent = nullptr); int Delete(Node *Path, bool Recursive = false, Node *Parent = nullptr); @@ -299,6 +363,8 @@ namespace vfs */ RefNode *Open(const char *Path, Node *Parent = nullptr); + Node *CreateIfNotExists(const char *Path, NodeType Type, Node *Parent); + Virtual(); ~Virtual(); @@ -310,27 +376,32 @@ namespace vfs public: struct Fildes { - RefNode *Handle{}; + RefNode *Handle = nullptr; mode_t Mode = 0; int Flags = 0; int Descriptor = -1; - }; - struct DupFildes - { - RefNode *Handle{}; - mode_t Mode = 0; - int Flags = 0; - int Descriptor = -1; - }; + int operator==(const Fildes &other) + { + return this->Handle == other.Handle && + this->Mode == other.Mode && + this->Flags == other.Flags && + this->Descriptor == other.Descriptor; + } + + int operator!=(const Fildes &other) + { + return !(*this == other); + } + } __attribute__((packed)) nullfd; private: std::vector FileDescriptors; - std::vector FildesDuplicates; + std::vector FildesDuplicates; vfs::Node *fdDir = nullptr; - Fildes GetFileDescriptor(int FileDescriptor); - FileDescriptorTable::DupFildes GetDupFildes(int FileDescriptor); + Fildes &GetFileDescriptor(int FileDescriptor); + FileDescriptorTable::Fildes &GetDupFildes(int FileDescriptor); int ProbeMode(mode_t Mode, int Flags); int AddFileDescriptor(const char *AbsolutePath, mode_t Mode, int Flags); @@ -338,8 +409,14 @@ namespace vfs int GetFreeFileDescriptor(); public: + Fildes &GetDescriptor(int FileDescriptor); const char *GetAbsolutePath(int FileDescriptor); std::vector &GetFileDescriptors() { return FileDescriptors; } + std::vector &GetFileDescriptorsDuplicates() { return FildesDuplicates; } + RefNode *GetRefNode(int FileDescriptor); + int GetFlags(int FileDescriptor); + int SetFlags(int FileDescriptor, int Flags); + void Fork(FileDescriptorTable *Parent); int _open(const char *pathname, int flags, mode_t mode); int _creat(const char *pathname, mode_t mode); diff --git a/include/filesystem/ext2.hpp b/include/filesystem/ext2.hpp index dab2360..830abe6 100644 --- a/include/filesystem/ext2.hpp +++ b/include/filesystem/ext2.hpp @@ -24,68 +24,68 @@ namespace vfs { - class EXT2 - { - public: - struct SuperBlock - { - uint32_t Inodes; - uint32_t Blocks; - uint32_t ReservedBlocks; - uint32_t FreeBlock; - uint32_t FreeInodes; - uint32_t FirstDataBlock; - uint32_t LogBlockSize; - uint32_t LogFragSize; - uint32_t BlocksPerGroup; - uint32_t FragsPerGroup; - uint32_t InodesPerGroup; - uint32_t LastMountTime; - uint32_t LastWrittenTime; - uint16_t MountedTimes; - uint16_t MaximumMountedTimes; - uint16_t Magic; - uint16_t State; - uint16_t Errors; - uint16_t MinorRevLevel; - uint32_t LastCheck; - uint32_t CheckInternval; - uint32_t SystemID; - uint32_t RevLevel; - uint16_t ReservedBlocksUserID; - uint16_t ReservedBlocksGroupID; + class EXT2 + { + public: + struct SuperBlock + { + uint32_t Inodes; + uint32_t Blocks; + uint32_t ReservedBlocks; + uint32_t FreeBlock; + uint32_t FreeInodes; + uint32_t FirstDataBlock; + uint32_t LogBlockSize; + uint32_t LogFragSize; + uint32_t BlocksPerGroup; + uint32_t FragsPerGroup; + uint32_t InodesPerGroup; + uint32_t LastMountTime; + uint32_t LastWrittenTime; + uint16_t MountedTimes; + uint16_t MaximumMountedTimes; + uint16_t Magic; + uint16_t State; + uint16_t Errors; + uint16_t MinorRevLevel; + uint32_t LastCheck; + uint32_t CheckInternval; + uint32_t SystemID; + uint32_t RevLevel; + uint16_t ReservedBlocksUserID; + uint16_t ReservedBlocksGroupID; - uint32_t FirstInode; - uint16_t InodeSize; - uint16_t BlockGroups; - uint32_t FeatureCompatibility; - uint32_t FeatureIncompatibility; - uint32_t FeatureRoCompatibility; - uint8_t UUID[16]; - char VolumeName[16]; - char LastMounted[64]; - uint32_t BitmapAlogrithm; + uint32_t FirstInode; + uint16_t InodeSize; + uint16_t BlockGroups; + uint32_t FeatureCompatibility; + uint32_t FeatureIncompatibility; + uint32_t FeatureRoCompatibility; + uint8_t UUID[16]; + char VolumeName[16]; + char LastMounted[64]; + uint32_t BitmapAlogrithm; - uint8_t PreallocatedBlocks; - uint8_t PreallocatedDirectoryBlocks; + uint8_t PreallocatedBlocks; + uint8_t PreallocatedDirectoryBlocks; - uint16_t Padding; - uint8_t JournalUUID[16]; - uint32_t JournalInum; - uint32_t JournalDev; - uint32_t LastOrphan; - uint32_t HashSeed[4]; - uint8_t DefHashVersion; - uint8_t ReservedCharPad; - uint16_t ReservedWordPad; - uint32_t DefaultMountOptions; - uint32_t FirstMetaBg; - uint32_t Reserved[190]; - }; + uint16_t Padding; + uint8_t JournalUUID[16]; + uint32_t JournalInum; + uint32_t JournalDev; + uint32_t LastOrphan; + uint32_t HashSeed[4]; + uint8_t DefHashVersion; + uint8_t ReservedCharPad; + uint16_t ReservedWordPad; + uint32_t DefaultMountOptions; + uint32_t FirstMetaBg; + uint32_t Reserved[190]; + }; - EXT2(void *partition); - ~EXT2(); - }; + EXT2(void *partition); + ~EXT2(); + }; } #endif // !__FENNIX_KERNEL_FILESYSTEM_EXT2_H__ diff --git a/include/filesystem/fat.hpp b/include/filesystem/fat.hpp index 30a083e..7a0bc6a 100644 --- a/include/filesystem/fat.hpp +++ b/include/filesystem/fat.hpp @@ -24,54 +24,54 @@ namespace vfs { - class FAT - { - public: - enum FatType - { - Unknown, - FAT12, - FAT16, - FAT32 - }; + class FAT + { + public: + enum FatType + { + Unknown, + FAT12, + FAT16, + FAT32 + }; - /* https://wiki.osdev.org/FAT */ - struct BIOSParameterBlock - { - /** @brief The first three bytes EB 3C 90 disassemble to JMP SHORT 3C NOP. (The 3C value may be different.) The reason for this is to jump over the disk format information (the BPB and EBPB). Since the first sector of the disk is loaded into ram at location 0x0000:0x7c00 and executed, without this jump, the processor would attempt to execute data that isn't code. Even for non-bootable volumes, code matching this pattern (or using the E9 jump opcode) is required to be present by both Windows and OS X. To fulfil this requirement, an infinite loop can be placed here with the bytes EB FE 90. */ - uint8_t JumpBoot[3]; - /** @brief OEM identifier. The first 8 Bytes (3 - 10) is the version of DOS being used. The next eight Bytes 29 3A 63 7E 2D 49 48 and 43 read out the name of the version. The official FAT Specification from Microsoft says that this field is really meaningless and is ignored by MS FAT Modules, however it does recommend the value "MSWIN4.1" as some 3rd party drivers supposedly check it and expect it to have that value. Older versions of dos also report MSDOS5.1, linux-formatted floppy will likely to carry "mkdosfs" here, and FreeDOS formatted disks have been observed to have "FRDOS5.1" here. If the string is less than 8 bytes, it is padded with spaces. */ - uint8_t OEM[8]; - /** @brief The number of Bytes per sector (remember, all numbers are in the little-endian format). */ - uint16_t BytesPerSector; - /** @brief Number of sectors per cluster. */ - uint8_t SectorsPerCluster; - /** @brief Number of reserved sectors. The boot record sectors are included in this value. */ - uint16_t ReservedSectors; - /** @brief Number of File Allocation Tables (FAT's) on the storage media. Often this value is 2. */ - uint8_t NumberOfFATs; - /** @brief Number of root directory entries (must be set so that the root directory occupies entire sectors). */ - uint16_t RootDirectoryEntries; - /** @brief The total sectors in the logical volume. If this value is 0, it means there are more than 65535 sectors in the volume, and the actual count is stored in the Large Sector Count entry at 0x20. */ - uint16_t Sectors16; - /** @brief This Byte indicates the media descriptor type. */ - uint8_t Media; - /** @brief Number of sectors per FAT. FAT12/FAT16 only. */ - uint16_t SectorsPerFAT; - /** @brief Number of sectors per track. */ - uint16_t SectorsPerTrack; - /** @brief Number of heads or sides on the storage media. */ - uint16_t NumberOfHeads; - /** @brief Number of hidden sectors. (i.e. the LBA of the beginning of the partition). */ - uint32_t HiddenSectors; - /** @brief Large sector count. This field is set if there are more than 65535 sectors in the volume, resulting in a value which does not fit in the Number of Sectors entry at 0x13. */ - uint32_t Sectors32; - } __packed; + /* https://wiki.osdev.org/FAT */ + struct BIOSParameterBlock + { + /** @brief The first three bytes EB 3C 90 disassemble to JMP SHORT 3C NOP. (The 3C value may be different.) The reason for this is to jump over the disk format information (the BPB and EBPB). Since the first sector of the disk is loaded into ram at location 0x0000:0x7c00 and executed, without this jump, the processor would attempt to execute data that isn't code. Even for non-bootable volumes, code matching this pattern (or using the E9 jump opcode) is required to be present by both Windows and OS X. To fulfil this requirement, an infinite loop can be placed here with the bytes EB FE 90. */ + uint8_t JumpBoot[3]; + /** @brief OEM identifier. The first 8 Bytes (3 - 10) is the version of DOS being used. The next eight Bytes 29 3A 63 7E 2D 49 48 and 43 read out the name of the version. The official FAT Specification from Microsoft says that this field is really meaningless and is ignored by MS FAT Modules, however it does recommend the value "MSWIN4.1" as some 3rd party drivers supposedly check it and expect it to have that value. Older versions of dos also report MSDOS5.1, linux-formatted floppy will likely to carry "mkdosfs" here, and FreeDOS formatted disks have been observed to have "FRDOS5.1" here. If the string is less than 8 bytes, it is padded with spaces. */ + uint8_t OEM[8]; + /** @brief The number of Bytes per sector (remember, all numbers are in the little-endian format). */ + uint16_t BytesPerSector; + /** @brief Number of sectors per cluster. */ + uint8_t SectorsPerCluster; + /** @brief Number of reserved sectors. The boot record sectors are included in this value. */ + uint16_t ReservedSectors; + /** @brief Number of File Allocation Tables (FAT's) on the storage media. Often this value is 2. */ + uint8_t NumberOfFATs; + /** @brief Number of root directory entries (must be set so that the root directory occupies entire sectors). */ + uint16_t RootDirectoryEntries; + /** @brief The total sectors in the logical volume. If this value is 0, it means there are more than 65535 sectors in the volume, and the actual count is stored in the Large Sector Count entry at 0x20. */ + uint16_t Sectors16; + /** @brief This Byte indicates the media descriptor type. */ + uint8_t Media; + /** @brief Number of sectors per FAT. FAT12/FAT16 only. */ + uint16_t SectorsPerFAT; + /** @brief Number of sectors per track. */ + uint16_t SectorsPerTrack; + /** @brief Number of heads or sides on the storage media. */ + uint16_t NumberOfHeads; + /** @brief Number of hidden sectors. (i.e. the LBA of the beginning of the partition). */ + uint32_t HiddenSectors; + /** @brief Large sector count. This field is set if there are more than 65535 sectors in the volume, resulting in a value which does not fit in the Number of Sectors entry at 0x13. */ + uint32_t Sectors32; + } __packed; - FatType GetFATType(BIOSParameterBlock *bpb); - FAT(void *partition); - ~FAT(); - }; + FatType GetFATType(BIOSParameterBlock *bpb); + FAT(void *partition); + ~FAT(); + }; } #endif // !__FENNIX_KERNEL_FILESYSTEM_FAT_H__ diff --git a/include/filesystem/initrd.hpp b/include/filesystem/initrd.hpp index 9bfb3a9..833eac7 100644 --- a/include/filesystem/initrd.hpp +++ b/include/filesystem/initrd.hpp @@ -24,25 +24,25 @@ namespace vfs { - class Initrd - { - public: - struct InitrdHeader - { - uint32_t nfiles; - }; + class Initrd + { + public: + struct InitrdHeader + { + uint32_t nfiles; + }; - struct InitrdFileHeader - { - uint8_t magic; - char name[64]; - uint32_t offset; - uint32_t length; - }; + struct InitrdFileHeader + { + uint8_t magic; + char name[64]; + uint32_t offset; + uint32_t length; + }; - Initrd(uintptr_t Address); - ~Initrd(); - }; + Initrd(uintptr_t Address); + ~Initrd(); + }; } #endif // !__FENNIX_KERNEL_FILESYSTEM_INITRD_H__ diff --git a/include/filesystem/ioctl.hpp b/include/filesystem/ioctl.hpp index 0024105..ee5ae64 100644 --- a/include/filesystem/ioctl.hpp +++ b/include/filesystem/ioctl.hpp @@ -20,13 +20,58 @@ #include #include +#include -struct winsize -{ - unsigned short ws_row; - unsigned short ws_col; - unsigned short ws_xpixel; - unsigned short ws_ypixel; -}; +#define _IOC_NRBITS 8 +#define _IOC_TYPEBITS 8 +#define _IOC_SIZEBITS 14 +#define _IOC_DIRBITS 2 + +#define _IOC_NRMASK \ + ((1 << _IOC_NRBITS) - 1) +#define _IOC_TYPEMASK \ + ((1 << _IOC_TYPEBITS) - 1) +#define _IOC_SIZEMASK \ + ((1 << _IOC_SIZEBITS) - 1) +#define _IOC_DIRMASK \ + ((1 << _IOC_DIRBITS) - 1) + +#define _IOC_NRSHIFT 0 +#define _IOC_TYPESHIFT \ + (_IOC_NRSHIFT + _IOC_NRBITS) +#define _IOC_SIZESHIFT \ + (_IOC_TYPESHIFT + _IOC_TYPEBITS) +#define _IOC_DIRSHIFT \ + (_IOC_SIZESHIFT + _IOC_SIZEBITS) + +#define _IOC(dir, type, nr, size) \ + (((dir) << _IOC_DIRSHIFT) | \ + ((type) << _IOC_TYPESHIFT) | \ + ((nr) << _IOC_NRSHIFT) | \ + ((size) << _IOC_SIZESHIFT)) + +#define _IOC_NONE 0U +#define _IOC_WRITE 1U +#define _IOC_READ 2U + +#define _IOC_TYPECHECK(t) (sizeof(t)) + +#define _IO(type, nr) \ + _IOC(_IOC_NONE, (type), (nr), 0) +#define _IOR(type, nr, size) \ + _IOC(_IOC_READ, (type), (nr), (_IOC_TYPECHECK(size))) +#define _IOW(type, nr, size) \ + _IOC(_IOC_WRITE, (type), (nr), (_IOC_TYPECHECK(size))) +#define _IOWR(type, nr, size) \ + _IOC(_IOC_READ | _IOC_WRITE, (type), (nr), (_IOC_TYPECHECK(size))) +#define _IOR_BAD(type, nr, size) \ + _IOC(_IOC_READ, (type), (nr), sizeof(size)) +#define _IOW_BAD(type, nr, size) \ + _IOC(_IOC_WRITE, (type), (nr), sizeof(size)) +#define _IOWR_BAD(type, nr, size) \ + _IOC(_IOC_READ | _IOC_WRITE, (type), (nr), sizeof(size)) + +#define TIOCGPTN _IOR('T', 0x30, unsigned int) +#define TIOCSPTLCK _IOW('T', 0x31, int) #endif // !__FENNIX_KERNEL_FILESYSTEM_IOCTL_H__ diff --git a/include/filesystem/mounts.hpp b/include/filesystem/mounts.hpp index 9f66336..feb2c8f 100644 --- a/include/filesystem/mounts.hpp +++ b/include/filesystem/mounts.hpp @@ -20,7 +20,12 @@ #include +#include #include +#include +#include +#include +#include namespace vfs { @@ -34,12 +39,12 @@ namespace vfs class NullDevice : public Node { public: - virtual size_t read(uint8_t *Buffer, - size_t Size, - off_t Offset); - virtual size_t write(uint8_t *Buffer, - size_t Size, - off_t Offset); + size_t read(uint8_t *Buffer, + size_t Size, + off_t Offset) final; + size_t write(uint8_t *Buffer, + size_t Size, + off_t Offset) final; NullDevice(); ~NullDevice(); @@ -48,12 +53,12 @@ namespace vfs class RandomDevice : public Node { public: - virtual size_t read(uint8_t *Buffer, - size_t Size, - off_t Offset); - virtual size_t write(uint8_t *Buffer, - size_t Size, - off_t Offset); + size_t read(uint8_t *Buffer, + size_t Size, + off_t Offset) final; + size_t write(uint8_t *Buffer, + size_t Size, + off_t Offset) final; RandomDevice(); ~RandomDevice(); @@ -62,42 +67,137 @@ namespace vfs class ZeroDevice : public Node { public: - virtual size_t read(uint8_t *Buffer, - size_t Size, - off_t Offset); - virtual size_t write(uint8_t *Buffer, - size_t Size, - off_t Offset); + size_t read(uint8_t *Buffer, + size_t Size, + off_t Offset) final; + size_t write(uint8_t *Buffer, + size_t Size, + off_t Offset) final; ZeroDevice(); ~ZeroDevice(); }; + class KConDevice : public Node + { + public: + size_t read(uint8_t *Buffer, + size_t Size, + off_t Offset) final; + size_t write(uint8_t *Buffer, + size_t Size, + off_t Offset) final; + int ioctl(unsigned long Request, + void *Argp) final; + + termios term{}; + winsize termSize{}; + + KConDevice(); + ~KConDevice(); + }; + class TTYDevice : public Node { public: - virtual size_t write(uint8_t *Buffer, - size_t Size, - off_t Offset); - virtual int ioctl(unsigned long Request, - void *Argp); + size_t write(uint8_t *Buffer, + size_t Size, + off_t Offset) final; + int ioctl(unsigned long Request, + void *Argp) final; TTYDevice(); ~TTYDevice(); }; + class MasterPTY + { + NewLock(PTYLock); + + public: + size_t read(uint8_t *Buffer, + size_t Size, + off_t Offset); + size_t write(uint8_t *Buffer, + size_t Size, + off_t Offset); + + MasterPTY(); + ~MasterPTY(); + }; + + class SlavePTY + { + NewLock(PTYLock); + + public: + size_t read(uint8_t *Buffer, + size_t Size, + off_t Offset); + size_t write(uint8_t *Buffer, + size_t Size, + off_t Offset); + + SlavePTY(); + ~SlavePTY(); + }; + + class PTYDevice : public Node + { + private: + Node *pts; + int id; + int fildes; + bool isMaster; + termios term{}; + winsize termSize{}; + + MasterPTY *MasterDev; + SlavePTY *SlaveDev; + + public: + decltype(id) &ptyId = id; + decltype(fildes) &fd = fildes; + + int open(int Flags, mode_t Mode) final; + int close() final; + size_t read(uint8_t *Buffer, + size_t Size, + off_t Offset) final; + size_t write(uint8_t *Buffer, + size_t Size, + off_t Offset) final; + int ioctl(unsigned long Request, + void *Argp) final; + + int OpenMaster(int Flags, mode_t Mode); + + PTYDevice(Node *pts, int id); + ~PTYDevice(); + }; + class PTMXDevice : public Node { private: - Node *pts = nullptr; + NewLock(PTMXLock); + Node *pts; + Bitmap ptysId; + std::vector ptysList; public: - virtual size_t read(uint8_t *Buffer, - size_t Size, - off_t Offset); - virtual size_t write(uint8_t *Buffer, - size_t Size, - off_t Offset); + int open(int Flags, mode_t Mode) final; + + /** + * Remove a PTY from the list + * + * @param fd The file descriptor of the PTY + * @param pcb The process that owns the PTY + * + * @note if pcb is nullptr, the current process + * will be used. + * + */ + void RemovePTY(int fd, Tasking::PCB *pcb = nullptr); PTMXDevice(); ~PTMXDevice(); diff --git a/include/filesystem/termios-bits.hpp b/include/filesystem/termios-bits.hpp new file mode 100644 index 0000000..ef42430 --- /dev/null +++ b/include/filesystem/termios-bits.hpp @@ -0,0 +1,160 @@ +/* + 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_TERMIOS_BITS_H__ +#define __FENNIX_KERNEL_TERMIOS_BITS_H__ + +/* c_cc */ +#define VINTR 0 +#define VQUIT 1 +#define VERASE 2 +#define VKILL 3 +#define VEOF 4 +#define VTIME 5 +#define VMIN 6 +#define VSWTC 7 +#define VSTART 8 +#define VSTOP 9 +#define VSUSP 10 +#define VEOL 11 +#define VREPRINT 12 +#define VDISCARD 13 +#define VWERASE 14 +#define VLNEXT 15 +#define VEOL2 16 + +/* c_iflag */ +#define IGNBRK 0000001 +#define BRKINT 0000002 +#define IGNPAR 0000004 +#define PARMRK 0000010 +#define INPCK 0000020 +#define ISTRIP 0000040 +#define INLCR 0000100 +#define IGNCR 0000200 +#define ICRNL 0000400 +#define IUCLC 0001000 +#define IXON 0002000 +#define IXANY 0004000 +#define IXOFF 0010000 +#define IMAXBEL 0020000 +#define IUTF8 0040000 + +/* c_lflag */ +#define ISIG 0000001 +#define ICANON 0000002 +#define XCASE 0000004 +#define ECHO 0000010 +#define ECHOE 0000020 +#define ECHOK 0000040 +#define ECHONL 0000100 +#define NOFLSH 0000200 +#define TOSTOP 0000400 +#define ECHOCTL 0001000 +#define ECHOPRT 0002000 +#define ECHOKE 0004000 +#define FLUSHO 0010000 +#define PENDIN 0040000 +#define IEXTEN 0100000 +#define EXTPROC 0200000 + +/* c_oflag */ +#define OPOST 0000001 +#define OLCUC 0000002 +#define ONLCR 0000004 +#define OCRNL 0000010 +#define ONOCR 0000020 +#define ONLRET 0000040 +#define OFILL 0000100 +#define OFDEL 0000200 +#define NLDLY 0000400 +#define NL0 0000000 +#define NL1 0000400 +#define CRDLY 0003000 +#define _CR0 0000000 +#define _CR1 0001000 +#define _CR2 0002000 +#define _CR3 0003000 +#define TABDLY 0014000 +#define TAB0 0000000 +#define TAB1 0004000 +#define TAB2 0010000 +#define TAB3 0014000 +#define XTABS 0014000 +#define BSDLY 0020000 +#define BS0 0000000 +#define BS1 0020000 +#define VTDLY 0040000 +#define VT0 0000000 +#define VT1 0040000 +#define FFDLY 0100000 +#define FF0 0000000 +#define FF1 0100000 + +/* c_cflag */ +#define CBAUD 0010017 +#define _B0 0000000 +#define B50 0000001 +#define B75 0000002 +#define B110 0000003 +#define B134 0000004 +#define B150 0000005 +#define B200 0000006 +#define B300 0000007 +#define B600 0000010 +#define B1200 0000011 +#define B1800 0000012 +#define B2400 0000013 +#define B4800 0000014 +#define B9600 0000015 +#define B19200 0000016 +#define B38400 0000017 +#define EXTA B19200 +#define EXTB B38400 +#define CSIZE 0000060 +#define CS5 0000000 +#define CS6 0000020 +#define CS7 0000040 +#define CS8 0000060 +#define CSTOPB 0000100 +#define CREAD 0000200 +#define PARENB 0000400 +#define PARODD 0001000 +#define HUPCL 0002000 +#define CLOCAL 0004000 +#define CBAUDEX 0010000 +#define BOTHER 0010000 +#define B57600 0010001 +#define B115200 0010002 +#define B230400 0010003 +#define B460800 0010004 +#define B500000 0010005 +#define B576000 0010006 +#define B921600 0010007 +#define B1000000 0010010 +#define B1152000 0010011 +#define B1500000 0010012 +#define B2000000 0010013 +#define B2500000 0010014 +#define B3000000 0010015 +#define B3500000 0010016 +#define B4000000 0010017 +#define CIBAUD 002003600000 +#define CMSPAR 010000000000 +#define CRTSCTS 020000000000 + +#endif // !__FENNIX_KERNEL_TERMIOS_BITS_H__ diff --git a/include/filesystem/termios.hpp b/include/filesystem/termios.hpp new file mode 100644 index 0000000..906a247 --- /dev/null +++ b/include/filesystem/termios.hpp @@ -0,0 +1,49 @@ +/* + 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_TERMIOS_H__ +#define __FENNIX_KERNEL_TERMIOS_H__ + +#include +#include + +typedef unsigned char cc_t; +typedef unsigned int speed_t; +typedef unsigned int tcflag_t; + +#define NCCS 32 +struct termios +{ + tcflag_t c_iflag; + tcflag_t c_oflag; + tcflag_t c_cflag; + tcflag_t c_lflag; + cc_t c_line; + cc_t c_cc[NCCS]; + speed_t c_ispeed; + speed_t c_ospeed; +}; + +struct winsize +{ + unsigned short ws_row; + unsigned short ws_col; + unsigned short ws_xpixel; + unsigned short ws_ypixel; +}; + +#endif // !__FENNIX_KERNEL_TERMIOS_H__ diff --git a/include/ini.h b/include/ini.h new file mode 100644 index 0000000..65968f9 --- /dev/null +++ b/include/ini.h @@ -0,0 +1,1067 @@ +/* +------------------------------------------------------------------------------ + Licensing information can be found at the end of the file. +------------------------------------------------------------------------------ + +ini.h - v1.2 - Simple ini-file reader for C/C++. + +Do this: + #define INI_IMPLEMENTATION +before you include this file in *one* C/C++ file to create the implementation. +*/ + +#pragma GCC diagnostic ignored "-Wsign-compare" + +#ifndef ini_h +#define ini_h + +#define INI_GLOBAL_SECTION ( 0 ) +#define INI_NOT_FOUND ( -1 ) + +typedef struct ini_t ini_t; + +ini_t* ini_create( void* memctx ); +ini_t* ini_load( char const* data, void* memctx ); + +int ini_save( ini_t const* ini, char* data, int size ); +void ini_destroy( ini_t* ini ); + +int ini_section_count( ini_t const* ini ); +char const* ini_section_name( ini_t const* ini, int section ); + +int ini_property_count( ini_t const* ini, int section ); +char const* ini_property_name( ini_t const* ini, int section, int property ); +char const* ini_property_value( ini_t const* ini, int section, int property ); + +int ini_find_section( ini_t const* ini, char const* name, int name_length ); +int ini_find_property( ini_t const* ini, int section, char const* name, int name_length ); + +int ini_section_add( ini_t* ini, char const* name, int length ); +void ini_property_add( ini_t* ini, int section, char const* name, int name_length, char const* value, int value_length ); +void ini_section_remove( ini_t* ini, int section ); +void ini_property_remove( ini_t* ini, int section, int property ); + +void ini_section_name_set( ini_t* ini, int section, char const* name, int length ); +void ini_property_name_set( ini_t* ini, int section, int property, char const* name, int length ); +void ini_property_value_set( ini_t* ini, int section, int property, char const* value, int length ); + +#endif /* ini_h */ + + +/** + +ini.h +===== + +Simple ini-file reader for C/C++. + + +Examples +-------- + +#### Loading an ini file and retrieving values + + #define INI_IMPLEMENTATION + #include "ini.h" + + #include + #include + + int main() + { + FILE* fp = fopen( "test.ini", "r" ); + fseek( fp, 0, SEEK_END ); + int size = ftell( fp ); + fseek( fp, 0, SEEK_SET ); + char* data = (char*) malloc( size + 1 ); + fread( data, 1, size, fp ); + data[ size ] = '\0'; + fclose( fp ); + + ini_t* ini = ini_load( data, NULL ); + free( data ); + int second_index = ini_find_property( ini, INI_GLOBAL_SECTION, "SecondSetting", 0 ); + char const* second = ini_property_value( ini, INI_GLOBAL_SECTION, second_index ); + printf( "%s=%s\n", "SecondSetting", second ); + int section = ini_find_section( ini, "MySection", 0 ); + int third_index = ini_find_property( ini, section, "ThirdSetting", 0 ); + char const* third = ini_property_value( ini, section, third_index ); + printf( "%s=%s\n", "ThirdSetting", third ); + ini_destroy( ini ); + + return 0; + } + +----------------------------------------------------------------------------------------------- + +#### Creating a new ini file + + #define INI_IMPLEMENTATION + #include "ini.h" + + #include + #include + + int main() + { + ini_t* ini = ini_create( NULL ); + ini_property_add( ini, INI_GLOBAL_SECTION, "FirstSetting", 0, "Test", 0 ); + ini_property_add( ini, INI_GLOBAL_SECTION, "SecondSetting", 0, "2", 0 ); + int section = ini_section_add( ini, "MySection", 0 ); + ini_property_add( ini, section, "ThirdSetting", 0, "Three", 0 ); + + int size = ini_save( ini, NULL, 0 ); // Find the size needed + char* data = (char*) malloc( size ); + size = ini_save( ini, data, size ); // Actually save the file + ini_destroy( ini ); + + FILE* fp = fopen( "test.ini", "w" ); + fwrite( data, 1, size - 1, fp ); + fclose( fp ); + free( data ); + + return 0; + } + + + +API Documentation +----------------- + +ini.h is a small library for reading classic .ini files. It is a single-header library, and does not need any .lib files +or other binaries, or any build scripts. To use it, you just include ini.h to get the API declarations. To get the +definitions, you must include ini.h from *one* single C or C++ file, and #define the symbol `INI_IMPLEMENTATION` before +you do. + + +### Customization + +There are a few different things in ini.h which are configurable by #defines. The customizations only affect the +implementation, so will only need to be defined in the file where you have the #define INI_IMPLEMENTATION. + +Note that if all customizations are utilized, ini.h will include no external files whatsoever, which might be useful +if you need full control over what code is being built. + + +#### Custom memory allocators + +To store the internal data structures, ini.h needs to do dynamic allocation by calling `malloc`. Programs might want to +keep track of allocations done, or use custom defined pools to allocate memory from. ini.h allows for specifying custom +memory allocation functions for `malloc` and `free`. +This is done with the following code: + + #define INI_IMPLEMENTATION + #define INI_MALLOC( ctx, size ) ( my_custom_malloc( ctx, size ) ) + #define INI_FREE( ctx, ptr ) ( my_custom_free( ctx, ptr ) ) + #include "ini.h" + +where `my_custom_malloc` and `my_custom_free` are your own memory allocation/deallocation functions. The `ctx` parameter +is an optional parameter of type `void*`. When `ini_create` or `ini_load` is called, you can pass in a `memctx` +parameter, which can be a pointer to anything you like, and which will be passed through as the `ctx` parameter to every +`INI_MALLOC`/`INI_FREE` call. For example, if you are doing memory tracking, you can pass a pointer to your tracking +data as `memctx`, and in your custom allocation/deallocation function, you can cast the `ctx` param back to the +right type, and access the tracking data. + +If no custom allocator is defined, ini.h will default to `malloc` and `free` from the C runtime library. + + +#### Custom C runtime function + +The library makes use of three additional functions from the C runtime library, and for full flexibility, it allows you +to substitute them for your own. Here's an example: + + #define INI_IMPLEMENTATION + #define INI_MEMCPY( dst, src, cnt ) ( my_memcpy_func( dst, src, cnt ) ) + #define INI_STRLEN( s ) ( my_strlen_func( s ) ) + #define INI_STRNICMP( s1, s2, cnt ) ( my_strnicmp_func( s1, s2, cnt ) ) + #include "ini.h" + +If no custom function is defined, ini.h will default to the C runtime library equivalent. + + +ini_create +---------- + + ini_t* ini_create( void* memctx ) + +Instantiates a new, empty ini structure, which can be manipulated with other API calls, to fill it with data. To save it +out to an ini-file string, use `ini_save`. When no longer needed, it can be destroyed by calling `ini_destroy`. +`memctx` is a pointer to user defined data which will be passed through to the custom INI_MALLOC/INI_FREE calls. It can +be NULL if no user defined data is needed. + + +ini_load +-------- + + ini_t* ini_load( char const* data, void* memctx ) + +Parse the zero-terminated string `data` containing an ini-file, and create a new ini_t instance containing the data. +The instance can be manipulated with other API calls to enumerate sections/properties and retrieve values. When no +longer needed, it can be destroyed by calling `ini_destroy`. `memctx` is a pointer to user defined data which will be +passed through to the custom INI_MALLOC/INI_FREE calls. It can be NULL if no user defined data is needed. + + +ini_save +-------- + + int ini_save( ini_t const* ini, char* data, int size ) + +Saves an ini structure as a zero-terminated ini-file string, into the specified buffer. Returns the number of bytes +written, including the zero terminator. If `data` is NULL, nothing is written, but `ini_save` still returns the number +of bytes it would have written. If the size of `data`, as specified in the `size` parameter, is smaller than that +required, only part of the ini-file string will be written. `ini_save` still returns the number of bytes it would have +written had the buffer been large enough. + + +ini_destroy +----------- + + void ini_destroy( ini_t* ini ) + +Destroy an `ini_t` instance created by calling `ini_load` or `ini_create`, releasing the memory allocated by it. No +further API calls are valid on an `ini_t` instance after calling `ini_destroy` on it. + + +ini_section_count +----------------- + + int ini_section_count( ini_t const* ini ) + +Returns the number of sections in an ini file. There's at least one section in an ini file (the global section), but +there can be many more, each specified in the file by the section name wrapped in square brackets [ ]. + + +ini_section_name +---------------- + + char const* ini_section_name( ini_t const* ini, int section ) + +Returns the name of the section with the specified index. `section` must be non-negative and less than the value +returned by `ini_section_count`, or `ini_section_name` will return NULL. The defined constant `INI_GLOBAL_SECTION` can +be used to indicate the global section. + + +ini_property_count +------------------ + + int ini_property_count( ini_t const* ini, int section ) + +Returns the number of properties belonging to the section with the specified index. `section` must be non-negative and +less than the value returned by `ini_section_count`, or `ini_section_name` will return 0. The defined constant +`INI_GLOBAL_SECTION` can be used to indicate the global section. Properties are declared in the ini-file on he format +`name=value`. + + +ini_property_name +----------------- + + char const* ini_property_name( ini_t const* ini, int section, int property ) + +Returns the name of the property with the specified index `property` in the section with the specified index `section`. +`section` must be non-negative and less than the value returned by `ini_section_count`, and `property` must be +non-negative and less than the value returned by `ini_property_count`, or `ini_property_name` will return NULL. The +defined constant `INI_GLOBAL_SECTION` can be used to indicate the global section. + + +ini_property_value +------------------ + + char const* ini_property_value( ini_t const* ini, int section, int property ) + +Returns the value of the property with the specified index `property` in the section with the specified index `section`. +`section` must be non-negative and less than the value returned by `ini_section_count`, and `property` must be +non-negative and less than the value returned by `ini_property_count`, or `ini_property_value` will return NULL. The +defined constant `INI_GLOBAL_SECTION` can be used to indicate the global section. + + +ini_find_section +---------------- + + int ini_find_section( ini_t const* ini, char const* name, int name_length ) + +Finds the section with the specified name, and returns its index. `name_length` specifies the number of characters in +`name`, which does not have to be zero-terminated. If `name_length` is zero, the length is determined automatically, but +in this case `name` has to be zero-terminated. If no section with the specified name could be found, the value +`INI_NOT_FOUND` is returned. + + +ini_find_property +----------------- + + int ini_find_property( ini_t const* ini, int section, char const* name, int name_length ) + +Finds the property with the specified name, within the section with the specified index, and returns the index of the +property. `name_length` specifies the number of characters in `name`, which does not have to be zero-terminated. If +`name_length` is zero, the length is determined automatically, but in this case `name` has to be zero-terminated. If no +property with the specified name could be found within the specified section, the value `INI_NOT_FOUND` is returned. +`section` must be non-negative and less than the value returned by `ini_section_count`, or `ini_find_property` will +return `INI_NOT_FOUND`. The defined constant `INI_GLOBAL_SECTION` can be used to indicate the global section. + + +ini_section_add +--------------- + + int ini_section_add( ini_t* ini, char const* name, int length ) + +Adds a section with the specified name, and returns the index it was added at. There is no check done to see if a +section with the specified name already exists - multiple sections of the same name are allowed. `length` specifies the +number of characters in `name`, which does not have to be zero-terminated. If `length` is zero, the length is determined +automatically, but in this case `name` has to be zero-terminated. + + +ini_property_add +---------------- + + void ini_property_add( ini_t* ini, int section, char const* name, int name_length, char const* value, int value_length ) + +Adds a property with the specified name and value to the specified section, and returns the index it was added at. There +is no check done to see if a property with the specified name already exists - multiple properties of the same name are +allowed. `name_length` and `value_length` specifies the number of characters in `name` and `value`, which does not have +to be zero-terminated. If `name_length` or `value_length` is zero, the length is determined automatically, but in this +case `name`/`value` has to be zero-terminated. `section` must be non-negative and less than the value returned by +`ini_section_count`, or the property will not be added. The defined constant `INI_GLOBAL_SECTION` can be used to +indicate the global section. + + +ini_section_remove +------------------ + + void ini_section_remove( ini_t* ini, int section ) + +Removes the section with the specified index, and all properties within it. `section` must be non-negative and less than +the value returned by `ini_section_count`. The defined constant `INI_GLOBAL_SECTION` can be used to indicate the global +section. Note that removing a section will shuffle section indices, so that section indices you may have stored will no +longer indicate the same section as it did before the remove. Use the find functions to update your indices. + + +ini_property_remove +------------------- + + void ini_property_remove( ini_t* ini, int section, int property ) + +Removes the property with the specified index from the specified section. `section` must be non-negative and less than +the value returned by `ini_section_count`, and `property` must be non-negative and less than the value returned by +`ini_property_count`. The defined constant `INI_GLOBAL_SECTION` can be used to indicate the global section. Note that +removing a property will shuffle property indices within the specified section, so that property indices you may have +stored will no longer indicate the same property as it did before the remove. Use the find functions to update your +indices. + + +ini_section_name_set +-------------------- + + void ini_section_name_set( ini_t* ini, int section, char const* name, int length ) + +Change the name of the section with the specified index. `section` must be non-negative and less than the value returned +by `ini_section_count`. The defined constant `INI_GLOBAL_SECTION` can be used to indicate the global section. `length` +specifies the number of characters in `name`, which does not have to be zero-terminated. If `length` is zero, the length +is determined automatically, but in this case `name` has to be zero-terminated. + + +ini_property_name_set +--------------------- + + void ini_property_name_set( ini_t* ini, int section, int property, char const* name, int length ) + +Change the name of the property with the specified index in the specified section. `section` must be non-negative and +less than the value returned by `ini_section_count`, and `property` must be non-negative and less than the value +returned by `ini_property_count`. The defined constant `INI_GLOBAL_SECTION` can be used to indicate the global section. +`length` specifies the number of characters in `name`, which does not have to be zero-terminated. If `length` is zero, +the length is determined automatically, but in this case `name` has to be zero-terminated. + + +ini_property_value_set +---------------------- + + void ini_property_value_set( ini_t* ini, int section, int property, char const* value, int length ) + +Change the value of the property with the specified index in the specified section. `section` must be non-negative and +less than the value returned by `ini_section_count`, and `property` must be non-negative and less than the value +returned by `ini_property_count`. The defined constant `INI_GLOBAL_SECTION` can be used to indicate the global section. +`length` specifies the number of characters in `value`, which does not have to be zero-terminated. If `length` is zero, +the length is determined automatically, but in this case `value` has to be zero-terminated. + +*/ + + +/* +---------------------- + IMPLEMENTATION +---------------------- +*/ + +#ifdef INI_IMPLEMENTATION +#undef INI_IMPLEMENTATION + +#define INITIAL_CAPACITY ( 256 ) + +#undef _CRT_NONSTDC_NO_DEPRECATE +#define _CRT_NONSTDC_NO_DEPRECATE +#undef _CRT_SECURE_NO_WARNINGS +#define _CRT_SECURE_NO_WARNINGS +#include + +#ifndef INI_MALLOC + #include + #define INI_MALLOC( ctx, size ) ( malloc( size ) ) + #define INI_FREE( ctx, ptr ) ( free( ptr ) ) +#endif + +#ifndef INI_MEMCPY + #include + #define INI_MEMCPY( dst, src, cnt ) ( memcpy( dst, src, cnt ) ) +#endif + +#ifndef INI_STRLEN + #include + #define INI_STRLEN( s ) ( strlen( s ) ) +#endif + +#ifndef INI_STRNICMP + #ifdef _WIN32 + #include + #define INI_STRNICMP( s1, s2, cnt ) ( strnicmp( s1, s2, cnt ) ) + #else + #include + #define INI_STRNICMP( s1, s2, cnt ) ( strncasecmp( s1, s2, cnt ) ) + #endif +#endif + + +struct ini_internal_section_t + { + char name[ 32 ]; + char* name_large; + }; + + +struct ini_internal_property_t + { + int section; + char name[ 32 ]; + char* name_large; + char value[ 64 ]; + char* value_large; + }; + + +struct ini_t + { + struct ini_internal_section_t* sections; + int section_capacity; + int section_count; + + struct ini_internal_property_t* properties; + int property_capacity; + int property_count; + + void* memctx; + }; + + +static int ini_internal_property_index( ini_t const* ini, int section, int property ) + { + int i; + int p; + + if( ini && section >= 0 && section < ini->section_count ) + { + p = 0; + for( i = 0; i < ini->property_count; ++i ) + { + if( ini->properties[ i ].section == section ) + { + if( p == property ) return i; + ++p; + } + } + } + + return INI_NOT_FOUND; + } + + +ini_t* ini_create( void* memctx ) + { + ini_t* ini; + + ini = (ini_t*) INI_MALLOC( memctx, sizeof( ini_t ) ); + ini->memctx = memctx; + ini->sections = (struct ini_internal_section_t*) INI_MALLOC( ini->memctx, INITIAL_CAPACITY * sizeof( ini->sections[ 0 ] ) ); + ini->section_capacity = INITIAL_CAPACITY; + ini->section_count = 1; /* global section */ + ini->sections[ 0 ].name[ 0 ] = '\0'; + ini->sections[ 0 ].name_large = 0; + ini->properties = (struct ini_internal_property_t*) INI_MALLOC( ini->memctx, INITIAL_CAPACITY * sizeof( ini->properties[ 0 ] ) ); + ini->property_capacity = INITIAL_CAPACITY; + ini->property_count = 0; + return ini; + } + + +ini_t* ini_load( char const* data, void* memctx ) + { + ini_t* ini; + char const* ptr; + int s; + char const* start; + char const* start2; + int l; + + ini = ini_create( memctx ); + + ptr = data; + if( ptr ) + { + s = 0; + while( *ptr ) + { + /* trim leading whitespace */ + while( *ptr && *ptr <=' ' ) + ++ptr; + + /* done? */ + if( !*ptr ) break; + + /* comment */ + else if( *ptr == ';' ) + { + while( *ptr && *ptr !='\n' ) + ++ptr; + } + /* section */ + else if( *ptr == '[' ) + { + ++ptr; + start = ptr; + while( *ptr && *ptr !=']' && *ptr != '\n' ) + ++ptr; + + if( *ptr == ']' ) + { + s = ini_section_add( ini, start, (int)( ptr - start) ); + ++ptr; + } + } + /* property */ + else + { + start = ptr; + while( *ptr && *ptr !='=' && *ptr != '\n' ) + ++ptr; + + if( *ptr == '=' ) + { + l = (int)( ptr - start); + ++ptr; + while( *ptr && *ptr <= ' ' && *ptr != '\n' ) + ptr++; + start2 = ptr; + while( *ptr && *ptr != '\n' ) + ++ptr; + while( ptr >= start2 && *(--ptr) <= ' ' ) + (void)ptr; + ptr++; + if( ptr == start2 ) + ini_property_add( ini, s, start, l, "", 1 ); + else + ini_property_add( ini, s, start, l, start2, (int)( ptr - start2 ) ); + } + } + } + } + + return ini; + } + + +int ini_save( ini_t const* ini, char* data, int size ) + { + int s; + int p; + int i; + int l; + char* n; + int pos; + + if( ini ) + { + pos = 0; + for( s = 0; s < ini->section_count; ++s ) + { + n = ini->sections[ s ].name_large ? ini->sections[ s ].name_large : ini->sections[ s ].name; + l = (int) INI_STRLEN( n ); + if( l > 0 ) + { + if( data && pos < size ) data[ pos ] = '['; + ++pos; + for( i = 0; i < l; ++i ) + { + if( data && pos < size ) data[ pos ] = n[ i ]; + ++pos; + } + if( data && pos < size ) data[ pos ] = ']'; + ++pos; + if( data && pos < size ) data[ pos ] = '\n'; + ++pos; + } + + for( p = 0; p < ini->property_count; ++p ) + { + if( ini->properties[ p ].section == s ) + { + n = ini->properties[ p ].name_large ? ini->properties[ p ].name_large : ini->properties[ p ].name; + l = (int) INI_STRLEN( n ); + for( i = 0; i < l; ++i ) + { + if( data && pos < size ) data[ pos ] = n[ i ]; + ++pos; + } + if( data && pos < size ) data[ pos ] = '='; + ++pos; + n = ini->properties[ p ].value_large ? ini->properties[ p ].value_large : ini->properties[ p ].value; + l = (int) INI_STRLEN( n ); + for( i = 0; i < l; ++i ) + { + if( data && pos < size ) data[ pos ] = n[ i ]; + ++pos; + } + if( data && pos < size ) data[ pos ] = '\n'; + ++pos; + } + } + + if( pos > 0 ) + { + if( data && pos < size ) data[ pos ] = '\n'; + ++pos; + } + } + + if( data && pos < size ) data[ pos ] = '\0'; + ++pos; + + return pos; + } + + return 0; + } + + +void ini_destroy( ini_t* ini ) + { + int i; + + if( ini ) + { + for( i = 0; i < ini->property_count; ++i ) + { + if( ini->properties[ i ].value_large ) INI_FREE( ini->memctx, ini->properties[ i ].value_large ); + if( ini->properties[ i ].name_large ) INI_FREE( ini->memctx, ini->properties[ i ].name_large ); + } + for( i = 0; i < ini->section_count; ++i ) + if( ini->sections[ i ].name_large ) INI_FREE( ini->memctx, ini->sections[ i ].name_large ); + INI_FREE( ini->memctx, ini->properties ); + INI_FREE( ini->memctx, ini->sections ); + INI_FREE( ini->memctx, ini ); + } + } + + +int ini_section_count( ini_t const* ini ) + { + if( ini ) return ini->section_count; + return 0; + } + + +char const* ini_section_name( ini_t const* ini, int section ) + { + if( ini && section >= 0 && section < ini->section_count ) + return ini->sections[ section ].name_large ? ini->sections[ section ].name_large : ini->sections[ section ].name; + + return NULL; + } + + +int ini_property_count( ini_t const* ini, int section ) + { + int i; + int count; + + if( ini ) + { + count = 0; + for( i = 0; i < ini->property_count; ++i ) + { + if( ini->properties[ i ].section == section ) ++count; + } + return count; + } + + return 0; + } + + +char const* ini_property_name( ini_t const* ini, int section, int property ) + { + int p; + + if( ini && section >= 0 && section < ini->section_count ) + { + p = ini_internal_property_index( ini, section, property ); + if( p != INI_NOT_FOUND ) + return ini->properties[ p ].name_large ? ini->properties[ p ].name_large : ini->properties[ p ].name; + } + + return NULL; + } + + +char const* ini_property_value( ini_t const* ini, int section, int property ) + { + int p; + + if( ini && section >= 0 && section < ini->section_count ) + { + p = ini_internal_property_index( ini, section, property ); + if( p != INI_NOT_FOUND ) + return ini->properties[ p ].value_large ? ini->properties[ p ].value_large : ini->properties[ p ].value; + } + + return NULL; + } + + +int ini_find_section( ini_t const* ini, char const* name, int name_length ) + { + int i; + + if( ini && name ) + { + if( name_length <= 0 ) name_length = (int) INI_STRLEN( name ); + for( i = 0; i < ini->section_count; ++i ) + { + char const* const other = + ini->sections[ i ].name_large ? ini->sections[ i ].name_large : ini->sections[ i ].name; + if( strlen( other ) == name_length && INI_STRNICMP( name, other, (size_t)name_length ) == 0 ) + return i; + } + } + + return INI_NOT_FOUND; + } + + +int ini_find_property( ini_t const* ini, int section, char const* name, int name_length ) + { + int i; + int c; + + if( ini && name && section >= 0 && section < ini->section_count) + { + if( name_length <= 0 ) name_length = (int) INI_STRLEN( name ); + c = 0; + for( i = 0; i < ini->property_count; ++i ) + { + if( ini->properties[ i ].section == section ) + { + char const* const other = + ini->properties[ i ].name_large ? ini->properties[ i ].name_large : ini->properties[ i ].name; + if( strlen( other ) == name_length && INI_STRNICMP( name, other, (size_t) name_length ) == 0 ) + return c; + ++c; + } + } + } + + return INI_NOT_FOUND; + } + + +int ini_section_add( ini_t* ini, char const* name, int length ) + { + struct ini_internal_section_t* new_sections; + + if( ini && name ) + { + if( length <= 0 ) length = (int) INI_STRLEN( name ); + if( ini->section_count >= ini->section_capacity ) + { + ini->section_capacity *= 2; + new_sections = (struct ini_internal_section_t*) INI_MALLOC( ini->memctx, + ini->section_capacity * sizeof( ini->sections[ 0 ] ) ); + INI_MEMCPY( new_sections, ini->sections, ini->section_count * sizeof( ini->sections[ 0 ] ) ); + INI_FREE( ini->memctx, ini->sections ); + ini->sections = new_sections; + } + + ini->sections[ ini->section_count ].name_large = 0; + if( (size_t) length + 1 >= sizeof( ini->sections[ 0 ].name ) ) + { + ini->sections[ ini->section_count ].name_large = (char*) INI_MALLOC( ini->memctx, (size_t) length + 1 ); + INI_MEMCPY( ini->sections[ ini->section_count ].name_large, name, (size_t) length ); + ini->sections[ ini->section_count ].name_large[ length ] = '\0'; + } + else + { + INI_MEMCPY( ini->sections[ ini->section_count ].name, name, (size_t) length ); + ini->sections[ ini->section_count ].name[ length ] = '\0'; + } + + return ini->section_count++; + } + return INI_NOT_FOUND; + } + + +void ini_property_add( ini_t* ini, int section, char const* name, int name_length, char const* value, int value_length ) + { + struct ini_internal_property_t* new_properties; + + if( ini && name && section >= 0 && section < ini->section_count ) + { + if( name_length <= 0 ) name_length = (int) INI_STRLEN( name ); + if( value_length <= 0 ) value_length = (int) INI_STRLEN( value ); + + if( ini->property_count >= ini->property_capacity ) + { + + ini->property_capacity *= 2; + new_properties = (struct ini_internal_property_t*) INI_MALLOC( ini->memctx, + ini->property_capacity * sizeof( ini->properties[ 0 ] ) ); + INI_MEMCPY( new_properties, ini->properties, ini->property_count * sizeof( ini->properties[ 0 ] ) ); + INI_FREE( ini->memctx, ini->properties ); + ini->properties = new_properties; + } + + ini->properties[ ini->property_count ].section = section; + ini->properties[ ini->property_count ].name_large = 0; + ini->properties[ ini->property_count ].value_large = 0; + + if( (size_t) name_length + 1 >= sizeof( ini->properties[ 0 ].name ) ) + { + ini->properties[ ini->property_count ].name_large = (char*) INI_MALLOC( ini->memctx, (size_t) name_length + 1 ); + INI_MEMCPY( ini->properties[ ini->property_count ].name_large, name, (size_t) name_length ); + ini->properties[ ini->property_count ].name_large[ name_length ] = '\0'; + } + else + { + INI_MEMCPY( ini->properties[ ini->property_count ].name, name, (size_t) name_length ); + ini->properties[ ini->property_count ].name[ name_length ] = '\0'; + } + + if( (size_t) value_length + 1 >= sizeof( ini->properties[ 0 ].value ) ) + { + ini->properties[ ini->property_count ].value_large = (char*) INI_MALLOC( ini->memctx, (size_t) value_length + 1 ); + INI_MEMCPY( ini->properties[ ini->property_count ].value_large, value, (size_t) value_length ); + ini->properties[ ini->property_count ].value_large[ value_length ] = '\0'; + } + else + { + INI_MEMCPY( ini->properties[ ini->property_count ].value, value, (size_t) value_length ); + ini->properties[ ini->property_count ].value[ value_length ] = '\0'; + } + + ++ini->property_count; + } + } + + +void ini_section_remove( ini_t* ini, int section ) + { + int p; + + if( ini && section >= 0 && section < ini->section_count ) + { + if( ini->sections[ section ].name_large ) INI_FREE( ini->memctx, ini->sections[ section ].name_large ); + for( p = ini->property_count - 1; p >= 0; --p ) + { + if( ini->properties[ p ].section == section ) + { + if( ini->properties[ p ].value_large ) INI_FREE( ini->memctx, ini->properties[ p ].value_large ); + if( ini->properties[ p ].name_large ) INI_FREE( ini->memctx, ini->properties[ p ].name_large ); + ini->properties[ p ] = ini->properties[ --ini->property_count ]; + } + } + + ini->sections[ section ] = ini->sections[ --ini->section_count ]; + + for( p = 0; p < ini->property_count; ++p ) + { + if( ini->properties[ p ].section == ini->section_count ) + ini->properties[ p ].section = section; + } + } + } + + +void ini_property_remove( ini_t* ini, int section, int property ) + { + int p; + + if( ini && section >= 0 && section < ini->section_count ) + { + p = ini_internal_property_index( ini, section, property ); + if( p != INI_NOT_FOUND ) + { + if( ini->properties[ p ].value_large ) INI_FREE( ini->memctx, ini->properties[ p ].value_large ); + if( ini->properties[ p ].name_large ) INI_FREE( ini->memctx, ini->properties[ p ].name_large ); + ini->properties[ p ] = ini->properties[ --ini->property_count ]; + return; + } + } + } + + +void ini_section_name_set( ini_t* ini, int section, char const* name, int length ) + { + if( ini && name && section >= 0 && section < ini->section_count ) + { + if( length <= 0 ) length = (int) INI_STRLEN( name ); + if( ini->sections[ section ].name_large ) INI_FREE( ini->memctx, ini->sections[ section ].name_large ); + ini->sections[ section ].name_large = 0; + + if( (size_t) length + 1 >= sizeof( ini->sections[ 0 ].name ) ) + { + ini->sections[ section ].name_large = (char*) INI_MALLOC( ini->memctx, (size_t) length + 1 ); + INI_MEMCPY( ini->sections[ section ].name_large, name, (size_t) length ); + ini->sections[ section ].name_large[ length ] = '\0'; + } + else + { + INI_MEMCPY( ini->sections[ section ].name, name, (size_t) length ); + ini->sections[ section ].name[ length ] = '\0'; + } + } + } + + +void ini_property_name_set( ini_t* ini, int section, int property, char const* name, int length ) + { + int p; + + if( ini && name && section >= 0 && section < ini->section_count ) + { + if( length <= 0 ) length = (int) INI_STRLEN( name ); + p = ini_internal_property_index( ini, section, property ); + if( p != INI_NOT_FOUND ) + { + if( ini->properties[ p ].name_large ) INI_FREE( ini->memctx, ini->properties[ p ].name_large ); + ini->properties[ ini->property_count ].name_large = 0; + + if( (size_t) length + 1 >= sizeof( ini->properties[ 0 ].name ) ) + { + ini->properties[ p ].name_large = (char*) INI_MALLOC( ini->memctx, (size_t) length + 1 ); + INI_MEMCPY( ini->properties[ p ].name_large, name, (size_t) length ); + ini->properties[ p ].name_large[ length ] = '\0'; + } + else + { + INI_MEMCPY( ini->properties[ p ].name, name, (size_t) length ); + ini->properties[ p ].name[ length ] = '\0'; + } + } + } + } + + +void ini_property_value_set( ini_t* ini, int section, int property, char const* value, int length ) + { + int p; + + if( ini && value && section >= 0 && section < ini->section_count ) + { + if( length <= 0 ) length = (int) INI_STRLEN( value ); + p = ini_internal_property_index( ini, section, property ); + if( p != INI_NOT_FOUND ) + { + if( ini->properties[ p ].value_large ) INI_FREE( ini->memctx, ini->properties[ p ].value_large ); + ini->properties[ ini->property_count ].value_large = 0; + + if( (size_t) length + 1 >= sizeof( ini->properties[ 0 ].value ) ) + { + ini->properties[ p ].value_large = (char*) INI_MALLOC( ini->memctx, (size_t) length + 1 ); + INI_MEMCPY( ini->properties[ p ].value_large, value, (size_t) length ); + ini->properties[ p ].value_large[ length ] = '\0'; + } + else + { + INI_MEMCPY( ini->properties[ p ].value, value, (size_t) length ); + ini->properties[ p ].value[ length ] = '\0'; + } + } + } + } + + +#endif /* INI_IMPLEMENTATION */ + +/* + +contributors: + Randy Gaul (copy-paste bug in ini_property_value_set) + Branimir Karadzic (INI_STRNICMP bugfix) + +revision history: + 1.2 using strnicmp for correct length compares, fixed copy-paste bug in ini_property_value_set + 1.1 customization, added documentation, cleanup + 1.0 first publicly released version + +*/ + +/* +------------------------------------------------------------------------------ + +This software is available under 2 licenses - you may choose the one you like. + +------------------------------------------------------------------------------ + +ALTERNATIVE A - MIT License + +Copyright (c) 2015 Mattias Gustavsson + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +------------------------------------------------------------------------------ + +ALTERNATIVE B - Public Domain (www.unlicense.org) + +This is free and unencumbered software released into the public domain. + +Anyone is free to copy, modify, publish, use, compile, sell, or distribute this +software, either in source code form or as a compiled binary, for any purpose, +commercial or non-commercial, and by any means. + +In jurisdictions that recognize copyright laws, the author or authors of this +software dedicate any and all copyright interest in the software to the public +domain. We make this dedication for the benefit of the public at large and to +the detriment of our heirs and successors. We intend this dedication to be an +overt act of relinquishment in perpetuity of all present and future rights to +this software under copyright law. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +------------------------------------------------------------------------------ +*/ diff --git a/include/ints.hpp b/include/ints.hpp index d0be168..6fde08c 100644 --- a/include/ints.hpp +++ b/include/ints.hpp @@ -20,6 +20,7 @@ #include #include +#include namespace Interrupts { @@ -30,49 +31,55 @@ namespace Interrupts #endif #if defined(a64) - /* APIC::APIC */ extern void *apic[256]; // MAX_CPU - /* APIC::Timer */ extern void *apicTimer[256]; // MAX_CPU + /* APIC::APIC */ extern void *apic[255]; // MAX_CPU + /* APIC::Timer */ extern void *apicTimer[255]; // MAX_CPU #elif defined(a32) - /* APIC::APIC */ extern void *apic[256]; // MAX_CPU - /* APIC::Timer */ extern void *apicTimer[256]; // MAX_CPU + /* APIC::APIC */ extern void *apic[255]; // MAX_CPU + /* APIC::Timer */ extern void *apicTimer[255]; // MAX_CPU #elif defined(aa64) #endif - extern void *InterruptFrames[INT_FRAMES_MAX]; + extern void *InterruptFrames[INT_FRAMES_MAX]; - void Initialize(int Core); - void Enable(int Core); - void InitializeTimer(int Core); - void RemoveAll(); + void Initialize(int Core); + void Enable(int Core); + void InitializeTimer(int Core); + void RemoveAll(); - class Handler - { - private: - int InterruptNumber; + void AddHandler(void (*Callback)(CPU::TrapFrame *), + int InterruptNumber, void *ctx = nullptr, + bool Critical = false); - protected: - /** - * @brief Set a new interrupt number. - * @param InterruptNumber The interrupt number. NOT the IRQ number! (IRQ0 != 32) - */ - void SetInterruptNumber(int InterruptNumber) { this->InterruptNumber = InterruptNumber; } - int GetInterruptNumber() { return this->InterruptNumber; } + void RemoveHandler(void (*Callback)(CPU::TrapFrame *), + int InterruptNumber); - /** - * @brief Create a new interrupt handler. - * @param InterruptNumber The interrupt number. NOT the IRQ number! (IRQ0 != 32) - */ - Handler(int InterruptNumber); - ~Handler(); + void RemoveHandler(void (*Callback)(CPU::TrapFrame *)); + void RemoveHandler(int InterruptNumber); - public: -#if defined(a64) - virtual void OnInterruptReceived(CPU::x64::TrapFrame *Frame); -#elif defined(a32) - virtual void OnInterruptReceived(CPU::x32::TrapFrame *Frame); -#elif defined(aa64) - virtual void OnInterruptReceived(CPU::aarch64::TrapFrame *Frame); -#endif - }; + class Handler + { + private: + int InterruptNumber; + + protected: + /** + * @brief Set a new interrupt number. + * @param InterruptNumber The interrupt number. NOT the IRQ number! (IRQ0 != 32) + */ + void SetInterruptNumber(int InterruptNumber) { this->InterruptNumber = InterruptNumber; } + int GetInterruptNumber() { return this->InterruptNumber; } + + /** + * @brief Create a new interrupt handler. + * @param InterruptNumber The interrupt number. NOT the IRQ number! (IRQ0 != 32) + */ + Handler(int InterruptNumber, bool Critical = false); + Handler(PCI::PCIDevice Device, bool Critical = false); + Handler(); + ~Handler(); + + public: + virtual void OnInterruptReceived(CPU::TrapFrame *Frame); + }; } #endif // !__FENNIX_KERNEL_INTERRUPTS_H__ diff --git a/include/io.h b/include/io.h index c5b90ab..a3e9079 100644 --- a/include/io.h +++ b/include/io.h @@ -26,7 +26,7 @@ extern "C" { #endif - static inline uint8_t inportb(uint16_t Port) + static inline uint8_t inb(uint16_t Port) { uint8_t Result; asm("in %%dx, %%al" @@ -35,7 +35,7 @@ extern "C" return Result; } - static inline uint16_t inportw(uint16_t Port) + static inline uint16_t inw(uint16_t Port) { uint16_t Result; asm("in %%dx, %%ax" @@ -44,7 +44,7 @@ extern "C" return Result; } - static inline uint32_t inportl(uint16_t Port) + static inline uint32_t inl(uint16_t Port) { uint32_t Result; asmv("inl %1, %0" @@ -53,103 +53,27 @@ extern "C" return Result; } - static inline void outportb(uint16_t Port, uint8_t Data) + static inline void outb(uint16_t Port, uint8_t Data) { asmv("out %%al, %%dx" : : "a"(Data), "d"(Port)); } - static inline void outportw(uint16_t Port, uint16_t Data) + static inline void outw(uint16_t Port, uint16_t Data) { asmv("out %%ax, %%dx" : : "a"(Data), "d"(Port)); } - static inline void outportl(uint16_t Port, uint32_t Data) + static inline void outl(uint16_t Port, uint32_t Data) { asmv("outl %1, %0" : : "dN"(Port), "a"(Data)); } - static inline uint8_t mmioin8(uint64_t Address) - { - asmv("" :: - : "memory"); - uint8_t Result = *(volatile uint8_t *)(uintptr_t)Address; - asmv("" :: - : "memory"); - return Result; - } - - static inline uint16_t mmioin16(uint64_t Address) - { - asmv("" :: - : "memory"); - uint16_t Result = *(volatile uint16_t *)(uintptr_t)Address; - asmv("" :: - : "memory"); - return Result; - } - - static inline uint32_t mmioin32(uint64_t Address) - { - asmv("" :: - : "memory"); - uint32_t Result = *(volatile uint32_t *)(uintptr_t)Address; - asmv("" :: - : "memory"); - return Result; - } - - static inline uint64_t mmioin64(uint64_t Address) - { - asmv("" :: - : "memory"); - uint64_t Result = *(volatile uint64_t *)(uintptr_t)Address; - asmv("" :: - : "memory"); - return Result; - } - - static inline void mmioout8(uint64_t Address, uint8_t Data) - { - asmv("" :: - : "memory"); - *(volatile uint8_t *)Address = Data; - asmv("" :: - : "memory"); - } - - static inline void mmioout16(uint64_t Address, uint16_t Data) - { - asmv("" :: - : "memory"); - *(volatile uint16_t *)Address = Data; - asmv("" :: - : "memory"); - } - - static inline void mmioout32(uint64_t Address, uint32_t Data) - { - asmv("" :: - : "memory"); - *(volatile uint32_t *)Address = Data; - asmv("" :: - : "memory"); - } - - static inline void mmioout64(uint64_t Address, uint64_t Data) - { - asmv("" :: - : "memory"); - *(volatile uint64_t *)Address = Data; - asmv("" :: - : "memory"); - } - static inline void mmoutb(void *Address, uint8_t Value) { asmv("mov %1, %0" @@ -225,17 +149,10 @@ extern "C" return Result; } #endif + #ifdef __cplusplus } #endif -#define inb(Port) inportb(Port) -#define inw(Port) inportw(Port) -#define inl(Port) inportl(Port) -#define outb(Port, Data) outportb(Port, Data) -#define outw(Port, Data) outportw(Port, Data) -#define outl(Port, Data) outportl(Port, Data) - #endif // defined(a86) - #endif // !__FENNIX_KERNEL_IO_H__ diff --git a/include/ipc.hpp b/include/ipc.hpp deleted file mode 100644 index 85ba19a..0000000 --- a/include/ipc.hpp +++ /dev/null @@ -1,94 +0,0 @@ -/* - This file is part of Fennix Kernel. - - Fennix Kernel is free software: you can redistribute it and/or - modify it under the terms of the GNU General Public License as - published by the Free Software Foundation, either version 3 of - the License, or (at your option) any later version. - - Fennix Kernel is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Fennix Kernel. If not, see . -*/ - -#ifndef __FENNIX_KERNEL_IPC_H__ -#define __FENNIX_KERNEL_IPC_H__ - -#include -#include -#include -#include -#include -#include - -namespace InterProcessCommunication -{ - typedef int IPCID; - - enum IPCType - { - IPCNone, - IPCMessagePassing, - IPCPort, - IPCSharedMemory, - IPCPipe, - IPCSocket - }; - - enum IPCErrorCode - { - IPCError = -1, - IPCSuccess, - IPCNotListening, - IPCTimeout, - IPCInvalidCommand, - IPCAlreadyAllocated, - IPCNotAllocated, - IPCIDInUse, - IPCIDNotRegistered, - IPCIDNotFound - }; - - struct IPCHandle - { - IPCID ID; - vfs::Node *Node; - void *Buffer; - long Length; - std::atomic_bool Listening; - }; - - class IPC - { - private: - NewLock(IPCLock); - IPCID NextID = 0; - std::vector Handles; - Memory::VirtualMemoryArea *vma; - vfs::Node *IPCNode; - void *Process; - - public: - std::vector GetHandles() { return Handles; } - void Fork(IPC *Parent); - IPCHandle *Create(IPCType Type, char UniqueToken[16]); - IPCErrorCode Destroy(IPCID ID); - IPCErrorCode Allocate(IPCID ID, long Size); - IPCErrorCode Deallocate(IPCID ID); - IPCErrorCode Read(IPCID ID, void *Buffer, long Size); - IPCErrorCode Write(IPCID ID, void *Buffer, long Size); - IPCErrorCode Listen(IPCID ID, bool Listen); - IPCErrorCode Wait(IPCID ID); - IPCHandle *SearchByToken(char UniqueToken[16]); - int HandleSyscall(long Command, long Type, int ID, int Flags, void *Buffer, size_t Size); - - IPC(void *Process); - ~IPC(); - }; -} - -#endif // !__FENNIX_KERNEL_IPC_H__ diff --git a/include/kconfig.hpp b/include/kconfig.hpp index 9831106..237a699 100644 --- a/include/kconfig.hpp +++ b/include/kconfig.hpp @@ -23,23 +23,23 @@ enum KCSchedType { - Mono = 0, - Multi = 1, + Mono = 0, + Multi = 1, }; struct KernelConfig { - Memory::MemoryAllocatorType AllocatorType; - bool SchedulerType; - char ModuleDirectory[256]; - char InitPath[256]; - bool UseLinuxSyscalls; - bool InterruptsOnCrash; - int Cores; - int IOAPICInterruptCore; - bool UnlockDeadLock; - bool SIMD; - bool BootAnimation; + Memory::MemoryAllocatorType AllocatorType; + bool SchedulerType; + char DriverDirectory[256]; + char InitPath[256]; + bool UseLinuxSyscalls; + bool InterruptsOnCrash; + int Cores; + int IOAPICInterruptCore; + bool UnlockDeadLock; + bool SIMD; + bool Quiet; }; void ParseConfig(char *ConfigString, KernelConfig *ModConfig); diff --git a/include/lock.hpp b/include/lock.hpp index 65e5ac3..6170669 100644 --- a/include/lock.hpp +++ b/include/lock.hpp @@ -60,6 +60,7 @@ private: void Yield(); public: + bool Locked() { return IsLocked.load(); } SpinLockData *GetLockData() { return &LockData; } int Lock(const char *FunctionName); int Unlock(); @@ -74,6 +75,11 @@ private: LockClass *LockPointer = nullptr; public: + bool Locked() + { + return this->LockPointer->Locked(); + } + SmartLockClass(LockClass &Lock, const char *FunctionName) { this->LockPointer = &Lock; @@ -88,6 +94,11 @@ private: LockClass *LockPointer = nullptr; public: + bool Locked() + { + return this->LockPointer->Locked(); + } + SmartTimeoutLockClass(LockClass &Lock, const char *FunctionName, uint64_t Timeout) diff --git a/include/md5.h b/include/md5.h index 9a8a8cc..9558753 100644 --- a/include/md5.h +++ b/include/md5.h @@ -28,10 +28,10 @@ START_EXTERNC typedef struct { - size_t size; // Size of input in bytes - uint32_t buffer[4]; // Current accumulation of hash - uint8_t input[64]; // Input to be used in the next step - uint8_t digest[16]; // Result of algorithm + size_t size; // Size of input in bytes + uint32_t buffer[4]; // Current accumulation of hash + uint8_t input[64]; // Input to be used in the next step + uint8_t digest[16]; // Result of algorithm } MD5Context; void md5Init(MD5Context *ctx); diff --git a/include/memory.hpp b/include/memory.hpp index 751485f..162237c 100644 --- a/include/memory.hpp +++ b/include/memory.hpp @@ -43,10 +43,20 @@ namespace Memory enum MemoryAllocatorType { None, + + /** Allocate memory by pages. */ Pages, + XallocV1, XallocV2, - liballoc11 + liballoc11, + + /** + * @warning Not working as expected. + * + * FIXME: This allocator is not working as expected. + */ + rpmalloc_, }; } @@ -61,6 +71,7 @@ namespace Memory #include void InitializeMemoryManagement(); +void CreatePageTable(Memory::PageTable *pt); void *operator new(std::size_t Size); void *operator new[](std::size_t Size); diff --git a/include/memory/brk.hpp b/include/memory/brk.hpp index b80c4fd..857ad9c 100644 --- a/include/memory/brk.hpp +++ b/include/memory/brk.hpp @@ -36,6 +36,9 @@ namespace Memory uintptr_t Break = 0x0; public: + /* fork() */ + void SetTable(PageTable *Table) { this->Table = Table; } + /* Directly to syscall */ void *brk(void *Address); diff --git a/include/memory/table.hpp b/include/memory/table.hpp index b007dc0..6859c23 100644 --- a/include/memory/table.hpp +++ b/include/memory/table.hpp @@ -148,7 +148,7 @@ namespace Memory #elif defined(aa64) #endif }; - uintptr_t raw; + uintptr_t raw = 0; /** @brief Set Address */ void SetAddress(uintptr_t _Address) @@ -273,7 +273,7 @@ namespace Memory } FourMiB; #elif defined(aa64) #endif - uintptr_t raw; + uintptr_t raw = 0; /** @brief Set PageTableEntryPtr address */ void SetAddress(uintptr_t _Address) @@ -359,7 +359,7 @@ namespace Memory } OneGiB; #elif defined(aa64) #endif - uintptr_t raw; + uintptr_t raw = 0; /** @brief Set PageDirectoryEntryPtr address */ void SetAddress(uintptr_t _Address) @@ -413,7 +413,7 @@ namespace Memory }; #elif defined(aa64) #endif - uintptr_t raw; + uintptr_t raw = 0; /** @brief Set PageDirectoryPointerTableEntryPtr address */ void SetAddress(uintptr_t _Address) @@ -467,7 +467,7 @@ namespace Memory }; #elif defined(aa64) #endif - uintptr_t raw; + uintptr_t raw = 0; /** @brief Set PageMapLevel4Ptr address */ void SetAddress(uintptr_t _Address) @@ -516,10 +516,34 @@ namespace Memory * * @return A new PageTable with the same content */ - PageTable Fork(); + PageTable *Fork(); + void *__getPhysical(void *Address); + + /** + * @brief Get the Physical Address of a virtual address + * + * This function will return the physical address + * of a virtual address and not the virtual address + * of the current page table. This is intentional because + * the kernel page table has 1:1 mapping for the free + * memory. + * + * @tparam T + * @param Address The virtual address + * @return The physical address + */ template - T Get(T Address); + T Get(T Address) + { + void *PhysAddr = __getPhysical((void *)Address); + if (PhysAddr == nullptr) + return {}; + uintptr_t Diff = uintptr_t(Address); + Diff &= 0xFFF; + Diff = uintptr_t(PhysAddr) + Diff; + return (T)Diff; + } } __aligned(0x1000); } diff --git a/include/memory/virtual.hpp b/include/memory/virtual.hpp index bd11e83..6061c8e 100644 --- a/include/memory/virtual.hpp +++ b/include/memory/virtual.hpp @@ -30,7 +30,7 @@ namespace Memory { private: NewLock(MemoryLock); - PageTable *Table = nullptr; + PageTable *pTable = nullptr; public: enum MapType @@ -60,8 +60,7 @@ namespace Memory * @param VirtualAddress Virtual address of the page * @param Flag Flag to check * @param Type Type of the page. Check MapType enum. - * @return true if page has the specified flag. - * @return false if page is has the specified flag. + * @return true if page has the specified flag, false otherwise. */ bool Check(void *VirtualAddress, PTFlag Flag = PTFlag::P, diff --git a/include/memory/vma.hpp b/include/memory/vma.hpp index 7c62ca6..f1fedb5 100644 --- a/include/memory/vma.hpp +++ b/include/memory/vma.hpp @@ -56,6 +56,7 @@ namespace Memory public: PageTable *GetTable() { return Table; } + void SetTable(PageTable *Table) { this->Table = Table; } std::vector GetAllocatedPagesList() { @@ -94,6 +95,10 @@ namespace Memory bool HandleCoW(uintptr_t PFA); + void FreeAllPages(); + + void Fork(VirtualMemoryArea *Parent); + VirtualMemoryArea(PageTable *Table = nullptr); ~VirtualMemoryArea(); }; diff --git a/include/module.hpp b/include/module.hpp deleted file mode 100644 index f338a52..0000000 --- a/include/module.hpp +++ /dev/null @@ -1,235 +0,0 @@ -/* - This file is part of Fennix Kernel. - - Fennix Kernel is free software: you can redistribute it and/or - modify it under the terms of the GNU General Public License as - published by the Free Software Foundation, either version 3 of - the License, or (at your option) any later version. - - Fennix Kernel is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Fennix Kernel. If not, see . -*/ - -#ifndef __FENNIX_KERNEL_MODULE_H__ -#define __FENNIX_KERNEL_MODULE_H__ - -#include - -#include -#include -#include -#include -#include -#include -#include - -namespace Module -{ - enum ModuleCode - { - /* This must be the same as in mapi.hpp ModuleReturnCode */ - ERROR, - OK, - NOT_IMPLEMENTED, - NOT_FOUND, - NOT_READY, - NOT_AVAILABLE, - NOT_AUTHORIZED, - NOT_VALID, - NOT_ACCEPTED, - INVALID_PCI_BAR, - INVALID_KERNEL_API, - INVALID_MEMORY_ALLOCATION, - INVALID_DATA, - DEVICE_NOT_SUPPORTED, - SYSTEM_NOT_SUPPORTED, - KERNEL_API_VERSION_NOT_SUPPORTED, - - /* End of module-only errors */ - - INVALID_FEX_HEADER, - INVALID_MODULE_DATA, - NOT_MODULE, - MODULE_RETURNED_ERROR, - UNKNOWN_MODULE_TYPE, - UNKNOWN_MODULE_BIND_TYPE, - PCI_DEVICE_NOT_FOUND, - MODULE_CONFLICT - }; - - class ModuleInterruptHook; - struct ModuleFile - { - bool Enabled = false; - bool BuiltIn = false; - unsigned int modUniqueID = 0; - void *Address = nullptr; - void *ExtendedHeaderAddress = nullptr; - void *InterruptCallback = nullptr; - Memory::VirtualMemoryArea *vma = nullptr; - ModuleInterruptHook *InterruptHook[16]{}; - - bool operator==(const ModuleFile &Other) const - { - return modUniqueID == Other.modUniqueID; - } - }; - - struct BuiltInModuleInfo - { - int (*EntryPoint)(void *); - void *ExtendedHeader; - }; - - class ModuleInterruptHook : public Interrupts::Handler - { - private: - NewLock(DriverInterruptLock); - - ModuleFile Handle; - bool Enabled = true; - -#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: - void Enable() { Enabled = true; } - void Disable() { Enabled = false; } - bool IsEnabled() { return Enabled; } - ModuleInterruptHook(int Interrupt, ModuleFile Handle); - virtual ~ModuleInterruptHook() = default; - }; - - class Module - { - private: - NewLock(ModuleInitLock); - - std::vector Modules; - unsigned int modUIDs = 0; - /* If BuiltIn is true, the "fex" is the entry point. */ - ModuleCode CallModuleEntryPoint(void *fex, bool BuiltIn = false); - - public: - /** - * @brief Load and bind a module to a PCI device. - * - * This function will search for a PCI device with the given VendorID and DeviceID. - * If the device is found, the module will be loaded and bound to the device. - * - * @param ModuleAddress The address of the module. The file will be copied to a new location. - * @param Size The size of the module. - * @param IsBuiltIn If the module is built-in, the @param ModuleAddress will be @see BuiltInModuleInfo and the @param Size will be ignored. - * @return ModuleCode The result of the operation. - */ - ModuleCode ModuleLoadBindPCI(uintptr_t ModuleAddress, size_t Size, bool IsBuiltIn = false); - - /** - * @brief Load and bind a module to an interrupt. - * - * This function will search for an interrupt with the given IRQ. - * If the interrupt is found, the module will be loaded and bound to the interrupt. - * - * @param ModuleAddress The address of the module. The file will be copied to a new location. - * @param Size The size of the module. - * @param IsBuiltIn If the module is built-in, the @param ModuleAddress will be @see BuiltInModuleInfo and the @param Size will be ignored. - * @return ModuleCode The result of the operation. - */ - ModuleCode ModuleLoadBindInterrupt(uintptr_t ModuleAddress, size_t Size, bool IsBuiltIn = false); - - /** - * @brief Load and bind a module to an input device. - * - * This function will attach the module to the input device. - * - * @param ModuleAddress The address of the module. The file will be copied to a new location. - * @param Size The size of the module. - * @param IsBuiltIn If the module is built-in, the @param ModuleAddress will be @see BuiltInModuleInfo and the @param Size will be ignored. - * @return ModuleCode The result of the operation. - */ - ModuleCode ModuleLoadBindInput(uintptr_t ModuleAddress, size_t Size, bool IsBuiltIn = false); - - /** - * @brief Load and bind a module to a process. - * - * This function will attach the module to the process. - * - * @param ModuleAddress The address of the module. The file will be copied to a new location. - * @param Size The size of the module. - * @param IsBuiltIn If the module is built-in, the @param ModuleAddress will be @see BuiltInModuleInfo and the @param Size will be ignored. - * @return ModuleCode The result of the operation. - */ - ModuleCode ModuleLoadBindProcess(uintptr_t ModuleAddress, size_t Size, bool IsBuiltIn = false); - - /** - * @brief Get the currently loaded drivers. - * - * This function returns a clone of the drivers vector. - * This means that the vector can be modified without affecting the drivers. - * - * @return std::vector A clone of the drivers vector. - */ - std::vector GetModules() { return Modules; } - - /* Reserved by the kernel */ - void Panic(); - - /** - * @brief Unload all drivers. - * - * This function will unload all drivers. - */ - void UnloadAllModules(); - - /** - * @brief Unload a module. - * - * This function will unload a module with the given module unique ID. - * It will free the memory and remove the module from the drivers vector. - * - * @param id The module unique ID. - * @return true If the module was found and unloaded successfully, false otherwise. - */ - bool UnloadModule(unsigned long id); - - /** - * @brief Send a callback to a module. - * - * This function will send a callback to a module with the given module unique ID. - * This is used to communicate with drivers. - * - * @param id The module unique ID. - * @param KCB The @see KernelCallback structure. - * @return int The result of the operation. - */ - int IOCB(unsigned long id, /* KernelCallback */ void *KCB); - - /** - * @brief Load a module. - * @param fildes The file descriptor of the module file. - * @return ModuleCode The result of the operation. - */ - ModuleCode LoadModule(vfs::Node *fildes); - - /* Reserved by the kernel */ - void LoadModules(); - - /* Reserved by the kernel */ - Module(); - - /* Reserved by the kernel */ - ~Module(); - }; -} - -#endif // !__FENNIX_KERNEL_MODULE_H__ diff --git a/include/msexec.h b/include/msexec.h index 60d2874..0784cc3 100644 --- a/include/msexec.h +++ b/include/msexec.h @@ -112,137 +112,137 @@ typedef double DOUBLE; typedef struct _IMAGE_DOS_HEADER /* DOS .EXE header */ { - USHORT e_magic; /* Magic number */ - USHORT e_cblp; /* Bytes on last page of file */ - USHORT e_cp; /* Pages in file */ - USHORT e_crlc; /* Relocations */ - USHORT e_cparhdr; /* Size of header in paragraphs */ - USHORT e_minalloc; /* Minimum extra paragraphs needed */ - USHORT e_maxalloc; /* Maximum extra paragraphs needed */ - USHORT e_ss; /* Initial (relative) SS value */ - USHORT e_sp; /* Initial SP value */ - USHORT e_csum; /* Checksum */ - USHORT e_ip; /* Initial IP value */ - USHORT e_cs; /* Initial (relative) CS value */ - USHORT e_lfarlc; /* File address of relocation table */ - USHORT e_ovno; /* Overlay number */ - USHORT e_res[4]; /* Reserved words */ - USHORT e_oemid; /* OEM identifier (for e_oeminfo) */ - USHORT e_oeminfo; /* OEM information; e_oemid specific */ - USHORT e_res2[10]; /* Reserved words */ - USHORT e_lfanew; /* File address of new exe header */ + USHORT e_magic; /* Magic number */ + USHORT e_cblp; /* Bytes on last page of file */ + USHORT e_cp; /* Pages in file */ + USHORT e_crlc; /* Relocations */ + USHORT e_cparhdr; /* Size of header in paragraphs */ + USHORT e_minalloc; /* Minimum extra paragraphs needed */ + USHORT e_maxalloc; /* Maximum extra paragraphs needed */ + USHORT e_ss; /* Initial (relative) SS value */ + USHORT e_sp; /* Initial SP value */ + USHORT e_csum; /* Checksum */ + USHORT e_ip; /* Initial IP value */ + USHORT e_cs; /* Initial (relative) CS value */ + USHORT e_lfarlc; /* File address of relocation table */ + USHORT e_ovno; /* Overlay number */ + USHORT e_res[4]; /* Reserved words */ + USHORT e_oemid; /* OEM identifier (for e_oeminfo) */ + USHORT e_oeminfo; /* OEM information; e_oemid specific */ + USHORT e_res2[10]; /* Reserved words */ + USHORT e_lfanew; /* File address of new exe header */ } IMAGE_DOS_HEADER, *PIMAGE_DOS_HEADER; typedef struct _IMAGE_OS2_HEADER /* OS/2 .EXE header */ { - USHORT ne_magic; /* Magic number */ - UCHAR ne_ver; /* Version number */ - UCHAR ne_rev; /* Revision number */ - USHORT ne_enttab; /* Offset of Entry Table */ - USHORT ne_cbenttab; /* Number of bytes in Entry Table */ - UINT ne_crc; /* Checksum of whole file */ - USHORT ne_flags; /* Flag word */ - USHORT ne_autodata; /* Automatic data segment number */ - USHORT ne_heap; /* Initial heap allocation */ - USHORT ne_stack; /* Initial stack allocation */ - UINT ne_csip; /* Initial CS:IP setting */ - UINT ne_sssp; /* Initial SS:SP setting */ - USHORT ne_cseg; /* Count of file segments */ - USHORT ne_cmod; /* Entries in Module Reference Table */ - USHORT ne_cbnrestab; /* Size of non-resident name table */ - USHORT ne_segtab; /* Offset of Segment Table */ - USHORT ne_rsrctab; /* Offset of Resource Table */ - USHORT ne_restab; /* Offset of resident name table */ - USHORT ne_modtab; /* Offset of Module Reference Table */ - USHORT ne_imptab; /* Offset of Imported Names Table */ - UINT ne_nrestab; /* Offset of Non-resident Names Table */ - USHORT ne_cmovent; /* Count of movable entries */ - USHORT ne_align; /* Segment alignment shift count */ - USHORT ne_cres; /* Count of resource segments */ - UCHAR ne_exetyp; /* Target Operating system */ - UCHAR ne_flagsothers; /* Other .EXE flags */ - USHORT ne_pretthunks; /* offset to return thunks */ - USHORT ne_psegrefbytes; /* offset to segment ref. bytes */ - USHORT ne_swaparea; /* Minimum code swap area size */ - USHORT ne_expver; /* Expected Windows version number */ + USHORT ne_magic; /* Magic number */ + UCHAR ne_ver; /* Version number */ + UCHAR ne_rev; /* Revision number */ + USHORT ne_enttab; /* Offset of Entry Table */ + USHORT ne_cbenttab; /* Number of bytes in Entry Table */ + UINT ne_crc; /* Checksum of whole file */ + USHORT ne_flags; /* Flag word */ + USHORT ne_autodata; /* Automatic data segment number */ + USHORT ne_heap; /* Initial heap allocation */ + USHORT ne_stack; /* Initial stack allocation */ + UINT ne_csip; /* Initial CS:IP setting */ + UINT ne_sssp; /* Initial SS:SP setting */ + USHORT ne_cseg; /* Count of file segments */ + USHORT ne_cmod; /* Entries in Module Reference Table */ + USHORT ne_cbnrestab; /* Size of non-resident name table */ + USHORT ne_segtab; /* Offset of Segment Table */ + USHORT ne_rsrctab; /* Offset of Resource Table */ + USHORT ne_restab; /* Offset of resident name table */ + USHORT ne_modtab; /* Offset of Module Reference Table */ + USHORT ne_imptab; /* Offset of Imported Names Table */ + UINT ne_nrestab; /* Offset of Non-resident Names Table */ + USHORT ne_cmovent; /* Count of movable entries */ + USHORT ne_align; /* Segment alignment shift count */ + USHORT ne_cres; /* Count of resource segments */ + UCHAR ne_exetyp; /* Target Operating system */ + UCHAR ne_flagsothers; /* Other .EXE flags */ + USHORT ne_pretthunks; /* offset to return thunks */ + USHORT ne_psegrefbytes; /* offset to segment ref. bytes */ + USHORT ne_swaparea; /* Minimum code swap area size */ + USHORT ne_expver; /* Expected Windows version number */ } IMAGE_OS2_HEADER, *PIMAGE_OS2_HEADER; typedef struct _IMAGE_SECTION_HEADER { #define IMAGE_SIZEOF_SHORT_NAME 8 - uint8_t Name[IMAGE_SIZEOF_SHORT_NAME]; - union - { - uint32_t PhysicalAddress; - uint32_t VirtualSize; - } Misc; - uint32_t VirtualAddress; - uint32_t SizeOfRawData; - uint32_t PointerToRawData; - uint32_t PointerToRelocations; - uint32_t PointerToLinenumbers; - uint16_t NumberOfRelocations; - uint16_t NumberOfLinenumbers; - uint32_t Characteristics; + uint8_t Name[IMAGE_SIZEOF_SHORT_NAME]; + union + { + uint32_t PhysicalAddress; + uint32_t VirtualSize; + } Misc; + uint32_t VirtualAddress; + uint32_t SizeOfRawData; + uint32_t PointerToRawData; + uint32_t PointerToRelocations; + uint32_t PointerToLinenumbers; + uint16_t NumberOfRelocations; + uint16_t NumberOfLinenumbers; + uint32_t Characteristics; } IMAGE_SECTION_HEADER, *PIMAGE_SECTION_HEADER; typedef struct _IMAGE_FILE_HEADER { - uint16_t Machine; - uint16_t NumberOfSections; - uint32_t TimeDateStamp; - uint32_t PointerToSymbolTable; - uint32_t NumberOfSymbols; - uint16_t SizeOfOptionalHeader; - uint16_t Characteristics; + uint16_t Machine; + uint16_t NumberOfSections; + uint32_t TimeDateStamp; + uint32_t PointerToSymbolTable; + uint32_t NumberOfSymbols; + uint16_t SizeOfOptionalHeader; + uint16_t Characteristics; } IMAGE_FILE_HEADER, *PIMAGE_FILE_HEADER; typedef struct _IMAGE_DATA_DIRECTORY { - uint32_t VirtualAddress; - uint32_t Size; + uint32_t VirtualAddress; + uint32_t Size; } IMAGE_DATA_DIRECTORY, *PIMAGE_DATA_DIRECTORY; typedef struct _IMAGE_OPTIONAL_HEADER { - uint16_t Magic; - uint8_t MajorLinkerVersion; - uint8_t MinorLinkerVersion; - uint32_t SizeOfCode; - uint32_t SizeOfInitializedData; - uint32_t SizeOfUninitializedData; - uint32_t AddressOfEntryPoint; - uint32_t BaseOfCode; - uint32_t BaseOfData; - uint32_t ImageBase; - uint32_t SectionAlignment; - uint32_t FileAlignment; - uint16_t MajorOperatingSystemVersion; - uint16_t MinorOperatingSystemVersion; - uint16_t MajorImageVersion; - uint16_t MinorImageVersion; - uint16_t MajorSubsystemVersion; - uint16_t MinorSubsystemVersion; - uint32_t Win32VersionValue; - uint32_t SizeOfImage; - uint32_t SizeOfHeaders; - uint32_t CheckSum; - uint16_t Subsystem; - uint16_t DllCharacteristics; - uint32_t SizeOfStackReserve; - uint32_t SizeOfStackCommit; - uint32_t SizeOfHeapReserve; - uint32_t SizeOfHeapCommit; - uint32_t LoaderFlags; - uint32_t NumberOfRvaAndSizes; - IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES]; + uint16_t Magic; + uint8_t MajorLinkerVersion; + uint8_t MinorLinkerVersion; + uint32_t SizeOfCode; + uint32_t SizeOfInitializedData; + uint32_t SizeOfUninitializedData; + uint32_t AddressOfEntryPoint; + uint32_t BaseOfCode; + uint32_t BaseOfData; + uint32_t ImageBase; + uint32_t SectionAlignment; + uint32_t FileAlignment; + uint16_t MajorOperatingSystemVersion; + uint16_t MinorOperatingSystemVersion; + uint16_t MajorImageVersion; + uint16_t MinorImageVersion; + uint16_t MajorSubsystemVersion; + uint16_t MinorSubsystemVersion; + uint32_t Win32VersionValue; + uint32_t SizeOfImage; + uint32_t SizeOfHeaders; + uint32_t CheckSum; + uint16_t Subsystem; + uint16_t DllCharacteristics; + uint32_t SizeOfStackReserve; + uint32_t SizeOfStackCommit; + uint32_t SizeOfHeapReserve; + uint32_t SizeOfHeapCommit; + uint32_t LoaderFlags; + uint32_t NumberOfRvaAndSizes; + IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES]; } IMAGE_OPTIONAL_HEADER, *PIMAGE_OPTIONAL_HEADER; typedef struct _IMAGE_NT_HEADERS { - uint32_t Signature; - IMAGE_FILE_HEADER FileHeader; - IMAGE_OPTIONAL_HEADER OptionalHeader; + uint32_t Signature; + IMAGE_FILE_HEADER FileHeader; + IMAGE_OPTIONAL_HEADER OptionalHeader; } IMAGE_NT_HEADERS, *PIMAGE_NT_HEADERS; #endif // !__FENNIX_KERNEL_MSEXEC_H__ diff --git a/include/net/arp.hpp b/include/net/arp.hpp index c97d2e5..e35702d 100644 --- a/include/net/arp.hpp +++ b/include/net/arp.hpp @@ -25,82 +25,82 @@ namespace NetworkARP { - enum ARPOperation - { - REQUEST = 0x1, - REPLY = 0x2 - }; + enum ARPOperation + { + REQUEST = 0x1, + REPLY = 0x2 + }; - enum ARPHardwareType - { - HTYPE_ETHERNET = 1, - HTYPE_802_3 = 6, - HTYPE_ARCNET = 7, - HTYPE_FRAME_RELAY = 15, - HTYPE_ATM = 16, - HTYPE_HDLC = 17, - HTYPE_FIBRE_CHANNEL = 18, - HTYPE_ATM_2 = 19, - HTYPE_SERIAL_LINE = 20 - }; + enum ARPHardwareType + { + HTYPE_ETHERNET = 1, + HTYPE_802_3 = 6, + HTYPE_ARCNET = 7, + HTYPE_FRAME_RELAY = 15, + HTYPE_ATM = 16, + HTYPE_HDLC = 17, + HTYPE_FIBRE_CHANNEL = 18, + HTYPE_ATM_2 = 19, + HTYPE_SERIAL_LINE = 20 + }; - struct ARPHeader - { - uint16_t HardwareType; - uint16_t ProtocolType; - uint8_t HardwareSize; - uint8_t ProtocolSize; - uint16_t Operation; - uint48_t SenderMAC : 48; - uint32_t SenderIP; - uint48_t TargetMAC : 48; - uint32_t TargetIP; - } __packed; + struct ARPHeader + { + uint16_t HardwareType; + uint16_t ProtocolType; + uint8_t HardwareSize; + uint8_t ProtocolSize; + uint16_t Operation; + uint48_t SenderMAC : 48; + uint32_t SenderIP; + uint48_t TargetMAC : 48; + uint32_t TargetIP; + } __packed; - struct DiscoveredAddress - { - MediaAccessControl MAC; - InternetProtocol IP; - }; + struct DiscoveredAddress + { + MediaAccessControl MAC; + InternetProtocol IP; + }; - class ARP : public NetworkEthernet::EthernetEvents - { - private: - NetworkEthernet::Ethernet *Ethernet; + class ARP : public NetworkEthernet::EthernetEvents + { + private: + NetworkEthernet::Ethernet *Ethernet; - enum DAType - { - DA_ADD = 1, - DA_DEL = 2, - DA_SEARCH = 3, - DA_UPDATE = 4 - }; + enum DAType + { + DA_ADD = 1, + DA_DEL = 2, + DA_SEARCH = 3, + DA_UPDATE = 4 + }; - std::vector DiscoveredAddresses; - DiscoveredAddress *ManageDiscoveredAddresses(DAType Type, InternetProtocol IP, MediaAccessControl MAC); - DiscoveredAddress *Search(InternetProtocol TargetIP); - DiscoveredAddress *Update(InternetProtocol TargetIP, MediaAccessControl TargetMAC); - bool OnEthernetPacketReceived(uint8_t *Data, size_t Length); + std::vector DiscoveredAddresses; + DiscoveredAddress *ManageDiscoveredAddresses(DAType Type, InternetProtocol IP, MediaAccessControl MAC); + DiscoveredAddress *Search(InternetProtocol TargetIP); + DiscoveredAddress *Update(InternetProtocol TargetIP, MediaAccessControl TargetMAC); + bool OnEthernetPacketReceived(uint8_t *Data, size_t Length); - public: - ARP(NetworkEthernet::Ethernet *Ethernet); - ~ARP(); + public: + ARP(NetworkEthernet::Ethernet *Ethernet); + ~ARP(); - /** - * @brief Resolve an IP address to a MAC address. - * - * @param IP The IP address to resolve. (Little-endian) - * @return uint48_t The MAC address of the IP address. - */ - uint48_t Resolve(InternetProtocol IP); + /** + * @brief Resolve an IP address to a MAC address. + * + * @param IP The IP address to resolve. (Little-endian) + * @return uint48_t The MAC address of the IP address. + */ + uint48_t Resolve(InternetProtocol IP); - /** - * @brief Broadcast an ARP packet. - * - * @param IP The IP address to broadcast. - */ - void Broadcast(InternetProtocol IP); - }; + /** + * @brief Broadcast an ARP packet. + * + * @param IP The IP address to broadcast. + */ + void Broadcast(InternetProtocol IP); + }; } #endif // !__FENNIX_KERNEL_NETWORK_ARP_H__ diff --git a/include/net/dhcp.hpp b/include/net/dhcp.hpp index 82f54e1..158f4dd 100644 --- a/include/net/dhcp.hpp +++ b/include/net/dhcp.hpp @@ -25,158 +25,158 @@ namespace NetworkDHCP { - struct DHCPHeader - { - uint8_t Opcode; - uint8_t HardwareType; - uint8_t HardwareAddressLength; - uint8_t Hops; - uint32_t TransactionID; - uint16_t Seconds; - uint16_t Flags; - uint32_t ClientIP; - uint32_t YourIP; - uint32_t ServerIP; - uint32_t GatewayIP; - uint8_t ClientHardwareAddress[16]; - uint8_t ServerHostName[64]; - uint8_t BootFileName[128]; - uint8_t Options[64]; - } __packed; + struct DHCPHeader + { + uint8_t Opcode; + uint8_t HardwareType; + uint8_t HardwareAddressLength; + uint8_t Hops; + uint32_t TransactionID; + uint16_t Seconds; + uint16_t Flags; + uint32_t ClientIP; + uint32_t YourIP; + uint32_t ServerIP; + uint32_t GatewayIP; + uint8_t ClientHardwareAddress[16]; + uint8_t ServerHostName[64]; + uint8_t BootFileName[128]; + uint8_t Options[64]; + } __packed; - enum DHCPOperation - { - DHCP_OP_BOOTREQUEST = 1, - DHCP_OP_BOOTREPLY = 2 - }; + enum DHCPOperation + { + DHCP_OP_BOOTREQUEST = 1, + DHCP_OP_BOOTREPLY = 2 + }; - /* TODO: Complete list from https://en.wikipedia.org/wiki/Dynamic_Host_Configuration_Protocol#Options */ - enum DHCPOption - { - DHCP_OPTION_PAD = 0, - DHCP_OPTION_SUBNETMASK = 1, - DHCP_OPTION_TIME_OFFSET = 2, - DHCP_OPTION_ROUTER = 3, - DHCP_OPTION_TIME_SERVER = 4, - DHCP_OPTION_NAME_SERVER = 5, - DHCP_OPTION_DOMAIN_NAME_SERVER = 6, - DHCP_OPTION_LOG_SERVER = 7, - DHCP_OPTION_COOKIE_SERVER = 8, - DHCP_OPTION_LPR_SERVER = 9, - DHCP_OPTION_IMPRESS_SERVER = 10, - DHCP_OPTION_RESOURCE_LOCATION_SERVER = 11, - DHCP_OPTION_HOST_NAME = 12, - DHCP_OPTION_BOOT_FILE_SIZE = 13, - DHCP_OPTION_MERIT_DUMP_FILE = 14, - DHCP_OPTION_DOMAIN_NAME = 15, - DHCP_OPTION_SWAP_SERVER = 16, - DHCP_OPTION_ROOT_PATH = 17, - DHCP_OPTION_EXTENSION_PATH = 18, + /* TODO: Complete list from https://en.wikipedia.org/wiki/Dynamic_Host_Configuration_Protocol#Options */ + enum DHCPOption + { + DHCP_OPTION_PAD = 0, + DHCP_OPTION_SUBNETMASK = 1, + DHCP_OPTION_TIME_OFFSET = 2, + DHCP_OPTION_ROUTER = 3, + DHCP_OPTION_TIME_SERVER = 4, + DHCP_OPTION_NAME_SERVER = 5, + DHCP_OPTION_DOMAIN_NAME_SERVER = 6, + DHCP_OPTION_LOG_SERVER = 7, + DHCP_OPTION_COOKIE_SERVER = 8, + DHCP_OPTION_LPR_SERVER = 9, + DHCP_OPTION_IMPRESS_SERVER = 10, + DHCP_OPTION_RESOURCE_LOCATION_SERVER = 11, + DHCP_OPTION_HOST_NAME = 12, + DHCP_OPTION_BOOT_FILE_SIZE = 13, + DHCP_OPTION_MERIT_DUMP_FILE = 14, + DHCP_OPTION_DOMAIN_NAME = 15, + DHCP_OPTION_SWAP_SERVER = 16, + DHCP_OPTION_ROOT_PATH = 17, + DHCP_OPTION_EXTENSION_PATH = 18, - DHCP_OPTION_IP_FORWARDING = 19, - DHCP_OPTION_NON_LOCAL_SOURCE_ROUTING = 20, - DHCP_OPTION_POLICY_FILTER = 21, - DHCP_OPTION_MAX_DATAGRAM_REASSEMBLY_SIZE = 22, - DHCP_OPTION_DEFAULT_IP_TTL = 23, - DHCP_OPTION_PATH_MTU_AGING_TIMEOUT = 24, - DHCP_OPTION_PATH_MTU_PLATEAU_TABLE = 25, + DHCP_OPTION_IP_FORWARDING = 19, + DHCP_OPTION_NON_LOCAL_SOURCE_ROUTING = 20, + DHCP_OPTION_POLICY_FILTER = 21, + DHCP_OPTION_MAX_DATAGRAM_REASSEMBLY_SIZE = 22, + DHCP_OPTION_DEFAULT_IP_TTL = 23, + DHCP_OPTION_PATH_MTU_AGING_TIMEOUT = 24, + DHCP_OPTION_PATH_MTU_PLATEAU_TABLE = 25, - DHCP_OPTION_INTERFACE_MTU = 26, - DHCP_OPTION_ALL_SUBNETS_ARE_LOCAL = 27, - DHCP_OPTION_BROADCAST_ADDRESS = 28, - DHCP_OPTION_PERFORM_MASK_DISCOVERY = 29, - DHCP_OPTION_MASK_SUPPLIER = 30, - DHCP_OPTION_ROUTER_DISCOVERY = 31, - DHCP_OPTION_ROUTER_SOLICITATION_ADDRESS = 32, - DHCP_OPTION_STATIC_ROUTE = 33, + DHCP_OPTION_INTERFACE_MTU = 26, + DHCP_OPTION_ALL_SUBNETS_ARE_LOCAL = 27, + DHCP_OPTION_BROADCAST_ADDRESS = 28, + DHCP_OPTION_PERFORM_MASK_DISCOVERY = 29, + DHCP_OPTION_MASK_SUPPLIER = 30, + DHCP_OPTION_ROUTER_DISCOVERY = 31, + DHCP_OPTION_ROUTER_SOLICITATION_ADDRESS = 32, + DHCP_OPTION_STATIC_ROUTE = 33, - DHCP_OPTION_TRAILER_ENCAPSULATION = 34, - DHCP_OPTION_ARP_CACHE_TIMEOUT = 35, - DHCP_OPTION_ETHERNET_ENCAPSULATION = 36, + DHCP_OPTION_TRAILER_ENCAPSULATION = 34, + DHCP_OPTION_ARP_CACHE_TIMEOUT = 35, + DHCP_OPTION_ETHERNET_ENCAPSULATION = 36, - DHCP_OPTION_DEFAULT_TCP_TTL = 37, - DHCP_OPTION_TCP_KEEPALIVE_INTERVAL = 38, - DHCP_OPTION_TCP_KEEPALIVE_GARBAGE = 39, + DHCP_OPTION_DEFAULT_TCP_TTL = 37, + DHCP_OPTION_TCP_KEEPALIVE_INTERVAL = 38, + DHCP_OPTION_TCP_KEEPALIVE_GARBAGE = 39, - DHCP_OPTION_NIS_DOMAIN = 40, - DHCP_OPTION_NIS_SERVERS = 41, - DHCP_OPTION_NTP_SERVERS = 42, - DHCP_OPTION_VENDOR_SPECIFIC = 43, - DHCP_OPTION_NETBIOS_NAME_SERVERS = 44, - DHCP_OPTION_NETBIOS_DD_SERVER = 45, - DHCP_OPTION_NETBIOS_NODE_TYPE = 46, - DHCP_OPTION_NETBIOS_SCOPE = 47, - DHCP_OPTION_X_FONT_SERVERS = 48, - DHCP_OPTION_X_DISPLAY_MANAGER = 49, + DHCP_OPTION_NIS_DOMAIN = 40, + DHCP_OPTION_NIS_SERVERS = 41, + DHCP_OPTION_NTP_SERVERS = 42, + DHCP_OPTION_VENDOR_SPECIFIC = 43, + DHCP_OPTION_NETBIOS_NAME_SERVERS = 44, + DHCP_OPTION_NETBIOS_DD_SERVER = 45, + DHCP_OPTION_NETBIOS_NODE_TYPE = 46, + DHCP_OPTION_NETBIOS_SCOPE = 47, + DHCP_OPTION_X_FONT_SERVERS = 48, + DHCP_OPTION_X_DISPLAY_MANAGER = 49, - DHCP_OPTION_REQUESTED_IP = 50, - DHCP_OPTION_IP_LEASE_TIME = 51, - DHCP_OPTION_OPTION_OVERLOAD = 52, - DHCP_OPTION_MESSAGE_TYPE = 53, - DHCP_OPTION_SERVER_IDENTIFIER = 54, - DHCP_OPTION_PARAMETER_REQUEST_LIST = 55, - DHCP_OPTION_MESSAGE = 56, - DHCP_OPTION_MAX_MESSAGE_SIZE = 57, - DHCP_OPTION_T1_TIMEOUT = 58, - DHCP_OPTION_T2_TIMEOUT = 59, - DHCP_OPTION_VENDOR_CLASS_IDENTIFIER = 60, - DHCP_OPTION_CLIENT_IDENTIFIER = 61, + DHCP_OPTION_REQUESTED_IP = 50, + DHCP_OPTION_IP_LEASE_TIME = 51, + DHCP_OPTION_OPTION_OVERLOAD = 52, + DHCP_OPTION_MESSAGE_TYPE = 53, + DHCP_OPTION_SERVER_IDENTIFIER = 54, + DHCP_OPTION_PARAMETER_REQUEST_LIST = 55, + DHCP_OPTION_MESSAGE = 56, + DHCP_OPTION_MAX_MESSAGE_SIZE = 57, + DHCP_OPTION_T1_TIMEOUT = 58, + DHCP_OPTION_T2_TIMEOUT = 59, + DHCP_OPTION_VENDOR_CLASS_IDENTIFIER = 60, + DHCP_OPTION_CLIENT_IDENTIFIER = 61, - DHCP_OPTION_NETWORK_TIME_SERVER = 62, + DHCP_OPTION_NETWORK_TIME_SERVER = 62, - DHCP_OPTION_END = 255 - }; + DHCP_OPTION_END = 255 + }; - enum DHCPMessageType - { - DHCP_MESSAGE_TYPE_DISCOVER = 1, - DHCP_MESSAGE_TYPE_OFFER = 2, - DHCP_MESSAGE_TYPE_REQUEST = 3, - DHCP_MESSAGE_TYPE_DECLINE = 4, - DHCP_MESSAGE_TYPE_ACK = 5, - DHCP_MESSAGE_TYPE_NAK = 6, - DHCP_MESSAGE_TYPE_RELEASE = 7, - DHCP_MESSAGE_TYPE_INFORM = 8, - DHCP_MESSAGE_TYPE_FORCERENEW = 9, - DHCP_MESSAGE_TYPE_LEASEQUERY = 10, - DHCP_MESSAGE_TYPE_LEASEUNASSIGNED = 11, - DHCP_MESSAGE_TYPE_LEASEUNKNOWN = 12, - DHCP_MESSAGE_TYPE_LEASEACTIVE = 13, - DHCP_MESSAGE_TYPE_BULKLEASEQUERY = 14, - DHCP_MESSAGE_TYPE_LEASEQUERYDONE = 15, - DHCP_MESSAGE_TYPE_ACTIVELEASEQUERY = 16, - DHCP_MESSAGE_TYPE_LEASEQUERYSTATUS = 17, - DHCP_MESSAGE_TYPE_DHCPTLS = 18 - }; + enum DHCPMessageType + { + DHCP_MESSAGE_TYPE_DISCOVER = 1, + DHCP_MESSAGE_TYPE_OFFER = 2, + DHCP_MESSAGE_TYPE_REQUEST = 3, + DHCP_MESSAGE_TYPE_DECLINE = 4, + DHCP_MESSAGE_TYPE_ACK = 5, + DHCP_MESSAGE_TYPE_NAK = 6, + DHCP_MESSAGE_TYPE_RELEASE = 7, + DHCP_MESSAGE_TYPE_INFORM = 8, + DHCP_MESSAGE_TYPE_FORCERENEW = 9, + DHCP_MESSAGE_TYPE_LEASEQUERY = 10, + DHCP_MESSAGE_TYPE_LEASEUNASSIGNED = 11, + DHCP_MESSAGE_TYPE_LEASEUNKNOWN = 12, + DHCP_MESSAGE_TYPE_LEASEACTIVE = 13, + DHCP_MESSAGE_TYPE_BULKLEASEQUERY = 14, + DHCP_MESSAGE_TYPE_LEASEQUERYDONE = 15, + DHCP_MESSAGE_TYPE_ACTIVELEASEQUERY = 16, + DHCP_MESSAGE_TYPE_LEASEQUERYSTATUS = 17, + DHCP_MESSAGE_TYPE_DHCPTLS = 18 + }; #define DHCP_TRANSACTION_ID 0xFE2EC005 - class DHCP : public NetworkUDP::UDPEvents - { - private: - NetworkUDP::Socket *UDPSocket; - NetworkInterfaceManager::DeviceInterface *Interface; - bool Received = false; + class DHCP : public NetworkUDP::UDPEvents + { + private: + NetworkUDP::Socket *UDPSocket; + NetworkInterfaceManager::DeviceInterface *Interface; + bool Received = false; - void CreatePacket(DHCPHeader *Packet, uint8_t MessageType, uint32_t RequestIP); - void *GetOption(DHCPHeader *Packet, uint8_t Type); - void OnUDPPacketReceived(NetworkUDP::Socket *Socket, uint8_t *Data, size_t Length); + void CreatePacket(DHCPHeader *Packet, uint8_t MessageType, uint32_t RequestIP); + void *GetOption(DHCPHeader *Packet, uint8_t Type); + void OnUDPPacketReceived(NetworkUDP::Socket *Socket, uint8_t *Data, size_t Length); - public: - /** @brief IP address (Little-endian) */ - InternetProtocol IP = {}; - /** @brief Gateway address (Little-endian) */ - InternetProtocol Gateway = {}; - /** @brief Subnet mask (Little-endian) */ - InternetProtocol SubNetworkMask = {}; - /** @brief DNS server address (Little-endian) */ - InternetProtocol DomainNameSystem = {}; + public: + /** @brief IP address (Little-endian) */ + InternetProtocol IP = {}; + /** @brief Gateway address (Little-endian) */ + InternetProtocol Gateway = {}; + /** @brief Subnet mask (Little-endian) */ + InternetProtocol SubNetworkMask = {}; + /** @brief DNS server address (Little-endian) */ + InternetProtocol DomainNameSystem = {}; - DHCP(NetworkUDP::Socket *Socket, NetworkInterfaceManager::DeviceInterface *Interface); - ~DHCP(); - void Request(); - void Request(InternetProtocol IP); - }; + DHCP(NetworkUDP::Socket *Socket, NetworkInterfaceManager::DeviceInterface *Interface); + ~DHCP(); + void Request(); + void Request(InternetProtocol IP); + }; } #endif // !__FENNIX_KERNEL_DHCP_H__ diff --git a/include/net/dns.hpp b/include/net/dns.hpp index 9eb03bf..b283e61 100644 --- a/include/net/dns.hpp +++ b/include/net/dns.hpp @@ -23,15 +23,15 @@ namespace NetworkDNS { - class DNS : public NetworkUDP::UDPEvents - { - private: - NetworkUDP::Socket *UDPSocket; + class DNS : public NetworkUDP::UDPEvents + { + private: + NetworkUDP::Socket *UDPSocket; - public: - DNS(NetworkUDP::Socket *Socket); - ~DNS(); - }; + public: + DNS(NetworkUDP::Socket *Socket); + ~DNS(); + }; } #endif // !__FENNIX_KERNEL_DNS_H__ diff --git a/include/net/eth.hpp b/include/net/eth.hpp index cbf24a0..633b54f 100644 --- a/include/net/eth.hpp +++ b/include/net/eth.hpp @@ -23,86 +23,86 @@ namespace NetworkEthernet { - enum FrameType - { - TYPE_IPV4 = 0x0800, - TYPE_ARP = 0x0806, - TYPE_RARP = 0x8035, - TYPE_IPV6 = 0x86DD - }; + enum FrameType + { + TYPE_IPV4 = 0x0800, + TYPE_ARP = 0x0806, + TYPE_RARP = 0x8035, + TYPE_IPV6 = 0x86DD + }; - struct EthernetHeader - { - uint48_t DestinationMAC : 48; - uint48_t SourceMAC : 48; - uint16_t Type; - } __packed; + struct EthernetHeader + { + uint48_t DestinationMAC : 48; + uint48_t SourceMAC : 48; + uint16_t Type; + } __packed; - struct EthernetPacket - { - EthernetHeader Header; - uint8_t Data[]; - }; + struct EthernetPacket + { + EthernetHeader Header; + uint8_t Data[]; + }; - class EthernetEvents - { - private: - FrameType FType; + class EthernetEvents + { + private: + FrameType FType; - protected: - EthernetEvents(FrameType Type); - ~EthernetEvents(); + protected: + EthernetEvents(FrameType Type); + ~EthernetEvents(); - public: - FrameType GetFrameType() { return FType; } - virtual void OnEthernetPacketSent(EthernetPacket *Packet) - { - UNUSED(Packet); - netdbg("Event not handled. [%p]", Packet); - } + public: + FrameType GetFrameType() { return FType; } + virtual void OnEthernetPacketSent(EthernetPacket *Packet) + { + UNUSED(Packet); + netdbg("Event not handled. [%p]", Packet); + } - virtual bool OnEthernetPacketReceived(uint8_t *Data, size_t Length) - { - UNUSED(Data); - UNUSED(Length); - netdbg("Event not handled. [%p, %d]", Data, Length); - return false; - } - }; + virtual bool OnEthernetPacketReceived(uint8_t *Data, size_t Length) + { + UNUSED(Data); + UNUSED(Length); + netdbg("Event not handled. [%p, %d]", Data, Length); + return false; + } + }; - class Ethernet : public NetworkInterfaceManager::Events - { - private: - NetworkInterfaceManager::DeviceInterface *Interface; - void Receive(uint8_t *Data, size_t Length); - void OnInterfaceReceived(NetworkInterfaceManager::DeviceInterface *Interface, uint8_t *Data, size_t Length); + class Ethernet : public NetworkInterfaceManager::Events + { + private: + NetworkInterfaceManager::DeviceInterface *Interface; + void Receive(uint8_t *Data, size_t Length); + void OnInterfaceReceived(NetworkInterfaceManager::DeviceInterface *Interface, uint8_t *Data, size_t Length); - public: - /** @brief Get driver interface - * @return Module interface - */ - NetworkInterfaceManager::DeviceInterface *GetInterface() - { - netdbg("Interface: %#lx (MAC: %s; IPv4: %s; IPv6: %s)", this->Interface, - this->Interface->MAC.ToString(), - this->Interface->IP.v4.ToStringLittleEndian(), - this->Interface->IP.v6.ToStringLittleEndian()); - return this->Interface; - } + public: + /** @brief Get driver interface + * @return Driver interface + */ + NetworkInterfaceManager::DeviceInterface *GetInterface() + { + netdbg("Interface: %#lx (MAC: %s; IPv4: %s; IPv6: %s)", this->Interface, + this->Interface->MAC.ToString(), + this->Interface->IP.v4.ToStringLittleEndian(), + this->Interface->IP.v6.ToStringLittleEndian()); + return this->Interface; + } - Ethernet(NetworkInterfaceManager::DeviceInterface *Interface); - ~Ethernet(); + Ethernet(NetworkInterfaceManager::DeviceInterface *Interface); + ~Ethernet(); - /** - * @brief Send an Ethernet packet. - * - * @param MAC The MAC address of the destination. (Big-endian) - * @param Type The type of the packet. - * @param Data The data to send. - * @param Length The length of the data. - */ - void Send(MediaAccessControl MAC, FrameType Type, uint8_t *Data, size_t Length); - }; + /** + * @brief Send an Ethernet packet. + * + * @param MAC The MAC address of the destination. (Big-endian) + * @param Type The type of the packet. + * @param Data The data to send. + * @param Length The length of the data. + */ + void Send(MediaAccessControl MAC, FrameType Type, uint8_t *Data, size_t Length); + }; } #endif // !__FENNIX_KERNEL_NETWORK_ETHERNET_H__ diff --git a/include/net/icmpv4.hpp b/include/net/icmpv4.hpp index fed57c3..1417e80 100644 --- a/include/net/icmpv4.hpp +++ b/include/net/icmpv4.hpp @@ -23,49 +23,49 @@ namespace NetworkICMPv4 { - enum ICMPv4Type - { - TYPE_ECHO_REPLY = 0, - TYPE_DESTINATION_UNREACHABLE = 3, - TYPE_SOURCE_QUENCH = 4, - TYPE_REDIRECT = 5, - TYPE_ECHO = 8, - TYPE_ROUTER_ADVERTISEMENT = 9, - TYPE_ROUTER_SELECTION = 10, - TYPE_TIME_EXCEEDED = 11, - TYPE_PARAMETER_PROBLEM = 12, - TYPE_TIMESTAMP = 13, - TYPE_TIMESTAMP_REPLY = 14 - }; + enum ICMPv4Type + { + TYPE_ECHO_REPLY = 0, + TYPE_DESTINATION_UNREACHABLE = 3, + TYPE_SOURCE_QUENCH = 4, + TYPE_REDIRECT = 5, + TYPE_ECHO = 8, + TYPE_ROUTER_ADVERTISEMENT = 9, + TYPE_ROUTER_SELECTION = 10, + TYPE_TIME_EXCEEDED = 11, + TYPE_PARAMETER_PROBLEM = 12, + TYPE_TIMESTAMP = 13, + TYPE_TIMESTAMP_REPLY = 14 + }; - struct ICMPHeader - { - uint8_t Type; - uint8_t Code; - uint16_t Checksum; - uint16_t Identifier; - uint16_t SequenceNumber; - }; + struct ICMPHeader + { + uint8_t Type; + uint8_t Code; + uint16_t Checksum; + uint16_t Identifier; + uint16_t SequenceNumber; + }; - struct ICMPPacket - { - ICMPHeader Header; - uint8_t Data[]; - }; + struct ICMPPacket + { + ICMPHeader Header; + uint8_t Data[]; + }; - class ICMPv4 - { - private: - NetworkInterfaceManager::DeviceInterface *Interface; + class ICMPv4 + { + private: + NetworkInterfaceManager::DeviceInterface *Interface; - public: - NetworkInterfaceManager::DeviceInterface *GetInterface() { return this->Interface; } + public: + NetworkInterfaceManager::DeviceInterface *GetInterface() { return this->Interface; } - ICMPv4(NetworkInterfaceManager::DeviceInterface *Interface); - ~ICMPv4(); - void Send(/* ???? */); - void Receive(ICMPPacket *Packet); - }; + ICMPv4(NetworkInterfaceManager::DeviceInterface *Interface); + ~ICMPv4(); + void Send(/* ???? */); + void Receive(ICMPPacket *Packet); + }; } #endif // !__FENNIX_KERNEL_ICMPv4_H__ diff --git a/include/net/icmpv6.hpp b/include/net/icmpv6.hpp index e4b9b26..519f114 100644 --- a/include/net/icmpv6.hpp +++ b/include/net/icmpv6.hpp @@ -23,34 +23,34 @@ namespace NetworkICMPv6 { - struct ICMPHeader - { - uint8_t Type; - uint8_t Code; - uint16_t Checksum; - uint16_t Identifier; - uint16_t SequenceNumber; - }; + struct ICMPHeader + { + uint8_t Type; + uint8_t Code; + uint16_t Checksum; + uint16_t Identifier; + uint16_t SequenceNumber; + }; - struct ICMPPacket - { - ICMPHeader Header; - uint8_t Data[]; - }; + struct ICMPPacket + { + ICMPHeader Header; + uint8_t Data[]; + }; - class ICMPv6 - { - private: - NetworkInterfaceManager::DeviceInterface *Interface; + class ICMPv6 + { + private: + NetworkInterfaceManager::DeviceInterface *Interface; - public: - NetworkInterfaceManager::DeviceInterface *GetInterface() { return this->Interface; } + public: + NetworkInterfaceManager::DeviceInterface *GetInterface() { return this->Interface; } - ICMPv6(NetworkInterfaceManager::DeviceInterface *Interface); - ~ICMPv6(); - void Send(uint8_t *Data, size_t Length); - void Receive(uint8_t *Data); - }; + ICMPv6(NetworkInterfaceManager::DeviceInterface *Interface); + ~ICMPv6(); + void Send(uint8_t *Data, size_t Length); + void Receive(uint8_t *Data); + }; } #endif // !__FENNIX_KERNEL_ICMPv6_H__ diff --git a/include/net/ipv4.hpp b/include/net/ipv4.hpp index cfd2412..5ac2cd6 100644 --- a/include/net/ipv4.hpp +++ b/include/net/ipv4.hpp @@ -25,113 +25,113 @@ namespace NetworkIPv4 { - struct IPv4Header - { - uint8_t IHL : 4; - uint8_t Version : 4; - uint8_t TypeOfService; - uint16_t TotalLength; - uint16_t Identification; - uint8_t Flags; - uint8_t FragmentOffset; - uint8_t TimeToLive; - uint8_t Protocol; - uint16_t HeaderChecksum; - uint32_t SourceIP; - uint32_t DestinationIP; + struct IPv4Header + { + uint8_t IHL : 4; + uint8_t Version : 4; + uint8_t TypeOfService; + uint16_t TotalLength; + uint16_t Identification; + uint8_t Flags; + uint8_t FragmentOffset; + uint8_t TimeToLive; + uint8_t Protocol; + uint16_t HeaderChecksum; + uint32_t SourceIP; + uint32_t DestinationIP; - /* On wikipedia page we have this: https://en.wikipedia.org/wiki/File:IPv4_Packet-en.svg - but only the code above works... */ - // uint8_t Version : 4; - // uint8_t IHL : 4; - // uint16_t TypeOfService : 8; - // uint16_t TotalLength : 12; - // uint16_t Identification : 16; - // uint16_t Flags : 3; - // uint16_t FragmentOffset : 13; - // uint8_t TimeToLive : 8; - // uint8_t Protocol : 8; - // uint16_t HeaderChecksum; - // uint32_t SourceIP; - // uint32_t DestinationIP; - }; + /* On wikipedia page we have this: https://en.wikipedia.org/wiki/File:IPv4_Packet-en.svg + but only the code above works... */ + // uint8_t Version : 4; + // uint8_t IHL : 4; + // uint16_t TypeOfService : 8; + // uint16_t TotalLength : 12; + // uint16_t Identification : 16; + // uint16_t Flags : 3; + // uint16_t FragmentOffset : 13; + // uint8_t TimeToLive : 8; + // uint8_t Protocol : 8; + // uint16_t HeaderChecksum; + // uint32_t SourceIP; + // uint32_t DestinationIP; + }; - struct IPv4Packet - { - IPv4Header Header; - uint8_t Data[]; - }; + struct IPv4Packet + { + IPv4Header Header; + uint8_t Data[]; + }; - enum IPv4Protocols - { - PROTOCOL_ICMP = 1, - PROTOCOL_IGMP = 2, - PROTOCOL_TCP = 6, - PROTOCOL_UDP = 17, - PROTOCOL_IPV6 = 41, - PROTOCOL_ROUTING = 43, - PROTOCOL_FRAGMENT = 44, - PROTOCOL_ESP = 50, - PROTOCOL_AH = 51, - PROTOCOL_ICMPV6 = 58, - PROTOCOL_NONE = 59, - PROTOCOL_DSTOPTS = 60, - PROTOCOL_ND = 77, - PROTOCOL_ICLFXBM = 78, - PROTOCOL_PIM = 103, - PROTOCOL_COMP = 108, - PROTOCOL_SCTP = 132, - PROTOCOL_UDPLITE = 136, - PROTOCOL_RAW = 255 - }; + enum IPv4Protocols + { + PROTOCOL_ICMP = 1, + PROTOCOL_IGMP = 2, + PROTOCOL_TCP = 6, + PROTOCOL_UDP = 17, + PROTOCOL_IPV6 = 41, + PROTOCOL_ROUTING = 43, + PROTOCOL_FRAGMENT = 44, + PROTOCOL_ESP = 50, + PROTOCOL_AH = 51, + PROTOCOL_ICMPV6 = 58, + PROTOCOL_NONE = 59, + PROTOCOL_DSTOPTS = 60, + PROTOCOL_ND = 77, + PROTOCOL_ICLFXBM = 78, + PROTOCOL_PIM = 103, + PROTOCOL_COMP = 108, + PROTOCOL_SCTP = 132, + PROTOCOL_UDPLITE = 136, + PROTOCOL_RAW = 255 + }; - class IPv4 : public NetworkEthernet::EthernetEvents - { - private: - NetworkARP::ARP *ARP; - NetworkEthernet::Ethernet *Ethernet; + class IPv4 : public NetworkEthernet::EthernetEvents + { + private: + NetworkARP::ARP *ARP; + NetworkEthernet::Ethernet *Ethernet; - virtual bool OnEthernetPacketReceived(uint8_t *Data, size_t Length); + virtual bool OnEthernetPacketReceived(uint8_t *Data, size_t Length); - public: - InternetProtocol GatewayIP; - InternetProtocol SubNetworkMaskIP; - IPv4(NetworkARP::ARP *ARP, NetworkEthernet::Ethernet *Ethernet); - ~IPv4(); + public: + InternetProtocol GatewayIP; + InternetProtocol SubNetworkMaskIP; + IPv4(NetworkARP::ARP *ARP, NetworkEthernet::Ethernet *Ethernet); + ~IPv4(); - /** - * @brief Send an IPv4 packet. - * - * @param Data The data to send. - * @param Length The length of the data. - * @param Protocol The protocol of the packet. - * @param DestinationIP The IP address of the destination. (Big-endian) - */ - void Send(uint8_t *Data, size_t Length, uint8_t Protocol, InternetProtocol DestinationIP); - }; + /** + * @brief Send an IPv4 packet. + * + * @param Data The data to send. + * @param Length The length of the data. + * @param Protocol The protocol of the packet. + * @param DestinationIP The IP address of the destination. (Big-endian) + */ + void Send(uint8_t *Data, size_t Length, uint8_t Protocol, InternetProtocol DestinationIP); + }; - class IPv4Events - { - private: - uint8_t Protocol; + class IPv4Events + { + private: + uint8_t Protocol; - protected: - IPv4Events(IPv4Protocols Protocol); - ~IPv4Events(); + protected: + IPv4Events(IPv4Protocols Protocol); + ~IPv4Events(); - public: - uint8_t GetProtocol() { return Protocol; } + public: + uint8_t GetProtocol() { return Protocol; } - virtual bool OnIPv4PacketReceived(InternetProtocol SourceIP, InternetProtocol DestinationIP, uint8_t *Data, size_t Length) - { - UNUSED(SourceIP); - UNUSED(DestinationIP); - UNUSED(Data); - UNUSED(Length); - warn("Not implemented."); - return false; - } - }; + virtual bool OnIPv4PacketReceived(InternetProtocol SourceIP, InternetProtocol DestinationIP, uint8_t *Data, size_t Length) + { + UNUSED(SourceIP); + UNUSED(DestinationIP); + UNUSED(Data); + UNUSED(Length); + warn("Not implemented."); + return false; + } + }; } #endif // !__FENNIX_KERNEL_IPv4_H__ diff --git a/include/net/ipv6.hpp b/include/net/ipv6.hpp index b910389..3c28c09 100644 --- a/include/net/ipv6.hpp +++ b/include/net/ipv6.hpp @@ -22,23 +22,23 @@ namespace NetworkIPv6 { - struct IPv6Header - { - uint32_t Version; - uint8_t TrafficClass; - uint16_t FlowLabel; - uint16_t PayloadLength; - uint8_t NextHeader; - uint8_t HopLimit; - uint32_t SourceIP; - uint32_t DestinationIP; - }; + struct IPv6Header + { + uint32_t Version; + uint8_t TrafficClass; + uint16_t FlowLabel; + uint16_t PayloadLength; + uint8_t NextHeader; + uint8_t HopLimit; + uint32_t SourceIP; + uint32_t DestinationIP; + }; - struct IPv6Packet - { - IPv6Header Header; - uint8_t Data[]; - }; + struct IPv6Packet + { + IPv6Header Header; + uint8_t Data[]; + }; } #endif // !__FENNIX_KERNEL_IPv6_H__ diff --git a/include/net/nc.hpp b/include/net/nc.hpp index 92aafbe..7f4e158 100644 --- a/include/net/nc.hpp +++ b/include/net/nc.hpp @@ -27,90 +27,90 @@ namespace NetworkInterfaceManager { - struct DeviceInterface - { - /** @brief Device interface name */ - char Name[128]; + struct DeviceInterface + { + /** @brief Device interface name */ + char Name[128]; - /** @brief Device interface index */ - uint64_t ID; + /** @brief Device interface index */ + uint64_t ID; - /** @brief Device interface MAC address (Big-endian) */ - MediaAccessControl MAC; + /** @brief Device interface MAC address (Big-endian) */ + MediaAccessControl MAC; - /** @brief Device interface IP address (Big-endian) */ - InternetProtocol IP; + /** @brief Device interface IP address (Big-endian) */ + InternetProtocol IP; - /** @brief Reserved */ - unsigned long DriverID; - }; + /** @brief Reserved */ + unsigned long DriverID; + }; - class Events - { - protected: - Events(DeviceInterface *Interface); - ~Events(); + class Events + { + protected: + Events(DeviceInterface *Interface); + ~Events(); - public: - virtual void OnInterfaceAdded(DeviceInterface *Interface) - { - UNUSED(Interface); - netdbg("Event for %s not handled.", Interface->Name); - } + public: + virtual void OnInterfaceAdded(DeviceInterface *Interface) + { + UNUSED(Interface); + netdbg("Event for %s not handled.", Interface->Name); + } - virtual void OnInterfaceRemoved(DeviceInterface *Interface) - { - UNUSED(Interface); - netdbg("Event for %s not handled.", Interface->Name); - } + virtual void OnInterfaceRemoved(DeviceInterface *Interface) + { + UNUSED(Interface); + netdbg("Event for %s not handled.", Interface->Name); + } - virtual void OnInterfaceChanged(DeviceInterface *Interface) - { - UNUSED(Interface); - netdbg("Event for %s not handled.", Interface->Name); - } + virtual void OnInterfaceChanged(DeviceInterface *Interface) + { + UNUSED(Interface); + netdbg("Event for %s not handled.", Interface->Name); + } - virtual void OnInterfaceReceived(DeviceInterface *Interface, uint8_t *Data, size_t Length) - { - UNUSED(Interface); - UNUSED(Data); - UNUSED(Length); - netdbg("Event for %s not handled.", Interface->Name); - } + virtual void OnInterfaceReceived(DeviceInterface *Interface, uint8_t *Data, size_t Length) + { + UNUSED(Interface); + UNUSED(Data); + UNUSED(Length); + netdbg("Event for %s not handled.", Interface->Name); + } - virtual void OnInterfaceSent(DeviceInterface *Interface, uint8_t *Data, size_t Length) - { - UNUSED(Interface); - UNUSED(Data); - UNUSED(Length); - netdbg("Event for %s not handled.", Interface->Name); - } - }; + virtual void OnInterfaceSent(DeviceInterface *Interface, uint8_t *Data, size_t Length) + { + UNUSED(Interface); + UNUSED(Data); + UNUSED(Length); + netdbg("Event for %s not handled.", Interface->Name); + } + }; - class NetworkInterface - { - private: - Memory::VirtualMemoryArea *vma; - int CardIDs = 0; - std::vector Interfaces; + class NetworkInterface + { + private: + Memory::VirtualMemoryArea *vma; + int CardIDs = 0; + std::vector Interfaces; - Tasking::TCB *NetSvcThread; - void StopNetworkStack(); - void FetchNetworkCards(unsigned long modUniqueID); + Tasking::TCB *NetSvcThread; + void StopNetworkStack(); + void FetchNetworkCards(unsigned long modUniqueID); - public: - NetworkInterface(); - ~NetworkInterface(); + public: + NetworkInterface(); + ~NetworkInterface(); - void StartService(); + void StartService(); - void Send(DeviceInterface *Interface, uint8_t *Data, size_t Length); - void Receive(DeviceInterface *Interface, uint8_t *Data, size_t Length); + void Send(DeviceInterface *Interface, uint8_t *Data, size_t Length); + void Receive(DeviceInterface *Interface, uint8_t *Data, size_t Length); - void DrvSend(unsigned int DriverID, unsigned char *Data, unsigned short Size); - void DrvReceive(unsigned int DriverID, unsigned char *Data, unsigned short Size); - void StartNetworkStack(); - }; + void DrvSend(unsigned int DriverID, unsigned char *Data, unsigned short Size); + void DrvReceive(unsigned int DriverID, unsigned char *Data, unsigned short Size); + void StartNetworkStack(); + }; } #endif // !__FENNIX_KERNEL_NETWORK_CONTROLLER_H__ diff --git a/include/net/net.hpp b/include/net/net.hpp index 2112abe..4760b26 100644 --- a/include/net/net.hpp +++ b/include/net/net.hpp @@ -32,199 +32,199 @@ void DbgDumpData(const char *Description, void *Address, unsigned long Length); static inline void DbgNetwork() { return; } static inline void DbgDumpData(const char *Description, void *Address, unsigned long Length) { - UNUSED(Description); - UNUSED(Address); - UNUSED(Length); - return; + UNUSED(Description); + UNUSED(Address); + UNUSED(Length); + return; } #endif enum Endianness { - LITTLE_ENDIAN, - BIG_ENDIAN + LITTLE_ENDIAN, + BIG_ENDIAN }; struct MediaAccessControl { - uint8_t Address[6] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; - Endianness Endianess = LITTLE_ENDIAN; + uint8_t Address[6] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; + Endianness Endianess = LITTLE_ENDIAN; - inline bool operator==(const MediaAccessControl &lhs) const - { - return lhs.Address[0] == this->Address[0] && - lhs.Address[1] == this->Address[1] && - lhs.Address[2] == this->Address[2] && - lhs.Address[3] == this->Address[3] && - lhs.Address[4] == this->Address[4] && - lhs.Address[5] == this->Address[5]; - } + inline bool operator==(const MediaAccessControl &lhs) const + { + return lhs.Address[0] == this->Address[0] && + lhs.Address[1] == this->Address[1] && + lhs.Address[2] == this->Address[2] && + lhs.Address[3] == this->Address[3] && + lhs.Address[4] == this->Address[4] && + lhs.Address[5] == this->Address[5]; + } - inline bool operator==(const uint48_t &lhs) const - { - MediaAccessControl MAC; - MAC.Address[0] = (uint8_t)((lhs >> 40) & 0xFF); - MAC.Address[1] = (uint8_t)((lhs >> 32) & 0xFF); - MAC.Address[2] = (uint8_t)((lhs >> 24) & 0xFF); - MAC.Address[3] = (uint8_t)((lhs >> 16) & 0xFF); - MAC.Address[4] = (uint8_t)((lhs >> 8) & 0xFF); - MAC.Address[5] = (uint8_t)(lhs & 0xFF); - return MAC.Address[0] == this->Address[0] && - MAC.Address[1] == this->Address[1] && - MAC.Address[2] == this->Address[2] && - MAC.Address[3] == this->Address[3] && - MAC.Address[4] == this->Address[4] && - MAC.Address[5] == this->Address[5]; - } + inline bool operator==(const uint48_t &lhs) const + { + MediaAccessControl MAC; + MAC.Address[0] = (uint8_t)((lhs >> 40) & 0xFF); + MAC.Address[1] = (uint8_t)((lhs >> 32) & 0xFF); + MAC.Address[2] = (uint8_t)((lhs >> 24) & 0xFF); + MAC.Address[3] = (uint8_t)((lhs >> 16) & 0xFF); + MAC.Address[4] = (uint8_t)((lhs >> 8) & 0xFF); + MAC.Address[5] = (uint8_t)(lhs & 0xFF); + return MAC.Address[0] == this->Address[0] && + MAC.Address[1] == this->Address[1] && + MAC.Address[2] == this->Address[2] && + MAC.Address[3] == this->Address[3] && + MAC.Address[4] == this->Address[4] && + MAC.Address[5] == this->Address[5]; + } - inline bool operator!=(const MediaAccessControl &lhs) const { return !(*this == lhs); } - inline bool operator!=(const uint48_t &lhs) const { return !(*this == lhs); } + inline bool operator!=(const MediaAccessControl &lhs) const { return !(*this == lhs); } + inline bool operator!=(const uint48_t &lhs) const { return !(*this == lhs); } - inline uint48_t ToHex() - { - return ((uint48_t)this->Address[0] << 40) | - ((uint48_t)this->Address[1] << 32) | - ((uint48_t)this->Address[2] << 24) | - ((uint48_t)this->Address[3] << 16) | - ((uint48_t)this->Address[4] << 8) | - ((uint48_t)this->Address[5]); - } + inline uint48_t ToHex() + { + return ((uint48_t)this->Address[0] << 40) | + ((uint48_t)this->Address[1] << 32) | + ((uint48_t)this->Address[2] << 24) | + ((uint48_t)this->Address[3] << 16) | + ((uint48_t)this->Address[4] << 8) | + ((uint48_t)this->Address[5]); + } - inline MediaAccessControl FromHex(uint48_t Hex) - { - this->Address[0] = (uint8_t)((Hex >> 40) & 0xFF); - this->Address[1] = (uint8_t)((Hex >> 32) & 0xFF); - this->Address[2] = (uint8_t)((Hex >> 24) & 0xFF); - this->Address[3] = (uint8_t)((Hex >> 16) & 0xFF); - this->Address[4] = (uint8_t)((Hex >> 8) & 0xFF); - this->Address[5] = (uint8_t)(Hex & 0xFF); - return *this; - } + inline MediaAccessControl FromHex(uint48_t Hex) + { + this->Address[0] = (uint8_t)((Hex >> 40) & 0xFF); + this->Address[1] = (uint8_t)((Hex >> 32) & 0xFF); + this->Address[2] = (uint8_t)((Hex >> 24) & 0xFF); + this->Address[3] = (uint8_t)((Hex >> 16) & 0xFF); + this->Address[4] = (uint8_t)((Hex >> 8) & 0xFF); + this->Address[5] = (uint8_t)(Hex & 0xFF); + return *this; + } - inline bool Valid() - { - // TODO: More complex MAC validation - return (this->Address[0] != 0 || - this->Address[1] != 0 || - this->Address[2] != 0 || - this->Address[3] != 0 || - this->Address[4] != 0 || - this->Address[5] != 0) && - (this->Address[0] != 0xFF || - this->Address[1] != 0xFF || - this->Address[2] != 0xFF || - this->Address[3] != 0xFF || - this->Address[4] != 0xFF || - this->Address[5] != 0xFF); - } + inline bool Valid() + { + // TODO: More complex MAC validation + return (this->Address[0] != 0 || + this->Address[1] != 0 || + this->Address[2] != 0 || + this->Address[3] != 0 || + this->Address[4] != 0 || + this->Address[5] != 0) && + (this->Address[0] != 0xFF || + this->Address[1] != 0xFF || + this->Address[2] != 0xFF || + this->Address[3] != 0xFF || + this->Address[4] != 0xFF || + this->Address[5] != 0xFF); + } - char *ToString() - { - static char Buffer[18]; - sprintf(Buffer, "%02X:%02X:%02X:%02X:%02X:%02X", this->Address[0], this->Address[1], this->Address[2], this->Address[3], this->Address[4], this->Address[5]); - return Buffer; - } + char *ToString() + { + static char Buffer[18]; + sprintf(Buffer, "%02X:%02X:%02X:%02X:%02X:%02X", this->Address[0], this->Address[1], this->Address[2], this->Address[3], this->Address[4], this->Address[5]); + return Buffer; + } }; /* There's a confusion between LSB and MSB. Not sure if "ToStringLittleEndian" and "ToStringBigEndian" are implemented correctly. Because x86 is a LSB architecture, I'm assuming that the "ToStringLittleEndian" is correct? */ struct InternetProtocol { - struct Version4 - { - uint8_t Address[4] = {255, 255, 255, 255}; - Endianness Endianess = LITTLE_ENDIAN; + struct Version4 + { + uint8_t Address[4] = {255, 255, 255, 255}; + Endianness Endianess = LITTLE_ENDIAN; - inline bool operator==(const InternetProtocol::Version4 &lhs) const - { - return lhs.Address[0] == this->Address[0] && - lhs.Address[1] == this->Address[1] && - lhs.Address[2] == this->Address[2] && - lhs.Address[3] == this->Address[3]; - } + inline bool operator==(const InternetProtocol::Version4 &lhs) const + { + return lhs.Address[0] == this->Address[0] && + lhs.Address[1] == this->Address[1] && + lhs.Address[2] == this->Address[2] && + lhs.Address[3] == this->Address[3]; + } - inline bool operator==(const uint32_t &lhs) const - { - InternetProtocol::Version4 IP; - IP.Address[0] = (uint8_t)((lhs >> 24) & 0xFF); - IP.Address[1] = (uint8_t)((lhs >> 16) & 0xFF); - IP.Address[2] = (uint8_t)((lhs >> 8) & 0xFF); - IP.Address[3] = (uint8_t)(lhs & 0xFF); + inline bool operator==(const uint32_t &lhs) const + { + InternetProtocol::Version4 IP; + IP.Address[0] = (uint8_t)((lhs >> 24) & 0xFF); + IP.Address[1] = (uint8_t)((lhs >> 16) & 0xFF); + IP.Address[2] = (uint8_t)((lhs >> 8) & 0xFF); + IP.Address[3] = (uint8_t)(lhs & 0xFF); - return IP.Address[0] == this->Address[0] && - IP.Address[1] == this->Address[1] && - IP.Address[2] == this->Address[2] && - IP.Address[3] == this->Address[3]; - } + return IP.Address[0] == this->Address[0] && + IP.Address[1] == this->Address[1] && + IP.Address[2] == this->Address[2] && + IP.Address[3] == this->Address[3]; + } - inline bool operator!=(const InternetProtocol::Version4 &lhs) const { return !(*this == lhs); } - inline bool operator!=(const uint32_t &lhs) const { return !(*this == lhs); } + inline bool operator!=(const InternetProtocol::Version4 &lhs) const { return !(*this == lhs); } + inline bool operator!=(const uint32_t &lhs) const { return !(*this == lhs); } - inline uint32_t ToHex() - { - return ((uint32_t)this->Address[0] << 24) | - ((uint32_t)this->Address[1] << 16) | - ((uint32_t)this->Address[2] << 8) | - ((uint32_t)this->Address[3]); - } + inline uint32_t ToHex() + { + return ((uint32_t)this->Address[0] << 24) | + ((uint32_t)this->Address[1] << 16) | + ((uint32_t)this->Address[2] << 8) | + ((uint32_t)this->Address[3]); + } - inline InternetProtocol::Version4 FromHex(uint32_t Hex) - { - this->Address[0] = (uint8_t)((Hex >> 24) & 0xFF); - this->Address[1] = (uint8_t)((Hex >> 16) & 0xFF); - this->Address[2] = (uint8_t)((Hex >> 8) & 0xFF); - this->Address[3] = (uint8_t)(Hex & 0xFF); - return *this; - } + inline InternetProtocol::Version4 FromHex(uint32_t Hex) + { + this->Address[0] = (uint8_t)((Hex >> 24) & 0xFF); + this->Address[1] = (uint8_t)((Hex >> 16) & 0xFF); + this->Address[2] = (uint8_t)((Hex >> 8) & 0xFF); + this->Address[3] = (uint8_t)(Hex & 0xFF); + return *this; + } - char *ToStringLittleEndian() - { - static char Buffer[16]; - sprintf(Buffer, "%d.%d.%d.%d", this->Address[0], this->Address[1], this->Address[2], this->Address[3]); - return Buffer; - } + char *ToStringLittleEndian() + { + static char Buffer[16]; + sprintf(Buffer, "%d.%d.%d.%d", this->Address[0], this->Address[1], this->Address[2], this->Address[3]); + return Buffer; + } - char *ToStringBigEndian() - { - static char Buffer[16]; - sprintf(Buffer, "%d.%d.%d.%d", this->Address[3], this->Address[2], this->Address[1], this->Address[0]); - return Buffer; - } - } v4; + char *ToStringBigEndian() + { + static char Buffer[16]; + sprintf(Buffer, "%d.%d.%d.%d", this->Address[3], this->Address[2], this->Address[1], this->Address[0]); + return Buffer; + } + } v4; - struct Version6 - { - uint16_t Address[8] = {0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF}; - Endianness Endianess = LITTLE_ENDIAN; + struct Version6 + { + uint16_t Address[8] = {0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF}; + Endianness Endianess = LITTLE_ENDIAN; - inline bool operator==(const InternetProtocol::Version6 &lhs) const - { - return lhs.Address[0] == this->Address[0] && - lhs.Address[1] == this->Address[1] && - lhs.Address[2] == this->Address[2] && - lhs.Address[3] == this->Address[3] && - lhs.Address[4] == this->Address[4] && - lhs.Address[5] == this->Address[5] && - lhs.Address[6] == this->Address[6] && - lhs.Address[7] == this->Address[7]; - } + inline bool operator==(const InternetProtocol::Version6 &lhs) const + { + return lhs.Address[0] == this->Address[0] && + lhs.Address[1] == this->Address[1] && + lhs.Address[2] == this->Address[2] && + lhs.Address[3] == this->Address[3] && + lhs.Address[4] == this->Address[4] && + lhs.Address[5] == this->Address[5] && + lhs.Address[6] == this->Address[6] && + lhs.Address[7] == this->Address[7]; + } - inline bool operator!=(const InternetProtocol::Version6 &lhs) const { return !(*this == lhs); } + inline bool operator!=(const InternetProtocol::Version6 &lhs) const { return !(*this == lhs); } - char *ToStringLittleEndian() - { - static char Buffer[40]; - sprintf(Buffer, "%04X:%04X:%04X:%04X:%04X:%04X:%04X:%04X", this->Address[0], this->Address[1], this->Address[2], this->Address[3], this->Address[4], this->Address[5], this->Address[6], this->Address[7]); - return Buffer; - } + char *ToStringLittleEndian() + { + static char Buffer[40]; + sprintf(Buffer, "%04X:%04X:%04X:%04X:%04X:%04X:%04X:%04X", this->Address[0], this->Address[1], this->Address[2], this->Address[3], this->Address[4], this->Address[5], this->Address[6], this->Address[7]); + return Buffer; + } - char *ToStringBigEndian() - { - static char Buffer[40]; - sprintf(Buffer, "%04X:%04X:%04X:%04X:%04X:%04X:%04X:%04X", this->Address[7], this->Address[6], this->Address[5], this->Address[4], this->Address[3], this->Address[2], this->Address[1], this->Address[0]); - return Buffer; - } - } v6; + char *ToStringBigEndian() + { + static char Buffer[40]; + sprintf(Buffer, "%04X:%04X:%04X:%04X:%04X:%04X:%04X:%04X", this->Address[7], this->Address[6], this->Address[5], this->Address[4], this->Address[3], this->Address[2], this->Address[1], this->Address[0]); + return Buffer; + } + } v6; }; uint16_t CalculateChecksum(uint16_t *Data, size_t Length); diff --git a/include/net/ntp.hpp b/include/net/ntp.hpp index 129a91b..d325a45 100644 --- a/include/net/ntp.hpp +++ b/include/net/ntp.hpp @@ -23,144 +23,144 @@ namespace NetworkNTP { - struct NTPHeader - { - /** @brief Leap indicator - * 00 - no warning - * 01 - last minute has 61 seconds - * 10 - last minute has 59 seconds - * 11 - alarm condition (clock not synchronized) - */ - uint8_t LeapIndicator : 2; - /** @brief Version number of the protocol - * 3 - IPv4 only - * 4 - IPv4, IPv6 and OSI - * 5 - IPv4, IPv6 and OSI - * 6 - IPv4, IPv6 and OSI - * 7 - IPv4, IPv6 and OSI - */ - uint8_t VersionNumber : 3; - /** @brief Mode - * 0 - reserved - * 1 - symmetric active - * 2 - symmetric passive - * 3 - client - * 4 - server - * 5 - broadcast - * 6 - reserved for NTP control message - * 7 - reserved for private use - */ - uint8_t Mode : 3; - /** @brief Stratum - * 0 - unspecified or unavailable - * 1 - primary reference (e.g. radio clock) - * 2-15 - secondary reference (via NTP or SNTP) - * 16 - unsynchronized - * 17-255 - reserved - */ - uint8_t Stratum; - /** @brief Polling interval - * 4 - 16 seconds - * 5 - 32 seconds - * 6 - 64 seconds - * 7 - 128 seconds - * 8 - 256 seconds - * 9 - 512 seconds - * 10 - 1024 seconds - * 11 - 2048 seconds - * 12 - 4096 seconds - * 13 - 8192 seconds - * 14 - 16384 seconds - * 15 - 32768 seconds - */ - uint8_t Poll; - /** @brief Precision - * -6 - 0.015625 seconds - * -5 - 0.03125 seconds - * -4 - 0.0625 seconds - * -3 - 0.125 seconds - * -2 - 0.25 seconds - * -1 - 0.5 seconds - * 0 - 1 second - * 1 - 2 seconds - * 2 - 4 seconds - * 3 - 8 seconds - * 4 - 16 seconds - * 5 - 32 seconds - * 6 - 64 seconds - * 7 - 128 seconds - */ - uint8_t Precision; - /** @brief Root delay - * Total round trip delay to the primary reference source - */ - uint32_t RootDelay; - /** @brief Root dispersion - * Nominal error relative to the primary reference source - */ - uint32_t RootDispersion; - /** @brief Reference identifier - * 0x00000000 - unspecified - * 0x00000001 - radio clock - * 0x00000002 - atomic clock - * 0x00000003 - GPS receiver - * 0x00000004 - local oscillator - * 0x00000005 - LORAN-C receiver - * 0x00000006 - microprocessor - * 0x00000007 - internet - * 0x00000008 - FLL - * 0x00000009 - other - * 0x0000000A - WWV - * 0x0000000B - WWVB - * 0x0000000C - WWVH - * 0x0000000D - NIST dialup - * 0x0000000E - telephone - * 0x0000000F - reserved - */ - uint32_t ReferenceIdentifier; - /** @brief Reference timestamp - * The time at which the clock was last set or corrected - */ - uint32_t ReferenceTimestamp[2]; - /** @brief Originate timestamp - * The time at which the request departed the client for the server - */ - uint32_t OriginateTimestamp[2]; - /** @brief Receive timestamp - * The time at which the request arrived at the server - */ - uint32_t ReceiveTimestamp[2]; - /** @brief Transmit timestamp - * The time at which the reply departed the server for the client - */ - uint32_t TransmitTimestamp[2]; - /** @brief Message authentication code - * Key identifier - * @note Only when the NTP authentication scheme is used - */ - // uint32_t MessageAuthenticationCode; - } __packed; + struct NTPHeader + { + /** @brief Leap indicator + * 00 - no warning + * 01 - last minute has 61 seconds + * 10 - last minute has 59 seconds + * 11 - alarm condition (clock not synchronized) + */ + uint8_t LeapIndicator : 2; + /** @brief Version number of the protocol + * 3 - IPv4 only + * 4 - IPv4, IPv6 and OSI + * 5 - IPv4, IPv6 and OSI + * 6 - IPv4, IPv6 and OSI + * 7 - IPv4, IPv6 and OSI + */ + uint8_t VersionNumber : 3; + /** @brief Mode + * 0 - reserved + * 1 - symmetric active + * 2 - symmetric passive + * 3 - client + * 4 - server + * 5 - broadcast + * 6 - reserved for NTP control message + * 7 - reserved for private use + */ + uint8_t Mode : 3; + /** @brief Stratum + * 0 - unspecified or unavailable + * 1 - primary reference (e.g. radio clock) + * 2-15 - secondary reference (via NTP or SNTP) + * 16 - unsynchronized + * 17-255 - reserved + */ + uint8_t Stratum; + /** @brief Polling interval + * 4 - 16 seconds + * 5 - 32 seconds + * 6 - 64 seconds + * 7 - 128 seconds + * 8 - 256 seconds + * 9 - 512 seconds + * 10 - 1024 seconds + * 11 - 2048 seconds + * 12 - 4096 seconds + * 13 - 8192 seconds + * 14 - 16384 seconds + * 15 - 32768 seconds + */ + uint8_t Poll; + /** @brief Precision + * -6 - 0.015625 seconds + * -5 - 0.03125 seconds + * -4 - 0.0625 seconds + * -3 - 0.125 seconds + * -2 - 0.25 seconds + * -1 - 0.5 seconds + * 0 - 1 second + * 1 - 2 seconds + * 2 - 4 seconds + * 3 - 8 seconds + * 4 - 16 seconds + * 5 - 32 seconds + * 6 - 64 seconds + * 7 - 128 seconds + */ + uint8_t Precision; + /** @brief Root delay + * Total round trip delay to the primary reference source + */ + uint32_t RootDelay; + /** @brief Root dispersion + * Nominal error relative to the primary reference source + */ + uint32_t RootDispersion; + /** @brief Reference identifier + * 0x00000000 - unspecified + * 0x00000001 - radio clock + * 0x00000002 - atomic clock + * 0x00000003 - GPS receiver + * 0x00000004 - local oscillator + * 0x00000005 - LORAN-C receiver + * 0x00000006 - microprocessor + * 0x00000007 - internet + * 0x00000008 - FLL + * 0x00000009 - other + * 0x0000000A - WWV + * 0x0000000B - WWVB + * 0x0000000C - WWVH + * 0x0000000D - NIST dialup + * 0x0000000E - telephone + * 0x0000000F - reserved + */ + uint32_t ReferenceIdentifier; + /** @brief Reference timestamp + * The time at which the clock was last set or corrected + */ + uint32_t ReferenceTimestamp[2]; + /** @brief Originate timestamp + * The time at which the request departed the client for the server + */ + uint32_t OriginateTimestamp[2]; + /** @brief Receive timestamp + * The time at which the request arrived at the server + */ + uint32_t ReceiveTimestamp[2]; + /** @brief Transmit timestamp + * The time at which the reply departed the server for the client + */ + uint32_t TransmitTimestamp[2]; + /** @brief Message authentication code + * Key identifier + * @note Only when the NTP authentication scheme is used + */ + // uint32_t MessageAuthenticationCode; + } __packed; - class NTP : public NetworkUDP::UDPEvents - { - private: - NetworkUDP::Socket *UDPSocket; - bool TimeReceived = false; - NTPHeader NTPPacket; + class NTP : public NetworkUDP::UDPEvents + { + private: + NetworkUDP::Socket *UDPSocket; + bool TimeReceived = false; + NTPHeader NTPPacket; - virtual void OnUDPPacketReceived(NetworkUDP::Socket *Socket, uint8_t *Data, size_t Length); + virtual void OnUDPPacketReceived(NetworkUDP::Socket *Socket, uint8_t *Data, size_t Length); - public: - NTP(NetworkUDP::Socket *Socket); - ~NTP(); + public: + NTP(NetworkUDP::Socket *Socket); + ~NTP(); - /** - * @brief Get the time from the NTP server - * - * @return Unix Timestamp - */ - int ReadTime(); - }; + /** + * @brief Get the time from the NTP server + * + * @return Unix Timestamp + */ + int ReadTime(); + }; } #endif // !__FENNIX_KERNEL_NTP_H__ diff --git a/include/net/udp.hpp b/include/net/udp.hpp index 1278755..25dc6a9 100644 --- a/include/net/udp.hpp +++ b/include/net/udp.hpp @@ -25,73 +25,73 @@ namespace NetworkUDP { - struct UDPHeader - { - uint16_t SourcePort; - uint16_t DestinationPort; - uint16_t Length; - uint16_t Checksum; - } __packed; + struct UDPHeader + { + uint16_t SourcePort; + uint16_t DestinationPort; + uint16_t Length; + uint16_t Checksum; + } __packed; - struct UDPPacket - { - UDPHeader Header; - uint8_t Data[]; - }; + struct UDPPacket + { + UDPHeader Header; + uint8_t Data[]; + }; - class Socket; + class Socket; - class UDPEvents - { - protected: - UDPEvents(); - ~UDPEvents(); + class UDPEvents + { + protected: + UDPEvents(); + ~UDPEvents(); - public: - virtual void OnUDPPacketReceived(Socket *Socket, uint8_t *Data, size_t Length) - { - UNUSED(Socket); - UNUSED(Data); - UNUSED(Length); - warn("Not implemented."); - } - }; + public: + virtual void OnUDPPacketReceived(Socket *Socket, uint8_t *Data, size_t Length) + { + UNUSED(Socket); + UNUSED(Data); + UNUSED(Length); + warn("Not implemented."); + } + }; - class UDP : public NetworkIPv4::IPv4Events - { - private: - NetworkIPv4::IPv4 *ipv4; - NetworkInterfaceManager::DeviceInterface *Interface; + class UDP : public NetworkIPv4::IPv4Events + { + private: + NetworkIPv4::IPv4 *ipv4; + NetworkInterfaceManager::DeviceInterface *Interface; - public: - NetworkInterfaceManager::DeviceInterface *GetInterface() { return this->Interface; } + public: + NetworkInterfaceManager::DeviceInterface *GetInterface() { return this->Interface; } - UDP(NetworkIPv4::IPv4 *ipv4, NetworkInterfaceManager::DeviceInterface *Interface); - ~UDP(); + UDP(NetworkIPv4::IPv4 *ipv4, NetworkInterfaceManager::DeviceInterface *Interface); + ~UDP(); - virtual Socket *Connect(InternetProtocol IP, uint16_t Port); - virtual Socket *Listen(uint16_t Port); - virtual void Disconnect(Socket *Socket); - virtual void Send(Socket *Socket, uint8_t *Data, size_t Length); - virtual void Bind(Socket *Socket, UDPEvents *EventHandler); + virtual Socket *Connect(InternetProtocol IP, uint16_t Port); + virtual Socket *Listen(uint16_t Port); + virtual void Disconnect(Socket *Socket); + virtual void Send(Socket *Socket, uint8_t *Data, size_t Length); + virtual void Bind(Socket *Socket, UDPEvents *EventHandler); - virtual bool OnIPv4PacketReceived(InternetProtocol SourceIP, InternetProtocol DestinationIP, uint8_t *Data, size_t Length); - }; + virtual bool OnIPv4PacketReceived(InternetProtocol SourceIP, InternetProtocol DestinationIP, uint8_t *Data, size_t Length); + }; - class Socket - { - public: - InternetProtocol LocalIP; - uint16_t LocalPort = 0; - InternetProtocol RemoteIP; - uint16_t RemotePort = 0; - bool Listening = false; - UDPEvents *EventHandler = nullptr; - UDP *SocketUDP = nullptr; + class Socket + { + public: + InternetProtocol LocalIP; + uint16_t LocalPort = 0; + InternetProtocol RemoteIP; + uint16_t RemotePort = 0; + bool Listening = false; + UDPEvents *EventHandler = nullptr; + UDP *SocketUDP = nullptr; - Socket(UDP *_UDP); - ~Socket(); - }; + Socket(UDP *_UDP); + ~Socket(); + }; } #endif // !__FENNIX_KERNEL_UDP_H__ diff --git a/include/pci.hpp b/include/pci.hpp index 0c0881b..f945d81 100644 --- a/include/pci.hpp +++ b/include/pci.hpp @@ -22,7 +22,7 @@ #include #include -#include +#include namespace PCI { @@ -30,6 +30,8 @@ namespace PCI { enum PCIVendors { + Apple = 0x106B, + BusLogic = 0x104B, SymbiosLogic = 0x1000, RedHat = 0x1AF4, REDHat2 = 0x1B36, @@ -120,12 +122,9 @@ namespace PCI uint8_t LatencyTimer; uint8_t HeaderType; uint8_t BIST; - }; + } __packed; - /** - * @brief PCI Header Type 0 - * - */ + /** PCI Header Type 0 */ struct PCIHeader0 { PCIDeviceHeader Header; @@ -147,11 +146,9 @@ namespace PCI uint8_t InterruptPin; uint8_t MinGrant; uint8_t MaxLatency; - }; + } __packed; - /** - * @brief PCI Header Type 1 (PCI-to-PCI Bridge) - */ + /** PCI Header Type 1 (PCI-to-PCI Bridge) */ struct PCIHeader1 { PCIDeviceHeader Header; @@ -179,11 +176,9 @@ namespace PCI uint8_t InterruptLine; uint8_t InterruptPin; uint16_t BridgeControl; - }; + } __packed; - /** - * @brief PCI Header Type 2 (PCI-to-CardBus Bridge) - */ + /** PCI Header Type 2 (PCI-to-CardBus Bridge) */ struct PCIHeader2 { PCIDeviceHeader Header; @@ -209,7 +204,7 @@ namespace PCI uint16_t SubsystemVendorID; uint16_t SubsystemID; uint32_t LegacyBaseAddress; - }; + } __packed; struct DeviceConfig { @@ -227,24 +222,25 @@ namespace PCI uint32_t Bus; uint32_t Device; uint32_t Function; - }; + } __packed; - class PCI + class Manager { private: - std::vector Devices; + std::list Devices; public: - std::vector &GetDevices() { return Devices; } - void MapPCIAddresses(PCIDevice Device, Memory::PageTable *Table = nullptr); + std::list GetDevices() { return Devices; } + void MapPCIAddresses(PCIDevice Device, Memory::PageTable *Table); void EnumerateFunction(uint64_t DeviceAddress, uint32_t Function, PCIDevice dev); void EnumerateDevice(uint64_t BusAddress, uint32_t Device, PCIDevice dev); void EnumerateBus(uint64_t BaseAddress, uint32_t Bus, PCIDevice dev); - std::vector FindPCIDevice(uint8_t Class, uint8_t Subclass, uint8_t ProgIF); - std::vector FindPCIDevice(int VendorID, int DeviceID); + std::list FindPCIDevice(uint8_t Class, uint8_t Subclass, uint8_t ProgIF); + std::list FindPCIDevice(uint16_t VendorID, uint16_t DeviceID); + std::list FindPCIDevice(std::list VendorIDs, std::list DeviceIDs); - PCI(); - ~PCI(); + Manager(); + ~Manager(); }; } diff --git a/include/power.hpp b/include/power.hpp index 88f2762..8a5e64f 100644 --- a/include/power.hpp +++ b/include/power.hpp @@ -22,48 +22,48 @@ namespace Power { - class Power - { - private: - void *acpi = nullptr; - void *dsdt = nullptr; - void *madt = nullptr; + class Power + { + private: + void *acpi = nullptr; + void *dsdt = nullptr; + void *madt = nullptr; - public: - /** - * @brief Get Advanced Configuration and Power Interface. (Available only on x32 and x64) - * - * @return void* (ACPI::ACPI *) - */ - void *GetACPI() { return this->acpi; } + public: + /** + * @brief Get Advanced Configuration and Power Interface. (Available only on x32 and x64) + * + * @return void* (ACPI::ACPI *) + */ + void *GetACPI() { return this->acpi; } - /** - * @brief Get Differentiated System Description Table. (Available only on x32 and x64) - * - * @return void* (ACPI::DSDT *) - */ - void *GetDSDT() { return this->dsdt; } + /** + * @brief Get Differentiated System Description Table. (Available only on x32 and x64) + * + * @return void* (ACPI::DSDT *) + */ + void *GetDSDT() { return this->dsdt; } - /** - * @brief Get Multiple APIC Description Table. (Available only on x32 and x64) - * - * @return void* (ACPI::MADT *) - */ - void *GetMADT() { return this->madt; } + /** + * @brief Get Multiple APIC Description Table. (Available only on x32 and x64) + * + * @return void* (ACPI::MADT *) + */ + void *GetMADT() { return this->madt; } - /** - * @brief Reboot the system. - */ - void Reboot(); + /** + * @brief Reboot the system. + */ + void Reboot(); - /** - * @brief Shutdown the system. - */ - void Shutdown(); + /** + * @brief Shutdown the system. + */ + void Shutdown(); - void InitDSDT(); - Power(); - }; + void InitDSDT(); + Power(); + }; } #endif // !__FENNIX_KERNEL_POWER_H__ diff --git a/include/signal.h b/include/signal.h deleted file mode 100644 index 18884d8..0000000 --- a/include/signal.h +++ /dev/null @@ -1,194 +0,0 @@ -/* - This file is part of Fennix Kernel. - - Fennix Kernel is free software: you can redistribute it and/or - modify it under the terms of the GNU General Public License as - published by the Free Software Foundation, either version 3 of - the License, or (at your option) any later version. - - Fennix Kernel is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Fennix Kernel. If not, see . -*/ - -#ifndef __FENNIX_KERNEL_SIGNAL_H__ -#define __FENNIX_KERNEL_SIGNAL_H__ - -#include - -enum Signals -{ - /** - * Process abort signal. - */ - SIGABRT, - - /** - * Alarm clock. - */ - SIGALRM, - - /** - * Access to an undefined portion of a memory object. - */ - SIGBUS, - - /** - * Child process terminated, stopped, - */ - SIGCHLD, - - /** - * Continue executing, if stopped. - */ - SIGCONT, - - /** - * Erroneous arithmetic operation. - */ - SIGFPE, - - /** - * Hangup. - */ - SIGHUP, - - /** - * Illegal instruction. - */ - SIGILL, - - /** - * Terminal interrupt signal. - */ - SIGINT, - - /** - * Kill (cannot be caught or ignored). - */ - SIGKILL, - - /** - * Write on a pipe with no one to read it. - */ - SIGPIPE, - - /** - * Terminal quit signal. - */ - SIGQUIT, - - /** - * Invalid memory reference. - */ - SIGSEGV, - - /** - * Stop executing (cannot be caught or ignored). - */ - SIGSTOP, - - /** - * Termination signal. - */ - SIGTERM, - - /** - * Terminal stop signal. - */ - SIGTSTP, - - /** - * Background process attempting read. - */ - SIGTTIN, - - /** - * Background process attempting write. - */ - SIGTTOU, - - /** - * User-defined signal 1. - */ - SIGUSR1, - - /** - * User-defined signal 2. - */ - SIGUSR2, - - /** - * Pollable event. - */ - SIGPOLL, - - /** - * Profiling timer expired. - */ - SIGPROF, - - /** - * Bad system call. - */ - SIGSYS, - - /** - * Trace/breakpoint trap. - */ - SIGTRAP, - - /** - * High bandwidth data is available at a socket. - */ - SIGURG, - - /** - * Virtual timer expired. - */ - SIGVTALRM, - - /** - * CPU time limit exceeded. - */ - SIGXCPU, - - /** - * File size limit exceeded. - */ - SIGXFSZ, -}; - -union sigval -{ - int sival_int; - void *sival_ptr; -}; - -struct sched_param -{ - int sched_priority; -}; - -struct pthread_attr_t -{ - uint64_t sig; - size_t guard_sz; - bool detach; - sched_param sched; -}; - -struct sigevent -{ - int sigev_notify; - int sigev_signo; - union sigval sigev_value; - void (*sigev_notify_function)(union sigval); - pthread_attr_t *sigev_notify_attributes; -}; - -#endif // !__FENNIX_KERNEL_SIGNAL_H__ diff --git a/include/signal.hpp b/include/signal.hpp new file mode 100644 index 0000000..6d5d607 --- /dev/null +++ b/include/signal.hpp @@ -0,0 +1,534 @@ +/* + 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_SIGNAL_H__ +#define __FENNIX_KERNEL_SIGNAL_H__ + +#include +#include +#include +#include +#include + +enum Signals : int +{ + SIG_NULL = 0, + + /** + * Process abort signal. + */ + SIGABRT, + + /** + * Alarm clock. + */ + SIGALRM, + + /** + * Access to an undefined portion of a memory object. + */ + SIGBUS, + + /** + * Child process terminated, stopped, or continued. + */ + SIGCHLD, + + /** + * Continue executing, if stopped. + */ + SIGCONT, + + /** + * Erroneous arithmetic operation. + */ + SIGFPE, + + /** + * Hangup. + */ + SIGHUP, + + /** + * Illegal instruction. + */ + SIGILL, + + /** + * Terminal interrupt signal. + */ + SIGINT, + + /** + * Kill (cannot be caught or ignored). + */ + SIGKILL, + + /** + * Write on a pipe with no one to read it. + */ + SIGPIPE, + + /** + * Terminal quit signal. + */ + SIGQUIT, + + /** + * Invalid memory reference. + */ + SIGSEGV, + + /** + * Stop executing (cannot be caught or ignored). + */ + SIGSTOP, + + /** + * Termination signal. + */ + SIGTERM, + + /** + * Terminal stop signal. + */ + SIGTSTP, + + /** + * Background process attempting read. + */ + SIGTTIN, + + /** + * Background process attempting write. + */ + SIGTTOU, + + /** + * User-defined signal 1. + */ + SIGUSR1, + + /** + * User-defined signal 2. + */ + SIGUSR2, + + /** + * Pollable event. + */ + SIGPOLL, + + /** + * Profiling timer expired. + */ + SIGPROF, + + /** + * Bad system call. + */ + SIGSYS, + + /** + * Trace/breakpoint trap. + */ + SIGTRAP, + + /** + * High bandwidth data is available at a socket. + */ + SIGURG, + + /** + * Virtual timer expired. + */ + SIGVTALRM, + + /** + * CPU time limit exceeded. + */ + SIGXCPU, + + /** + * File size limit exceeded. + */ + SIGXFSZ, + + /** + * Reserved + * + * These are just to match Linux's signal numbers. + */ + SIGRSV1, + SIGRSV2, + + /** + * Maximum signal number. + */ + SIGNAL_MAX +}; + +enum SignalDisposition +{ + /** + * Terminate the process. + */ + SIG_TERM, + + /** + * Ignore the signal. + */ + SIG_IGN, + + /** + * Dump core. + */ + SIG_CORE, + + /** + * Stop the process. + */ + SIG_STOP, + + /** + * Continue the process. + */ + SIG_CONT +}; + +enum SignalAction +{ + SIG_BLOCK, + SIG_UNBLOCK, + SIG_SETMASK +}; + +#define SA_NOCLDSTOP 1 +#define SA_NOCLDWAIT 2 +#define SA_SIGINFO 4 +#define SA_ONSTACK 0x08000000 +#define SA_RESTART 0x10000000 +#define SA_NODEFER 0x40000000 +#define SA_RESETHAND 0x80000000 +#define SA_RESTORER 0x04000000 + +#define __SI_PAD_SIZE \ + (128 - 2 * sizeof(int) - sizeof(long)) + +typedef unsigned long sigset_t; + +union sigval +{ + int sival_int; + void *sival_ptr; +}; + +struct sched_param +{ + int sched_priority; +}; + +struct pthread_attr_t +{ + uint64_t sig; + size_t guard_sz; + bool detach; + sched_param sched; +}; + +struct sigevent +{ + int sigev_notify; + int sigev_signo; + union sigval sigev_value; + void (*sigev_notify_function)(union sigval); + pthread_attr_t *sigev_notify_attributes; +}; + +typedef struct +{ + int si_signo; + int si_errno; + int si_code; + union + { + char __pad[__SI_PAD_SIZE]; + struct + { + union + { + struct + { + pid_t si_pid; + uid_t si_uid; + } __piduid; + struct + { + int si_timerid; + int si_overrun; + } __timer; + } __first; + union + { + union sigval si_value; + struct + { + int si_status; + clock_t si_utime, si_stime; + } __sigchld; + } __second; + } __si_common; + + struct + { + void *si_addr; + short si_addr_lsb; + union + { + struct + { + void *si_lower; + void *si_upper; + } __addr_bnd; + unsigned si_pkey; + } __first; + } __sigfault; + + struct + { + long si_band; + int si_fd; + } __sigpoll; + + struct + { + void *si_call_addr; + int si_syscall; + unsigned si_arch; + } __sigsys; + } __si_fields; +} siginfo_t; + +struct sigaction +{ + union + { + void (*sa_handler)(int); + void (*sa_sigaction)(int, siginfo_t *, void *); + } __sa_handler; + sigset_t sa_mask; + int sa_flags; + void (*sa_restorer)(void); +}; + +namespace Tasking +{ + __no_sanitize("shift") inline __always_inline + sigset_t + ToFlag(sigset_t sig) + { + return 1 << (sig - 1); + } + + inline __always_inline + sigset_t + ToSig(sigset_t flag) + { + return __builtin_ctzl(flag) + 1; + } + + class Signal + { + private: + struct SignalInfo + { + int sig; + union sigval val; + }; + + struct StackInfo + { +#ifdef a64 + CPU::x64::FXState fx; + CPU::x64::TrapFrame tf; + uintptr_t GSBase, FSBase, ShadowGSBase; +#else + CPU::x32::FXState fx; + CPU::x32::TrapFrame tf; + uintptr_t GSBase, FSBase; +#endif + sigset_t SignalMask; + int Compatibility; + +#ifdef DEBUG + // For debugging purposes + char dbg[6] = {'S', 'I', 'G', 'N', 'A', 'L'}; +#endif + } __aligned(16) __packed; + + NewLock(SignalLock); + void *ctx; + Signals LastSignal = SIG_NULL; + + // Signal trampoline + void *TrampAddr = nullptr; + size_t TrampSz = 0; + + std::vector SignalQueue; + std::atomic SignalMask = 0; + sigaction SignalAction[SIGNAL_MAX]{}; + SignalDisposition sigDisp[SIGNAL_MAX]; + std::vector Watchers; + + bool LinuxSig(); + + int ConvertToLinuxIfNecessary(int sig); + int ConvertToNativeIfNecessary(int sig); + + sigset_t ConvertSigsetToLinuxIfNecessary(sigset_t sig); + sigset_t ConvertSigsetToNativeIfNecessary(sigset_t sig); + + int MakeExitCode(int sig); + + const sigset_t nMasks = ToFlag(SIGKILL) | + ToFlag(SIGSTOP) | + ToFlag(SIGCONT) | + ToFlag(SIGSEGV) | + ToFlag(SIGBUS) | + ToFlag(SIGILL) | + ToFlag(SIGFPE); + + const sigset_t lMasks = ToFlag(linux_SIGKILL) | + ToFlag(linux_SIGSTOP) | + ToFlag(linux_SIGCONT) | + ToFlag(linux_SIGSEGV) | + ToFlag(linux_SIGBUS) | + ToFlag(linux_SIGILL) | + ToFlag(linux_SIGFPE); + + void RemoveUnmaskable(sigset_t *sig) + { + if (LinuxSig()) + *sig &= ~lMasks; + else + *sig &= ~nMasks; + } + + bool CanHaveHandler(sigset_t sig) + { + switch (sig) + { + case SIGKILL: + case SIGSTOP: + case SIGCONT: + return false; + default: + return true; + } + } + + public: + void *GetContext() { return ctx; } + Signals GetLastSignal() { return LastSignal; } + + int AddWatcher(Signal *who, int sig); + int RemoveWatcher(Signal *who, int sig); + + int AddSignal(int sig, union sigval val); + int RemoveSignal(int sig); + + /** + * For scheduler use only + * @return True if there is a signal to handle + */ + bool HandleSignal(CPU::TrapFrame *tf); + void RestoreHandleSignal(SyscallsFrame *tf); + + /** + * Mask a signal + * + * @param sig The signal to set + * + * @return Old mask + */ + sigset_t Block(sigset_t sig); + + /** + * Unmask a signal + * + * @param sig The signal to set + * + * @return Old mask + */ + sigset_t Unblock(sigset_t sig); + + /** + * Set the signal mask + * + * @param sig The signal to set + * + * @return Old mask + */ + sigset_t SetMask(sigset_t sig); + + sigset_t GetMask() { return SignalMask.load(); } + + int SetAction(int sig, const sigaction act); + int GetAction(int sig, sigaction *act); + + /** + * Send a signal to the process + * + * @param sig The signal to send + * (compatibility specific) + * @param val The value to send + * + * @return 0 on success, -errno on error + */ + int SendSignal(int sig, union sigval val = {0}); + + int WaitAnySignal(); + + /** + * Wait for a signal + * + * @param sig The signal to wait for + * (compatibility specific) + * @param val The value to wait for + * + * @return 0 on success, -errno on error + */ + int WaitSignal(int sig, union sigval *val); + + /** + * Wait for a signal with a timeout + * + * @param sig The signal to wait for + * (compatibility specific) + * @param val The value to wait for + * @param timeout The timeout to wait for + * + * @return 0 on success, -errno on error + */ + int WaitSignalTimeout(int sig, union sigval *val, uint64_t timeout); + + Signal(void *ctx); + ~Signal(); + }; +} + +#endif // !__FENNIX_KERNEL_SIGNAL_H__ diff --git a/include/smp.hpp b/include/smp.hpp index 56596b9..20af0b6 100644 --- a/include/smp.hpp +++ b/include/smp.hpp @@ -24,7 +24,7 @@ #include /** @brief Maximum supported number of CPU cores by the kernel */ -#define MAX_CPU 256 +#define MAX_CPU 255 #define CPU_DATA_CHECKSUM 0xC0FFEE struct CPUArchData diff --git a/include/symbols.hpp b/include/symbols.hpp index cd7bf26..b38bad2 100644 --- a/include/symbols.hpp +++ b/include/symbols.hpp @@ -31,17 +31,20 @@ namespace SymbolResolver }; std::vector SymTable; - void *Image; + void *Image = nullptr; bool SymbolTableExists = false; public: decltype(SymbolTableExists) &SymTableExists = this->SymbolTableExists; + std::vector &GetSymTable() { return this->SymTable; } void *GetImage() { return this->Image; } - const char *GetSymbolFromAddress(uintptr_t Address); + const char *GetSymbol(uintptr_t Address); + uintptr_t GetSymbol(const char *Name); void AddSymbol(uintptr_t Address, const char *Name); void AddSymbolInfoFromGRUB(uint64_t Num, uint64_t EntSize, uint64_t Shndx, uintptr_t Sections); void AppendSymbols(uintptr_t ImageAddress, uintptr_t BaseAddress = 0); Symbols(uintptr_t ImageAddress); + Symbols() {} ~Symbols(); }; } diff --git a/include/syscall/linux/defs.hpp b/include/syscall/linux/defs.hpp new file mode 100644 index 0000000..fe00fb2 --- /dev/null +++ b/include/syscall/linux/defs.hpp @@ -0,0 +1,233 @@ +/* + 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_LINUX_DEFS_H__ +#define __FENNIX_KERNEL_LINUX_DEFS_H__ + +#include + +#define ARCH_SET_GS 0x1001 +#define ARCH_SET_FS 0x1002 +#define ARCH_GET_FS 0x1003 +#define ARCH_GET_GS 0x1004 + +#define ARCH_GET_CPUID 0x1011 +#define ARCH_SET_CPUID 0x1012 + +#define ARCH_GET_XCOMP_SUPP 0x1021 +#define ARCH_GET_XCOMP_PERM 0x1022 +#define ARCH_REQ_XCOMP_PERM 0x1023 +#define ARCH_GET_XCOMP_GUEST_PERM 0x1024 +#define ARCH_REQ_XCOMP_GUEST_PERM 0x1025 + +#define ARCH_XCOMP_TILECFG 17 +#define ARCH_XCOMP_TILEDATA 18 + +#define ARCH_MAP_VDSO_X32 0x2001 +#define ARCH_MAP_VDSO_32 0x2002 +#define ARCH_MAP_VDSO_64 0x2003 + +#define ARCH_GET_UNTAG_MASK 0x4001 +#define ARCH_ENABLE_TAGGED_ADDR 0x4002 +#define ARCH_GET_MAX_TAG_BITS 0x4003 +#define ARCH_FORCE_TAGGED_SVA 0x4004 + +#define PROT_NONE 0 +#define PROT_READ 1 +#define PROT_WRITE 2 +#define PROT_EXEC 4 +#define PROT_GROWSDOWN 0x01000000 +#define PROT_GROWSUP 0x02000000 + +#define MAP_TYPE 0x0f + +#define MAP_FILE 0 +#define MAP_SHARED 0x01 +#define MAP_PRIVATE 0x02 +#define MAP_SHARED_VALIDATE 0x03 +#define MAP_FIXED 0x10 +#define MAP_ANONYMOUS 0x20 +#define MAP_NORESERVE 0x4000 +#define MAP_GROWSDOWN 0x0100 +#define MAP_DENYWRITE 0x0800 +#define MAP_EXECUTABLE 0x1000 +#define MAP_LOCKED 0x2000 +#define MAP_POPULATE 0x8000 +#define MAP_NONBLOCK 0x10000 +#define MAP_STACK 0x20000 +#define MAP_HUGETLB 0x40000 +#define MAP_SYNC 0x80000 +#define MAP_FIXED_NOREPLACE 0x100000 + +#define CLOCK_REALTIME 0 +#define CLOCK_MONOTONIC 1 +#define CLOCK_PROCESS_CPUTIME_ID 2 +#define CLOCK_THREAD_CPUTIME_ID 3 +#define CLOCK_MONOTONIC_RAW 4 +#define CLOCK_REALTIME_COARSE 5 +#define CLOCK_MONOTONIC_COARSE 6 +#define CLOCK_BOOTTIME 7 +#define CLOCK_REALTIME_ALARM 8 +#define CLOCK_BOOTTIME_ALARM 9 +#define CLOCK_SGI_CYCLE 10 +#define CLOCK_TAI 11 + +#define GRND_NONBLOCK 0x1 +#define GRND_RANDOM 0x2 +#define GRND_INSECURE 0x4 + +#define RLIMIT_CPU 0 +#define RLIMIT_FSIZE 1 +#define RLIMIT_DATA 2 +#define RLIMIT_STACK 3 +#define RLIMIT_CORE 4 +#define RLIMIT_RSS 5 +#define RLIMIT_NPROC 6 +#define RLIMIT_NOFILE 7 +#define RLIMIT_MEMLOCK 8 +#define RLIMIT_AS 9 +#define RLIMIT_LOCKS 10 +#define RLIMIT_SIGPENDING 11 +#define RLIMIT_MSGQUEUE 12 +#define RLIMIT_NICE 13 +#define RLIMIT_RTPRIO 14 +#define RLIMIT_RTTIME 15 +#define RLIMIT_NLIMITS 16 + +#define F_DUPFD 0 +#define F_GETFD 1 +#define F_SETFD 2 +#define F_GETFL 3 +#define F_SETFL 4 + +#define F_SETOWN 8 +#define F_GETOWN 9 +#define F_SETSIG 10 +#define F_GETSIG 11 + +#if __LONG_MAX == 0x7fffffffL +#define F_GETLK 12 +#define F_SETLK 13 +#define F_SETLKW 14 +#else +#define F_GETLK 5 +#define F_SETLK 6 +#define F_SETLKW 7 +#endif + +#define F_SETOWN_EX 15 +#define F_GETOWN_EX 16 + +#define DT_UNKNOWN 0 +#define DT_FIFO 1 +#define DT_CHR 2 +#define DT_DIR 4 +#define DT_BLK 6 +#define DT_REG 8 +#define DT_LNK 10 +#define DT_SOCK 12 +#define DT_WHT 14 + +#define AT_FDCWD (-100) +#define AT_SYMLINK_NOFOLLOW 0x100 +#define AT_REMOVEDIR 0x200 +#define AT_SYMLINK_FOLLOW 0x400 +#define AT_EACCESS 0x200 +#define AT_NO_AUTOMOUNT 0x800 +#define AT_EMPTY_PATH 0x1000 +#define AT_STATX_SYNC_TYPE 0x6000 +#define AT_STATX_SYNC_AS_STAT 0x0000 +#define AT_STATX_FORCE_SYNC 0x2000 +#define AT_STATX_DONT_SYNC 0x4000 +#define AT_RECURSIVE 0x8000 + +#define LINUX_REBOOT_MAGIC1 0xfee1dead +#define LINUX_REBOOT_MAGIC2 0x28121969 +#define LINUX_REBOOT_MAGIC2A 0x05121996 +#define LINUX_REBOOT_MAGIC2B 0x16041998 +#define LINUX_REBOOT_MAGIC2C 0x20112000 + +#define LINUX_REBOOT_CMD_RESTART 0x01234567 +#define LINUX_REBOOT_CMD_HALT 0xCDEF0123 +#define LINUX_REBOOT_CMD_CAD_ON 0x89ABCDEF +#define LINUX_REBOOT_CMD_CAD_OFF 0x00000000 +#define LINUX_REBOOT_CMD_POWER_OFF 0x4321FEDC +#define LINUX_REBOOT_CMD_RESTART2 0xA1B2C3D4 +#define LINUX_REBOOT_CMD_SW_SUSPEND 0xD000FCE2 +#define LINUX_REBOOT_CMD_KEXEC 0x45584543 + +typedef long __kernel_old_time_t; +typedef long __kernel_suseconds_t; +typedef int clockid_t; + +struct iovec +{ + void *iov_base; + size_t iov_len; +}; + +struct timeval +{ + __kernel_old_time_t tv_sec; + __kernel_suseconds_t tv_usec; +}; + +struct rusage +{ + struct timeval ru_utime; + struct timeval ru_stime; + long ru_maxrss; + long ru_ixrss; + long ru_idrss; + long ru_isrss; + long ru_minflt; + long ru_majflt; + long ru_nswap; + long ru_inblock; + long ru_oublock; + long ru_msgsnd; + long ru_msgrcv; + long ru_nsignals; + long ru_nvcsw; + long ru_nivcsw; +}; + +typedef unsigned long rlim_t; +struct rlimit +{ + rlim_t rlim_cur; /* Soft limit */ + rlim_t rlim_max; /* Hard limit (ceiling for rlim_cur) */ +}; + +struct linux_dirent +{ + unsigned long d_ino; /* Inode number */ + unsigned long d_off; /* Offset to next linux_dirent */ + unsigned short d_reclen; /* Length of this linux_dirent */ + char d_name[]; /* Filename (null-terminated) */ +}; + +struct linux_dirent64 +{ + ino64_t d_ino; /* 64-bit inode number */ + off64_t d_off; /* 64-bit offset to next structure */ + unsigned short d_reclen; /* Size of this dirent */ + unsigned char d_type; /* File type */ + char d_name[]; /* Filename (null-terminated) */ +}; + +#endif // !__FENNIX_KERNEL_LINUX_DEFS_H__ diff --git a/include/syscall/linux/signals.hpp b/include/syscall/linux/signals.hpp new file mode 100644 index 0000000..2c08462 --- /dev/null +++ b/include/syscall/linux/signals.hpp @@ -0,0 +1,56 @@ +/* + 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_LINUX_SIGNALS_H__ +#define __FENNIX_KERNEL_LINUX_SIGNALS_H__ + +#include + +#define linux_SIGHUP 1 +#define linux_SIGINT 2 +#define linux_SIGQUIT 3 +#define linux_SIGILL 4 +#define linux_SIGTRAP 5 +#define linux_SIGABRT 6 +#define linux_SIGBUS 7 +#define linux_SIGFPE 8 +#define linux_SIGKILL 9 +#define linux_SIGUSR1 10 +#define linux_SIGSEGV 11 +#define linux_SIGUSR2 12 +#define linux_SIGPIPE 13 +#define linux_SIGALRM 14 +#define linux_SIGTERM 15 +#define linux_SIGSTKFLT 16 +#define linux_SIGCHLD 17 +#define linux_SIGCONT 18 +#define linux_SIGSTOP 19 +#define linux_SIGTSTP 20 +#define linux_SIGTTIN 21 +#define linux_SIGTTOU 22 +#define linux_SIGURG 23 +#define linux_SIGXCPU 24 +#define linux_SIGXFSZ 25 +#define linux_SIGVTALRM 26 +#define linux_SIGPROF 27 +#define linux_SIGWINCH 28 +#define linux_SIGPOLL 29 +#define linux_SIGPWR 30 +#define linux_SIGSYS 31 +#define linux_SIGUNUSED linux_SIGSYS + +#endif // !__FENNIX_KERNEL_LINUX_SIGNALS_H__ diff --git a/include/syscall/linux/syscalls_amd64.hpp b/include/syscall/linux/syscalls_amd64.hpp new file mode 100644 index 0000000..0c3676d --- /dev/null +++ b/include/syscall/linux/syscalls_amd64.hpp @@ -0,0 +1,381 @@ +/* + 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_LINUX_SYSCALLS_x64_H__ +#define __FENNIX_KERNEL_LINUX_SYSCALLS_x64_H__ + +#include + +#define __NR_amd64_read 0 +#define __NR_amd64_write 1 +#define __NR_amd64_open 2 +#define __NR_amd64_close 3 +#define __NR_amd64_stat 4 +#define __NR_amd64_fstat 5 +#define __NR_amd64_lstat 6 +#define __NR_amd64_poll 7 +#define __NR_amd64_lseek 8 +#define __NR_amd64_mmap 9 +#define __NR_amd64_mprotect 10 +#define __NR_amd64_munmap 11 +#define __NR_amd64_brk 12 +#define __NR_amd64_rt_sigaction 13 +#define __NR_amd64_rt_sigprocmask 14 +#define __NR_amd64_rt_sigreturn 15 +#define __NR_amd64_ioctl 16 +#define __NR_amd64_pread64 17 +#define __NR_amd64_pwrite64 18 +#define __NR_amd64_readv 19 +#define __NR_amd64_writev 20 +#define __NR_amd64_access 21 +#define __NR_amd64_pipe 22 +#define __NR_amd64_select 23 +#define __NR_amd64_sched_yield 24 +#define __NR_amd64_mremap 25 +#define __NR_amd64_msync 26 +#define __NR_amd64_mincore 27 +#define __NR_amd64_madvise 28 +#define __NR_amd64_shmget 29 +#define __NR_amd64_shmat 30 +#define __NR_amd64_shmctl 31 +#define __NR_amd64_dup 32 +#define __NR_amd64_dup2 33 +#define __NR_amd64_pause 34 +#define __NR_amd64_nanosleep 35 +#define __NR_amd64_getitimer 36 +#define __NR_amd64_alarm 37 +#define __NR_amd64_setitimer 38 +#define __NR_amd64_getpid 39 +#define __NR_amd64_sendfile 40 +#define __NR_amd64_socket 41 +#define __NR_amd64_connect 42 +#define __NR_amd64_accept 43 +#define __NR_amd64_sendto 44 +#define __NR_amd64_recvfrom 45 +#define __NR_amd64_sendmsg 46 +#define __NR_amd64_recvmsg 47 +#define __NR_amd64_shutdown 48 +#define __NR_amd64_bind 49 +#define __NR_amd64_listen 50 +#define __NR_amd64_getsockname 51 +#define __NR_amd64_getpeername 52 +#define __NR_amd64_socketpair 53 +#define __NR_amd64_setsockopt 54 +#define __NR_amd64_getsockopt 55 +#define __NR_amd64_clone 56 +#define __NR_amd64_fork 57 +#define __NR_amd64_vfork 58 +#define __NR_amd64_execve 59 +#define __NR_amd64_exit 60 +#define __NR_amd64_wait4 61 +#define __NR_amd64_kill 62 +#define __NR_amd64_uname 63 +#define __NR_amd64_semget 64 +#define __NR_amd64_semop 65 +#define __NR_amd64_semctl 66 +#define __NR_amd64_shmdt 67 +#define __NR_amd64_msgget 68 +#define __NR_amd64_msgsnd 69 +#define __NR_amd64_msgrcv 70 +#define __NR_amd64_msgctl 71 +#define __NR_amd64_fcntl 72 +#define __NR_amd64_flock 73 +#define __NR_amd64_fsync 74 +#define __NR_amd64_fdatasync 75 +#define __NR_amd64_truncate 76 +#define __NR_amd64_ftruncate 77 +#define __NR_amd64_getdents 78 +#define __NR_amd64_getcwd 79 +#define __NR_amd64_chdir 80 +#define __NR_amd64_fchdir 81 +#define __NR_amd64_rename 82 +#define __NR_amd64_mkdir 83 +#define __NR_amd64_rmdir 84 +#define __NR_amd64_creat 85 +#define __NR_amd64_link 86 +#define __NR_amd64_unlink 87 +#define __NR_amd64_symlink 88 +#define __NR_amd64_readlink 89 +#define __NR_amd64_chmod 90 +#define __NR_amd64_fchmod 91 +#define __NR_amd64_chown 92 +#define __NR_amd64_fchown 93 +#define __NR_amd64_lchown 94 +#define __NR_amd64_umask 95 +#define __NR_amd64_gettimeofday 96 +#define __NR_amd64_getrlimit 97 +#define __NR_amd64_getrusage 98 +#define __NR_amd64_sysinfo 99 +#define __NR_amd64_times 100 +#define __NR_amd64_ptrace 101 +#define __NR_amd64_getuid 102 +#define __NR_amd64_syslog 103 +#define __NR_amd64_getgid 104 +#define __NR_amd64_setuid 105 +#define __NR_amd64_setgid 106 +#define __NR_amd64_geteuid 107 +#define __NR_amd64_getegid 108 +#define __NR_amd64_setpgid 109 +#define __NR_amd64_getppid 110 +#define __NR_amd64_getpgrp 111 +#define __NR_amd64_setsid 112 +#define __NR_amd64_setreuid 113 +#define __NR_amd64_setregid 114 +#define __NR_amd64_getgroups 115 +#define __NR_amd64_setgroups 116 +#define __NR_amd64_setresuid 117 +#define __NR_amd64_getresuid 118 +#define __NR_amd64_setresgid 119 +#define __NR_amd64_getresgid 120 +#define __NR_amd64_getpgid 121 +#define __NR_amd64_setfsuid 122 +#define __NR_amd64_setfsgid 123 +#define __NR_amd64_getsid 124 +#define __NR_amd64_capget 125 +#define __NR_amd64_capset 126 +#define __NR_amd64_rt_sigpending 127 +#define __NR_amd64_rt_sigtimedwait 128 +#define __NR_amd64_rt_sigqueueinfo 129 +#define __NR_amd64_rt_sigsuspend 130 +#define __NR_amd64_sigaltstack 131 +#define __NR_amd64_utime 132 +#define __NR_amd64_mknod 133 +#define __NR_amd64_uselib 134 +#define __NR_amd64_personality 135 +#define __NR_amd64_ustat 136 +#define __NR_amd64_statfs 137 +#define __NR_amd64_fstatfs 138 +#define __NR_amd64_sysfs 139 +#define __NR_amd64_getpriority 140 +#define __NR_amd64_setpriority 141 +#define __NR_amd64_sched_setparam 142 +#define __NR_amd64_sched_getparam 143 +#define __NR_amd64_sched_setscheduler 144 +#define __NR_amd64_sched_getscheduler 145 +#define __NR_amd64_sched_get_priority_max 146 +#define __NR_amd64_sched_get_priority_min 147 +#define __NR_amd64_sched_rr_get_interval 148 +#define __NR_amd64_mlock 149 +#define __NR_amd64_munlock 150 +#define __NR_amd64_mlockall 151 +#define __NR_amd64_munlockall 152 +#define __NR_amd64_vhangup 153 +#define __NR_amd64_modify_ldt 154 +#define __NR_amd64_pivot_root 155 +#define __NR_amd64__sysctl 156 +#define __NR_amd64_prctl 157 +#define __NR_amd64_arch_prctl 158 +#define __NR_amd64_adjtimex 159 +#define __NR_amd64_setrlimit 160 +#define __NR_amd64_chroot 161 +#define __NR_amd64_sync 162 +#define __NR_amd64_acct 163 +#define __NR_amd64_settimeofday 164 +#define __NR_amd64_mount 165 +#define __NR_amd64_umount2 166 +#define __NR_amd64_swapon 167 +#define __NR_amd64_swapoff 168 +#define __NR_amd64_reboot 169 +#define __NR_amd64_sethostname 170 +#define __NR_amd64_setdomainname 171 +#define __NR_amd64_iopl 172 +#define __NR_amd64_ioperm 173 +#define __NR_amd64_create_module 174 +#define __NR_amd64_init_module 175 +#define __NR_amd64_delete_module 176 +#define __NR_amd64_get_kernel_syms 177 +#define __NR_amd64_query_module 178 +#define __NR_amd64_quotactl 179 +#define __NR_amd64_nfsservctl 180 +#define __NR_amd64_getpmsg 181 +#define __NR_amd64_putpmsg 182 +#define __NR_amd64_afs_syscall 183 +#define __NR_amd64_tuxcall 184 +#define __NR_amd64_security 185 +#define __NR_amd64_gettid 186 +#define __NR_amd64_readahead 187 +#define __NR_amd64_setxattr 188 +#define __NR_amd64_lsetxattr 189 +#define __NR_amd64_fsetxattr 190 +#define __NR_amd64_getxattr 191 +#define __NR_amd64_lgetxattr 192 +#define __NR_amd64_fgetxattr 193 +#define __NR_amd64_listxattr 194 +#define __NR_amd64_llistxattr 195 +#define __NR_amd64_flistxattr 196 +#define __NR_amd64_removexattr 197 +#define __NR_amd64_lremovexattr 198 +#define __NR_amd64_fremovexattr 199 +#define __NR_amd64_tkill 200 +#define __NR_amd64_time 201 +#define __NR_amd64_futex 202 +#define __NR_amd64_sched_setaffinity 203 +#define __NR_amd64_sched_getaffinity 204 +#define __NR_amd64_set_thread_area 205 +#define __NR_amd64_io_setup 206 +#define __NR_amd64_io_destroy 207 +#define __NR_amd64_io_getevents 208 +#define __NR_amd64_io_submit 209 +#define __NR_amd64_io_cancel 210 +#define __NR_amd64_get_thread_area 211 +#define __NR_amd64_lookup_dcookie 212 +#define __NR_amd64_epoll_create 213 +#define __NR_amd64_epoll_ctl_old 214 +#define __NR_amd64_epoll_wait_old 215 +#define __NR_amd64_remap_file_pages 216 +#define __NR_amd64_getdents64 217 +#define __NR_amd64_set_tid_address 218 +#define __NR_amd64_restart_syscall 219 +#define __NR_amd64_semtimedop 220 +#define __NR_amd64_fadvise64 221 +#define __NR_amd64_timer_create 222 +#define __NR_amd64_timer_settime 223 +#define __NR_amd64_timer_gettime 224 +#define __NR_amd64_timer_getoverrun 225 +#define __NR_amd64_timer_delete 226 +#define __NR_amd64_clock_settime 227 +#define __NR_amd64_clock_gettime 228 +#define __NR_amd64_clock_getres 229 +#define __NR_amd64_clock_nanosleep 230 +#define __NR_amd64_exit_group 231 +#define __NR_amd64_epoll_wait 232 +#define __NR_amd64_epoll_ctl 233 +#define __NR_amd64_tgkill 234 +#define __NR_amd64_utimes 235 +#define __NR_amd64_vserver 236 +#define __NR_amd64_mbind 237 +#define __NR_amd64_set_mempolicy 238 +#define __NR_amd64_get_mempolicy 239 +#define __NR_amd64_mq_open 240 +#define __NR_amd64_mq_unlink 241 +#define __NR_amd64_mq_timedsend 242 +#define __NR_amd64_mq_timedreceive 243 +#define __NR_amd64_mq_notify 244 +#define __NR_amd64_mq_getsetattr 245 +#define __NR_amd64_kexec_load 246 +#define __NR_amd64_waitid 247 +#define __NR_amd64_add_key 248 +#define __NR_amd64_request_key 249 +#define __NR_amd64_keyctl 250 +#define __NR_amd64_ioprio_set 251 +#define __NR_amd64_ioprio_get 252 +#define __NR_amd64_inotify_init 253 +#define __NR_amd64_inotify_add_watch 254 +#define __NR_amd64_inotify_rm_watch 255 +#define __NR_amd64_migrate_pages 256 +#define __NR_amd64_openat 257 +#define __NR_amd64_mkdirat 258 +#define __NR_amd64_mknodat 259 +#define __NR_amd64_fchownat 260 +#define __NR_amd64_futimesat 261 +#define __NR_amd64_newfstatat 262 +#define __NR_amd64_unlinkat 263 +#define __NR_amd64_renameat 264 +#define __NR_amd64_linkat 265 +#define __NR_amd64_symlinkat 266 +#define __NR_amd64_readlinkat 267 +#define __NR_amd64_fchmodat 268 +#define __NR_amd64_faccessat 269 +#define __NR_amd64_pselect6 270 +#define __NR_amd64_ppoll 271 +#define __NR_amd64_unshare 272 +#define __NR_amd64_set_robust_list 273 +#define __NR_amd64_get_robust_list 274 +#define __NR_amd64_splice 275 +#define __NR_amd64_tee 276 +#define __NR_amd64_sync_file_range 277 +#define __NR_amd64_vmsplice 278 +#define __NR_amd64_move_pages 279 +#define __NR_amd64_utimensat 280 +#define __NR_amd64_epoll_pwait 281 +#define __NR_amd64_signalfd 282 +#define __NR_amd64_timerfd_create 283 +#define __NR_amd64_eventfd 284 +#define __NR_amd64_fallocate 285 +#define __NR_amd64_timerfd_settime 286 +#define __NR_amd64_timerfd_gettime 287 +#define __NR_amd64_accept4 288 +#define __NR_amd64_signalfd4 289 +#define __NR_amd64_eventfd2 290 +#define __NR_amd64_epoll_create1 291 +#define __NR_amd64_dup3 292 +#define __NR_amd64_pipe2 293 +#define __NR_amd64_inotify_init1 294 +#define __NR_amd64_preadv 295 +#define __NR_amd64_pwritev 296 +#define __NR_amd64_rt_tgsigqueueinfo 297 +#define __NR_amd64_perf_event_open 298 +#define __NR_amd64_recvmmsg 299 +#define __NR_amd64_fanotify_init 300 +#define __NR_amd64_fanotify_mark 301 +#define __NR_amd64_prlimit64 302 +#define __NR_amd64_name_to_handle_at 303 +#define __NR_amd64_open_by_handle_at 304 +#define __NR_amd64_clock_adjtime 305 +#define __NR_amd64_syncfs 306 +#define __NR_amd64_sendmmsg 307 +#define __NR_amd64_setns 308 +#define __NR_amd64_getcpu 309 +#define __NR_amd64_process_vm_readv 310 +#define __NR_amd64_process_vm_writev 311 +#define __NR_amd64_kcmp 312 +#define __NR_amd64_finit_module 313 +#define __NR_amd64_sched_setattr 314 +#define __NR_amd64_sched_getattr 315 +#define __NR_amd64_renameat2 316 +#define __NR_amd64_seccomp 317 +#define __NR_amd64_getrandom 318 +#define __NR_amd64_memfd_create 319 +#define __NR_amd64_kexec_file_load 320 +#define __NR_amd64_bpf 321 +#define __NR_amd64_execveat 322 +#define __NR_amd64_userfaultfd 323 +#define __NR_amd64_membarrier 324 +#define __NR_amd64_mlock2 325 +#define __NR_amd64_copy_file_range 326 +#define __NR_amd64_preadv2 327 +#define __NR_amd64_pwritev2 328 +#define __NR_amd64_pkey_mprotect 329 +#define __NR_amd64_pkey_alloc 330 +#define __NR_amd64_pkey_free 331 +#define __NR_amd64_statx 332 +#define __NR_amd64_io_pgetevents 333 +#define __NR_amd64_rseq 334 +#define __NR_amd64_pidfd_send_signal 424 +#define __NR_amd64_io_uring_setup 425 +#define __NR_amd64_io_uring_enter 426 +#define __NR_amd64_io_uring_register 427 +#define __NR_amd64_open_tree 428 +#define __NR_amd64_move_mount 429 +#define __NR_amd64_fsopen 430 +#define __NR_amd64_fsconfig 431 +#define __NR_amd64_fsmount 432 +#define __NR_amd64_fspick 433 +#define __NR_amd64_pidfd_open 434 +#define __NR_amd64_clone3 435 +#define __NR_amd64_close_range 436 +#define __NR_amd64_openat2 437 +#define __NR_amd64_pidfd_getfd 438 +#define __NR_amd64_faccessat2 439 +#define __NR_amd64_process_madvise 440 +#define __NR_amd64_epoll_pwait2 441 +#define __NR_amd64_mount_setattr 442 +#define __NR_amd64_landlock_create_ruleset 444 +#define __NR_amd64_landlock_add_rule 445 +#define __NR_amd64_landlock_restrict_self 446 + +#endif // !__FENNIX_KERNEL_LINUX_SYSCALLS_x64_H__ diff --git a/include/syscall/linux/syscalls_i386.hpp b/include/syscall/linux/syscalls_i386.hpp new file mode 100644 index 0000000..7bf64e5 --- /dev/null +++ b/include/syscall/linux/syscalls_i386.hpp @@ -0,0 +1,459 @@ +/* + 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_LINUX_SYSCALLS_I386_H__ +#define __FENNIX_KERNEL_LINUX_SYSCALLS_I386_H__ + +#define __NR_i386_restart_syscall 0 +#define __NR_i386_exit 1 +#define __NR_i386_fork 2 +#define __NR_i386_read 3 +#define __NR_i386_write 4 +#define __NR_i386_open 5 +#define __NR_i386_close 6 +#define __NR_i386_waitpid 7 +#define __NR_i386_creat 8 +#define __NR_i386_link 9 +#define __NR_i386_unlink 10 +#define __NR_i386_execve 11 +#define __NR_i386_chdir 12 +#define __NR_i386_time 13 +#define __NR_i386_mknod 14 +#define __NR_i386_chmod 15 +#define __NR_i386_lchown 16 +#define __NR_i386_break 17 +#define __NR_i386_oldstat 18 +#define __NR_i386_lseek 19 +#define __NR_i386_getpid 20 +#define __NR_i386_mount 21 +#define __NR_i386_umount 22 +#define __NR_i386_setuid 23 +#define __NR_i386_getuid 24 +#define __NR_i386_stime 25 +#define __NR_i386_ptrace 26 +#define __NR_i386_alarm 27 +#define __NR_i386_oldfstat 28 +#define __NR_i386_pause 29 +#define __NR_i386_utime 30 +#define __NR_i386_stty 31 +#define __NR_i386_gtty 32 +#define __NR_i386_access 33 +#define __NR_i386_nice 34 +#define __NR_i386_ftime 35 +#define __NR_i386_sync 36 +#define __NR_i386_kill 37 +#define __NR_i386_rename 38 +#define __NR_i386_mkdir 39 +#define __NR_i386_rmdir 40 +#define __NR_i386_dup 41 +#define __NR_i386_pipe 42 +#define __NR_i386_times 43 +#define __NR_i386_prof 44 +#define __NR_i386_brk 45 +#define __NR_i386_setgid 46 +#define __NR_i386_getgid 47 +#define __NR_i386_signal 48 +#define __NR_i386_geteuid 49 +#define __NR_i386_getegid 50 +#define __NR_i386_acct 51 +#define __NR_i386_umount2 52 +#define __NR_i386_lock 53 +#define __NR_i386_ioctl 54 +#define __NR_i386_fcntl 55 +#define __NR_i386_mpx 56 +#define __NR_i386_setpgid 57 +#define __NR_i386_ulimit 58 +#define __NR_i386_oldolduname 59 +#define __NR_i386_umask 60 +#define __NR_i386_chroot 61 +#define __NR_i386_ustat 62 +#define __NR_i386_dup2 63 +#define __NR_i386_getppid 64 +#define __NR_i386_getpgrp 65 +#define __NR_i386_setsid 66 +#define __NR_i386_sigaction 67 +#define __NR_i386_sgetmask 68 +#define __NR_i386_ssetmask 69 +#define __NR_i386_setreuid 70 +#define __NR_i386_setregid 71 +#define __NR_i386_sigsuspend 72 +#define __NR_i386_sigpending 73 +#define __NR_i386_sethostname 74 +#define __NR_i386_setrlimit 75 +#define __NR_i386_getrlimit 76 +#define __NR_i386_getrusage 77 +#define __NR_i386_gettimeofday_time32 78 +#define __NR_i386_settimeofday_time32 79 +#define __NR_i386_getgroups 80 +#define __NR_i386_setgroups 81 +#define __NR_i386_select 82 +#define __NR_i386_symlink 83 +#define __NR_i386_oldlstat 84 +#define __NR_i386_readlink 85 +#define __NR_i386_uselib 86 +#define __NR_i386_swapon 87 +#define __NR_i386_reboot 88 +#define __NR_i386_readdir 89 +#define __NR_i386_mmap 90 +#define __NR_i386_munmap 91 +#define __NR_i386_truncate 92 +#define __NR_i386_ftruncate 93 +#define __NR_i386_fchmod 94 +#define __NR_i386_fchown 95 +#define __NR_i386_getpriority 96 +#define __NR_i386_setpriority 97 +#define __NR_i386_profil 98 +#define __NR_i386_statfs 99 +#define __NR_i386_fstatfs 100 +#define __NR_i386_ioperm 101 +#define __NR_i386_socketcall 102 +#define __NR_i386_syslog 103 +#define __NR_i386_setitimer 104 +#define __NR_i386_getitimer 105 +#define __NR_i386_stat 106 +#define __NR_i386_lstat 107 +#define __NR_i386_fstat 108 +#define __NR_i386_olduname 109 +#define __NR_i386_iopl 110 +#define __NR_i386_vhangup 111 +#define __NR_i386_idle 112 +#define __NR_i386_vm86old 113 +#define __NR_i386_wait4 114 +#define __NR_i386_swapoff 115 +#define __NR_i386_sysinfo 116 +#define __NR_i386_ipc 117 +#define __NR_i386_fsync 118 +#define __NR_i386_sigreturn 119 +#define __NR_i386_clone 120 +#define __NR_i386_setdomainname 121 +#define __NR_i386_uname 122 +#define __NR_i386_modify_ldt 123 +#define __NR_i386_adjtimex 124 +#define __NR_i386_mprotect 125 +#define __NR_i386_sigprocmask 126 +#define __NR_i386_create_module 127 +#define __NR_i386_init_module 128 +#define __NR_i386_delete_module 129 +#define __NR_i386_get_kernel_syms 130 +#define __NR_i386_quotactl 131 +#define __NR_i386_getpgid 132 +#define __NR_i386_fchdir 133 +#define __NR_i386_bdflush 134 +#define __NR_i386_sysfs 135 +#define __NR_i386_personality 136 +#define __NR_i386_afs_syscall 137 +#define __NR_i386_setfsuid 138 +#define __NR_i386_setfsgid 139 +#define __NR_i386__llseek 140 +#define __NR_i386_getdents 141 +#define __NR_i386__newselect 142 +#define __NR_i386_flock 143 +#define __NR_i386_msync 144 +#define __NR_i386_readv 145 +#define __NR_i386_writev 146 +#define __NR_i386_getsid 147 +#define __NR_i386_fdatasync 148 +#define __NR_i386__sysctl 149 +#define __NR_i386_mlock 150 +#define __NR_i386_munlock 151 +#define __NR_i386_mlockall 152 +#define __NR_i386_munlockall 153 +#define __NR_i386_sched_setparam 154 +#define __NR_i386_sched_getparam 155 +#define __NR_i386_sched_setscheduler 156 +#define __NR_i386_sched_getscheduler 157 +#define __NR_i386_sched_yield 158 +#define __NR_i386_sched_get_priority_max 159 +#define __NR_i386_sched_get_priority_min 160 +#define __NR_i386_sched_rr_get_interval 161 +#define __NR_i386_nanosleep 162 +#define __NR_i386_mremap 163 +#define __NR_i386_setresuid 164 +#define __NR_i386_getresuid 165 +#define __NR_i386_vm86 166 +#define __NR_i386_query_module 167 +#define __NR_i386_poll 168 +#define __NR_i386_nfsservctl 169 +#define __NR_i386_setresgid 170 +#define __NR_i386_getresgid 171 +#define __NR_i386_prctl 172 +#define __NR_i386_rt_sigreturn 173 +#define __NR_i386_rt_sigaction 174 +#define __NR_i386_rt_sigprocmask 175 +#define __NR_i386_rt_sigpending 176 +#define __NR_i386_rt_sigtimedwait 177 +#define __NR_i386_rt_sigqueueinfo 178 +#define __NR_i386_rt_sigsuspend 179 +#define __NR_i386_pread64 180 +#define __NR_i386_pwrite64 181 +#define __NR_i386_chown 182 +#define __NR_i386_getcwd 183 +#define __NR_i386_capget 184 +#define __NR_i386_capset 185 +#define __NR_i386_sigaltstack 186 +#define __NR_i386_sendfile 187 +#define __NR_i386_getpmsg 188 +#define __NR_i386_putpmsg 189 +#define __NR_i386_vfork 190 +#define __NR_i386_ugetrlimit 191 +#define __NR_i386_mmap2 192 +#define __NR_i386_truncate64 193 +#define __NR_i386_ftruncate64 194 +#define __NR_i386_stat64 195 +#define __NR_i386_lstat64 196 +#define __NR_i386_fstat64 197 +#define __NR_i386_lchown32 198 +#define __NR_i386_getuid32 199 +#define __NR_i386_getgid32 200 +#define __NR_i386_geteuid32 201 +#define __NR_i386_getegid32 202 +#define __NR_i386_setreuid32 203 +#define __NR_i386_setregid32 204 +#define __NR_i386_getgroups32 205 +#define __NR_i386_setgroups32 206 +#define __NR_i386_fchown32 207 +#define __NR_i386_setresuid32 208 +#define __NR_i386_getresuid32 209 +#define __NR_i386_setresgid32 210 +#define __NR_i386_getresgid32 211 +#define __NR_i386_chown32 212 +#define __NR_i386_setuid32 213 +#define __NR_i386_setgid32 214 +#define __NR_i386_setfsuid32 215 +#define __NR_i386_setfsgid32 216 +#define __NR_i386_pivot_root 217 +#define __NR_i386_mincore 218 +#define __NR_i386_madvise 219 +#define __NR_i386_getdents64 220 +#define __NR_i386_fcntl64 221 +#define __NR_i386_gettid 224 +#define __NR_i386_readahead 225 +#define __NR_i386_setxattr 226 +#define __NR_i386_lsetxattr 227 +#define __NR_i386_fsetxattr 228 +#define __NR_i386_getxattr 229 +#define __NR_i386_lgetxattr 230 +#define __NR_i386_fgetxattr 231 +#define __NR_i386_listxattr 232 +#define __NR_i386_llistxattr 233 +#define __NR_i386_flistxattr 234 +#define __NR_i386_removexattr 235 +#define __NR_i386_lremovexattr 236 +#define __NR_i386_fremovexattr 237 +#define __NR_i386_tkill 238 +#define __NR_i386_sendfile64 239 +#define __NR_i386_futex 240 +#define __NR_i386_sched_setaffinity 241 +#define __NR_i386_sched_getaffinity 242 +#define __NR_i386_set_thread_area 243 +#define __NR_i386_get_thread_area 244 +#define __NR_i386_io_setup 245 +#define __NR_i386_io_destroy 246 +#define __NR_i386_io_getevents 247 +#define __NR_i386_io_submit 248 +#define __NR_i386_io_cancel 249 +#define __NR_i386_fadvise64 250 +#define __NR_i386_set_zone_reclaim 251 /* removed in 2.6.16 */ +#define __NR_i386_exit_group 252 +#define __NR_i386_lookup_dcookie 253 +#define __NR_i386_epoll_create 254 +#define __NR_i386_epoll_ctl 255 +#define __NR_i386_epoll_wait 256 +#define __NR_i386_remap_file_pages 257 +#define __NR_i386_set_tid_address 258 +#define __NR_i386_timer_create 259 +#define __NR_i386_timer_settime32 260 +#define __NR_i386_timer_gettime32 261 +#define __NR_i386_timer_getoverrun 262 +#define __NR_i386_timer_delete 263 +#define __NR_i386_clock_settime32 264 +#define __NR_i386_clock_gettime32 265 +#define __NR_i386_clock_getres_time32 266 +#define __NR_i386_clock_nanosleep_time32 267 +#define __NR_i386_statfs64 268 +#define __NR_i386_fstatfs64 269 +#define __NR_i386_tgkill 270 +#define __NR_i386_utimes 271 +#define __NR_i386_fadvise64_64 272 +#define __NR_i386_vserver 273 +#define __NR_i386_mbind 274 +#define __NR_i386_get_mempolicy 275 +#define __NR_i386_set_mempolicy 276 +#define __NR_i386_mq_open 277 +#define __NR_i386_mq_unlink 278 +#define __NR_i386_mq_timedsend 279 +#define __NR_i386_mq_timedreceive 280 +#define __NR_i386_mq_notify 281 +#define __NR_i386_mq_getsetattr 282 +#define __NR_i386_kexec_load 283 +#define __NR_i386_waitid 284 +#define __NR_i386_sys_setaltroot 285 +#define __NR_i386_add_key 286 +#define __NR_i386_request_key 287 +#define __NR_i386_keyctl 288 +#define __NR_i386_ioprio_set 289 +#define __NR_i386_ioprio_get 290 +#define __NR_i386_inotify_init 291 +#define __NR_i386_inotify_add_watch 292 +#define __NR_i386_inotify_rm_watch 293 +#define __NR_i386_migrate_pages 294 +#define __NR_i386_openat 295 +#define __NR_i386_mkdirat 296 +#define __NR_i386_mknodat 297 +#define __NR_i386_fchownat 298 +#define __NR_i386_futimesat 299 +#define __NR_i386_fstatat64 300 +#define __NR_i386_unlinkat 301 +#define __NR_i386_renameat 302 +#define __NR_i386_linkat 303 +#define __NR_i386_symlinkat 304 +#define __NR_i386_readlinkat 305 +#define __NR_i386_fchmodat 306 +#define __NR_i386_faccessat 307 +#define __NR_i386_pselect6 308 +#define __NR_i386_ppoll 309 +#define __NR_i386_unshare 310 +#define __NR_i386_set_robust_list 311 +#define __NR_i386_get_robust_list 312 +#define __NR_i386_splice 313 +#define __NR_i386_sync_file_range 314 +#define __NR_i386_tee 315 +#define __NR_i386_vmsplice 316 +#define __NR_i386_move_pages 317 +#define __NR_i386_getcpu 318 +#define __NR_i386_epoll_pwait 319 +#define __NR_i386_utimensat 320 +#define __NR_i386_signalfd 321 +#define __NR_i386_timerfd_create 322 +#define __NR_i386_eventfd 323 +#define __NR_i386_fallocate 324 +#define __NR_i386_timerfd_settime32 325 +#define __NR_i386_timerfd_gettime32 326 +#define __NR_i386_signalfd4 327 +#define __NR_i386_eventfd2 328 +#define __NR_i386_epoll_create1 329 +#define __NR_i386_dup3 330 +#define __NR_i386_pipe2 331 +#define __NR_i386_inotify_init1 332 +#define __NR_i386_preadv 333 +#define __NR_i386_pwritev 334 +#define __NR_i386_rt_tgsigqueueinfo 335 +#define __NR_i386_perf_event_open 336 +#define __NR_i386_recvmmsg 337 +#define __NR_i386_fanotify_init 338 +#define __NR_i386_fanotify_mark 339 +#define __NR_i386_prlimit64 340 +#define __NR_i386_name_to_handle_at 341 +#define __NR_i386_open_by_handle_at 342 +#define __NR_i386_clock_adjtime 343 +#define __NR_i386_syncfs 344 +#define __NR_i386_sendmmsg 345 +#define __NR_i386_setns 346 +#define __NR_i386_process_vm_readv 347 +#define __NR_i386_process_vm_writev 348 +#define __NR_i386_kcmp 349 +#define __NR_i386_finit_module 350 +#define __NR_i386_sched_setattr 351 +#define __NR_i386_sched_getattr 352 +#define __NR_i386_renameat2 353 +#define __NR_i386_seccomp 354 +#define __NR_i386_getrandom 355 +#define __NR_i386_memfd_create 356 +#define __NR_i386_bpf 357 +#define __NR_i386_execveat 358 +#define __NR_i386_socket 359 +#define __NR_i386_socketpair 360 +#define __NR_i386_bind 361 +#define __NR_i386_connect 362 +#define __NR_i386_listen 363 +#define __NR_i386_accept4 364 +#define __NR_i386_getsockopt 365 +#define __NR_i386_setsockopt 366 +#define __NR_i386_getsockname 367 +#define __NR_i386_getpeername 368 +#define __NR_i386_sendto 369 +#define __NR_i386_sendmsg 370 +#define __NR_i386_recvfrom 371 +#define __NR_i386_recvmsg 372 +#define __NR_i386_shutdown 373 +#define __NR_i386_userfaultfd 374 +#define __NR_i386_membarrier 375 +#define __NR_i386_mlock2 376 +#define __NR_i386_copy_file_range 377 +#define __NR_i386_preadv2 378 +#define __NR_i386_pwritev2 379 +#define __NR_i386_pkey_mprotect 380 +#define __NR_i386_pkey_alloc 381 +#define __NR_i386_pkey_free 382 +#define __NR_i386_statx 383 +#define __NR_i386_arch_prctl 384 +#define __NR_i386_io_pgetevents 385 +#define __NR_i386_rseq 386 +#define __NR_i386_semget 393 +#define __NR_i386_semctl 394 +#define __NR_i386_shmget 395 +#define __NR_i386_shmctl 396 +#define __NR_i386_shmat 397 +#define __NR_i386_shmdt 398 +#define __NR_i386_msgget 399 +#define __NR_i386_msgsnd 400 +#define __NR_i386_msgrcv 401 +#define __NR_i386_msgctl 402 +#define __NR_i386_clock_gettime64 403 +#define __NR_i386_clock_settime64 404 +#define __NR_i386_clock_adjtime64 405 +#define __NR_i386_clock_getres_time64 406 +#define __NR_i386_clock_nanosleep_time64 407 +#define __NR_i386_timer_gettime64 408 +#define __NR_i386_timer_settime64 409 +#define __NR_i386_timerfd_gettime64 410 +#define __NR_i386_timerfd_settime64 411 +#define __NR_i386_utimensat_time64 412 +#define __NR_i386_pselect6_time64 413 +#define __NR_i386_ppoll_time64 414 +#define __NR_i386_io_pgetevents_time64 416 +#define __NR_i386_recvmmsg_time64 417 +#define __NR_i386_mq_timedsend_time64 418 +#define __NR_i386_mq_timedreceive_time64 419 +#define __NR_i386_semtimedop_time64 420 +#define __NR_i386_rt_sigtimedwait_time64 421 +#define __NR_i386_futex_time64 422 +#define __NR_i386_sched_rr_get_interval_time64 423 +#define __NR_i386_pidfd_send_signal 424 +#define __NR_i386_io_uring_setup 425 +#define __NR_i386_io_uring_enter 426 +#define __NR_i386_io_uring_register 427 +#define __NR_i386_open_tree 428 +#define __NR_i386_move_mount 429 +#define __NR_i386_fsopen 430 +#define __NR_i386_fsconfig 431 +#define __NR_i386_fsmount 432 +#define __NR_i386_fspick 433 +#define __NR_i386_pidfd_open 434 +#define __NR_i386_clone3 435 +#define __NR_i386_close_range 436 +#define __NR_i386_openat2 437 +#define __NR_i386_pidfd_getfd 438 +#define __NR_i386_faccessat2 439 +#define __NR_i386_process_madvise 440 +#define __NR_i386_epoll_pwait2 441 +#define __NR_i386_mount_setattr 442 +#define __NR_i386_landlock_create_ruleset 444 +#define __NR_i386_landlock_add_rule 445 +#define __NR_i386_landlock_restrict_self 446 + +#endif // !__FENNIX_KERNEL_LINUX_SYSCALLS_I386_H__ diff --git a/include/syscalls.hpp b/include/syscalls.hpp index 072b213..ae9642a 100644 --- a/include/syscalls.hpp +++ b/include/syscalls.hpp @@ -23,46 +23,47 @@ typedef struct SyscallsFrame { #if defined(a64) - uint64_t r15; - uint64_t r14; - uint64_t r13; - uint64_t r12; - uint64_t r11; - uint64_t r10; - uint64_t r9; - uint64_t r8; - uint64_t rbp; - uint64_t rdi; - uint64_t rsi; - uint64_t rdx; - uint64_t rcx; - uint64_t rbx; - uint64_t rax; + uint64_t r15; + uint64_t r14; + uint64_t r13; + uint64_t r12; + uint64_t r11; + uint64_t r10; + uint64_t r9; + uint64_t r8; + uint64_t rbp; + uint64_t rdi; + uint64_t rsi; + uint64_t rdx; + uint64_t rcx; + uint64_t rbx; + uint64_t rax; - uint64_t ReturnAddress; - uint64_t CodeSegment; - uint64_t Flags; - uint64_t StackPointer; - uint64_t StackSegment; + uint64_t ReturnAddress; + uint64_t CodeSegment; + uint64_t Flags; + uint64_t StackPointer; + uint64_t StackSegment; #elif defined(a32) - uint32_t ebp; - uint32_t edi; - uint32_t esi; - uint32_t edx; - uint32_t ecx; - uint32_t ebx; - uint32_t eax; + uint32_t ebp; + uint32_t edi; + uint32_t esi; + uint32_t edx; + uint32_t ecx; + uint32_t ebx; + uint32_t eax; - uint32_t ReturnAddress; - uint32_t CodeSegment; - uint32_t Flags; - uint32_t StackPointer; - uint32_t StackSegment; + uint32_t ReturnAddress; + uint32_t CodeSegment; + uint32_t Flags; + uint32_t StackPointer; + uint32_t StackSegment; #elif defined(aa64) - uint32_t ReturnAddress; - uint32_t StackPointer; + uint32_t ReturnAddress; + uint32_t StackPointer; #endif } SyscallsFrame; +#define SysFrm SyscallsFrame uintptr_t HandleNativeSyscalls(SyscallsFrame *Frame); uintptr_t HandleLinuxSyscalls(SyscallsFrame *Frame); diff --git a/include/targp.h b/include/targp.h index c6991c2..375038d 100644 --- a/include/targp.h +++ b/include/targp.h @@ -23,7 +23,7 @@ extern "C" { #endif - void targp_parse(const char *cmd, char **argv, int *argc); + void targp_parse(const char *cmd, char **argv, int *argc); #ifdef __cplusplus } diff --git a/include/task.hpp b/include/task.hpp index c789911..8b5856d 100644 --- a/include/task.hpp +++ b/include/task.hpp @@ -23,13 +23,14 @@ #include #include #include +#include #include -#include #include #include #include #include #include +#include namespace Tasking { @@ -39,9 +40,9 @@ namespace Tasking /** Instruction Pointer */ typedef __UINTPTR_TYPE__ IP; /** Process ID */ - typedef int PID; + typedef pid_t PID; /** Thread ID */ - typedef int TID; + typedef pid_t TID; enum TaskArchitecture { @@ -77,48 +78,54 @@ namespace Tasking _ExecuteModeMax = User }; - enum TaskState : int + enum TaskState : short { UnknownStatus, /** - * Task ready to be scheduled + * Ready + * + * Used when the task is ready + * to be scheduled */ Ready, /** - * Task is the current running task + * Running + * + * Used when the task is running + * on the CPU */ Running, /** - * Task is sleeping - * - * Used when the task is waiting for - * a specific amount of time to pass + * Sleeping + * + * Used when the task is sleeping + * for a given amount of time */ Sleeping, /** - * Task is blocked - * - * Used when the task is waiting for - * another task to finish or for an - * event to occur + * Blocked + * + * Used when the task is blocked + * by another task or until an + * event occurs */ Blocked, /** - * Task is stopped - * + * Stopped + * * Used when the task is stopped - * by the debugger or by the user + * by the user */ Stopped, /** - * Task is waiting - * + * Waiting + * * Used when the task is not ready * to be scheduled by implementation * e.g. Creating a separate page table @@ -127,8 +134,8 @@ namespace Tasking Waiting, /** - * Task is a zombie - * + * Zombie + * * Used when the task is waiting * for the parent to read the exit * code @@ -136,8 +143,17 @@ namespace Tasking Zombie, /** - * Task is terminated - * + * Core Dump + * + * Used when the task is waiting + * for the parent to read the core + * dump + */ + CoreDump, + + /** + * Terminated + * * Used when the task is terminated * and is waiting to be cleaned up * by the scheduler @@ -161,7 +177,7 @@ namespace Tasking _PriorityMax = Critical }; - enum KillErrorCodes : int + enum KillCode : int { KILL_SCHEDULER_DESTRUCTION = -0xFFFF, KILL_CXXABI_EXCEPTION = -0xECE97, @@ -188,6 +204,36 @@ namespace Tasking cwk_path_style PathStyle = CWK_STYLE_UNIX; }; + struct ThreadLocalStorage + { + /** + * Physical base address of the + * TLS segment with the data + */ + uintptr_t pBase; + + /** + * Virtual base where the TLS + * segment should be mapped + */ + uintptr_t vBase; + + /** + * Alignment of the TLS segment + */ + uintptr_t Align; + + /** + * Size of the TLS segment + */ + uintptr_t Size; + + /** + * File size of the TLS segment + */ + uintptr_t fSize; + }; + /** * TCB struct for gs register */ @@ -246,6 +292,12 @@ namespace Tasking const char **envp, const std::vector &auxv); + /** + * This function should be called after + * GS and FS are set up + */ + void SetupThreadLocalStorage(); + public: class Task *GetContext() { return ctx; } @@ -258,8 +310,6 @@ namespace Tasking /* Statuses */ std::atomic_int ExitCode; std::atomic State = TaskState::Waiting; - std::atomic_bool KeepInMemory = false; - std::atomic_size_t KeepTime = 0; int ErrorNumber; /* Memory */ @@ -271,12 +321,11 @@ namespace Tasking CPU::x64::TrapFrame Registers{}; uintptr_t ShadowGSBase, GSBase, FSBase; #elif defined(a32) - CPU::x32::TrapFrame Registers; // TODO + CPU::x32::TrapFrame Registers{}; uintptr_t ShadowGSBase, GSBase, FSBase; #elif defined(aa64) uintptr_t Registers; // TODO #endif - uintptr_t IPHistory[128]; __aligned(16) CPU::x64::FXState FPU; /* Info & Security info */ @@ -288,6 +337,7 @@ namespace Tasking bool IsKernelDebugEnabled = false; } Security{}; TaskInfo Info{}; + ThreadLocalStorage TLS{}; /* Compatibility structures */ struct @@ -296,6 +346,9 @@ namespace Tasking int *clear_child_tid{}; } Linux{}; + int SendSignal(int sig); + void SetState(TaskState state); + void SetExitCode(int code); void Rename(const char *name); void SetPriority(TaskPriority priority); int GetExitCode() { return ExitCode.load(); } @@ -303,7 +356,6 @@ namespace Tasking void SetDebugMode(bool Enable); void SetKernelDebugMode(bool Enable); size_t GetSize(); - void Block() { State.store(TaskState::Blocked); } void Unblock() { State.store(TaskState::Ready); } @@ -328,7 +380,7 @@ namespace Tasking ~TCB(); }; - class PCB + class PCB : public vfs::Node { private: class Task *ctx = nullptr; @@ -355,8 +407,6 @@ namespace Tasking /* Statuses */ std::atomic_int ExitCode; std::atomic State = Waiting; - std::atomic_bool KeepInMemory = false; - std::atomic_size_t KeepTime = 0; /* Info & Security info */ struct @@ -372,30 +422,40 @@ namespace Tasking } Real, Effective; } Security{}; TaskInfo Info{}; + ThreadLocalStorage TLS{}; /* Filesystem */ Node *CurrentWorkingDirectory; - Node *ProcessDirectory; + Node *Executable; FileDescriptorTable *FileDescriptors; + /* stdio */ + Node *stdin; + Node *stdout; + Node *stderr; + /* Memory */ Memory::PageTable *PageTable; Memory::VirtualMemoryArea *vma; Memory::ProgramBreak *ProgramBreak; /* Other */ - InterProcessCommunication::IPC *IPC; + Signal *Signals; SymbolResolver::Symbols *ELFSymbolTable; /* Threads & Children */ - std::vector Threads; - std::vector Children; + std::list Threads; + std::list Children; public: class Task *GetContext() { return ctx; } + int SendSignal(int sig); + void SetState(TaskState state); + void SetExitCode(int code); void Rename(const char *name); void SetWorkingDirectory(Node *node); + void SetExe(const char *path); size_t GetSize(); PCB(class Task *ctx, @@ -403,7 +463,7 @@ namespace Tasking const char *Name, TaskExecutionMode ExecutionMode, void *Image = nullptr, - bool DoNotCreatePageTable = false, + bool UseKernelPageTable = false, uint16_t UserID = -1, uint16_t GroupID = -1); @@ -419,10 +479,10 @@ namespace Tasking PID NextPID = 0; TID NextTID = 0; - std::vector ProcessList; + std::list ProcessList; + PCB *KernelProcess = nullptr; PCB *IdleProcess = nullptr; TCB *IdleThread = nullptr; - TCB *CleanupThread = nullptr; std::atomic_size_t SchedulerTicks = 0; std::atomic_size_t LastTaskTicks = 0; std::atomic_int LastCore = 0; @@ -481,36 +541,24 @@ namespace Tasking */ void WakeUpThreads(); -#if defined(a64) /** * @note This function is NOT thread safe */ - void Schedule(CPU::x64::TrapFrame *Frame); + void CleanupTerminated(); - void OnInterruptReceived(CPU::x64::TrapFrame *Frame); -#elif defined(a32) /** * @note This function is NOT thread safe */ - void Schedule(CPU::x32::TrapFrame *Frame); + void Schedule(CPU::TrapFrame *Frame); - void OnInterruptReceived(CPU::x32::TrapFrame *Frame); -#elif defined(aa64) - /** - * @note This function is NOT thread safe - */ - void Schedule(CPU::aarch64::TrapFrame *Frame); - - void OnInterruptReceived(CPU::aarch64::TrapFrame *Frame); -#endif + void OnInterruptReceived(CPU::TrapFrame *Frame) final; public: - void SetCleanupThread(TCB *Thread) { CleanupThread = Thread; } + PCB *GetKernelProcess() { return KernelProcess; } size_t GetSchedulerTicks() { return SchedulerTicks.load(); } size_t GetLastTaskTicks() { return LastTaskTicks.load(); } int GetLastCore() { return LastCore.load(); } - std::vector GetProcessList() { return ProcessList; } - void CleanupProcessesThread(); + std::list GetProcessList() { return ProcessList; } void Panic() { StopScheduler = true; } bool IsPanic() { return StopScheduler; } @@ -542,18 +590,18 @@ namespace Tasking void SignalShutdown(); - void KillThread(TCB *tcb, enum KillErrorCodes Code) + void KillThread(TCB *tcb, enum KillCode Code) { - tcb->State = TaskState::Terminated; - tcb->ExitCode = (int)Code; + tcb->SetState(TaskState::Terminated); + tcb->SetExitCode(Code); debug("Killing thread %s(%d) with exit code %d", tcb->Name, tcb->ID, Code); } - void KillProcess(PCB *pcb, enum KillErrorCodes Code) + void KillProcess(PCB *pcb, enum KillCode Code) { - pcb->State = TaskState::Terminated; - pcb->ExitCode = (int)Code; + pcb->SetState(TaskState::Terminated); + pcb->SetExitCode(Code); debug("Killing process %s(%d) with exit code %d", pcb->Name, pcb->ID, Code); } @@ -594,7 +642,7 @@ namespace Tasking const char *Name, TaskExecutionMode TrustLevel, void *Image = nullptr, - bool DoNotCreatePageTable = false, + bool UseKernelPageTable = false, uint16_t UserID = UINT16_MAX, uint16_t GroupID = UINT16_MAX); @@ -607,6 +655,7 @@ namespace Tasking TaskCompatibility Compatibility = TaskCompatibility::Native, bool ThreadNotReady = false); + void StartScheduler(); Task(const IP EntryPoint); ~Task(); @@ -615,11 +664,15 @@ namespace Tasking }; } -#define thisProcess TaskManager->GetCurrentProcess() -#define thisThread TaskManager->GetCurrentThread() +/* + If these macros are used, + you have to add: + "#include " too + if necessary. +*/ -#define PEXIT(Code) thisProcess->ExitCode = Code -#define TEXIT(Code) thisThread->ExitCode = Code +#define thisProcess GetCurrentCPU()->CurrentProcess.load() +#define thisThread GetCurrentCPU()->CurrentThread.load() extern "C" void TaskingScheduler_OneShot(int TimeSlice); diff --git a/include/time.hpp b/include/time.hpp index 8e27174..59fea95 100644 --- a/include/time.hpp +++ b/include/time.hpp @@ -20,6 +20,7 @@ #include #include +#include namespace Time { @@ -47,6 +48,38 @@ namespace Time Years }; + /** @deprecated this shouldn't be used */ + inline uint64_t ConvertUnit(const Units Unit) + { + switch (Unit) + { + case Femtoseconds: + return 1; + case Picoseconds: + return 1000; + case Nanoseconds: + return 1000000; + case Microseconds: + return 1000000000; + case Milliseconds: + return 1000000000000; + case Seconds: + return 1000000000000000; + case Minutes: + return 1000000000000000000; + // case Hours: + // return 1000000000000000000000; + // case Days: + // return 1000000000000000000000000; + // case Months: + // return 1000000000000000000000000000; + // case Years: + // return 1000000000000000000000000000000; + default: + assert(!"Invalid time unit"); + } + } + class HighPrecisionEventTimer { private: @@ -67,38 +100,6 @@ namespace Time HPET *hpet = nullptr; uint64_t ClassCreationTime = 0; - inline uint64_t ConvertUnit(Units Unit) - { - switch (Unit) - { - case Femtoseconds: - return 1; - case Picoseconds: - return 1000; - case Nanoseconds: - return 1000000; - case Microseconds: - return 1000000000; - case Milliseconds: - return 1000000000000; - case Seconds: - return 1000000000000000; - case Minutes: - return 1000000000000000000; - // case Hours: - // return 1000000000000000000000; - // case Days: - // return 1000000000000000000000000; - // case Months: - // return 1000000000000000000000000000; - // case Years: - // return 1000000000000000000000000000000; - default: - error("Invalid time unit %d", Unit); - return 1; - } - } - public: bool Sleep(size_t Duration, Units Unit); uint64_t GetCounter(); @@ -115,38 +116,6 @@ namespace Time uint64_t clk = 0; uint64_t ClassCreationTime = 0; - inline uint64_t ConvertUnit(Units Unit) - { - switch (Unit) - { - case Femtoseconds: - return 1; - case Picoseconds: - return 1000; - case Nanoseconds: - return 1000000; - case Microseconds: - return 1000000000; - case Milliseconds: - return 1000000000000; - case Seconds: - return 1000000000000000; - case Minutes: - return 1000000000000000000; - // case Hours: - // return 1000000000000000000000; - // case Days: - // return 1000000000000000000000000; - // case Months: - // return 1000000000000000000000000000; - // case Years: - // return 1000000000000000000000000000000; - default: - error("Invalid time unit %d", Unit); - return 1; - } - } - public: bool Sleep(size_t Duration, Units Unit); uint64_t GetCounter(); @@ -198,5 +167,5 @@ namespace Time ~time(); }; } - + #endif // !__FENNIX_KERNEL_TIME_H__ diff --git a/include/types.h b/include/types.h index 9806556..570f1c2 100644 --- a/include/types.h +++ b/include/types.h @@ -212,6 +212,8 @@ typedef int64_t blkcnt64_t; typedef int64_t time_t; typedef unsigned uid_t; typedef unsigned gid_t; +typedef long clock_t; +typedef int pid_t; #elif defined(a32) typedef int32_t off_t; typedef long long off64_t; @@ -226,6 +228,8 @@ typedef int32_t blkcnt64_t; typedef int32_t time_t; typedef unsigned uid_t; typedef unsigned gid_t; +typedef long clock_t; +typedef int pid_t; #endif #define INT8_MAX __INT8_MAX__ @@ -323,15 +327,15 @@ typedef uint48_t uint_fast48_t; #endif // __INT48_TYPE__ #define b4(x) ((x & 0x0F) << 4 | (x & 0xF0) >> 4) -#define b8(x) ((x)&0xFF) +#define b8(x) ((x) & 0xFF) #define b16(x) __builtin_bswap16(x) #define b32(x) __builtin_bswap32(x) -#define b48(x) (((((x)&0x0000000000ff) << 40) | \ - (((x)&0x00000000ff00) << 24) | \ - (((x)&0x000000ff0000) << 8) | \ - (((x)&0x0000ff000000) >> 8) | \ - (((x)&0x00ff00000000) >> 24) | \ - (((x)&0xff0000000000) >> 40))) +#define b48(x) (((((x) & 0x0000000000ff) << 40) | \ + (((x) & 0x00000000ff00) << 24) | \ + (((x) & 0x000000ff0000) << 8) | \ + (((x) & 0x0000ff000000) >> 8) | \ + (((x) & 0x00ff00000000) >> 24) | \ + (((x) & 0xff0000000000) >> 40))) #define b64(x) __builtin_bswap64(x) /* https://gcc.gnu.org/onlinedocs/gcc-9.5.0/gnat_ugn/Optimization-Levels.html */ @@ -401,6 +405,8 @@ typedef uint48_t uint_fast48_t; #define __synchronize __sync_synchronize() #define __sync __synchronize +#define __unreachable __builtin_unreachable() + #define likely(x) __builtin_expect(!!(x), 1) #define unlikely(x) __builtin_expect(!!(x), 0) @@ -417,4 +423,10 @@ typedef uint48_t uint_fast48_t; : \ : "memory") +#define StackPush(stack, type, value) \ + *((type *)--stack) = value; + +#define StackPop(stack, type) \ + *((type *)stack++) + #endif // !__FENNIX_KERNEL_TYPES_H__ diff --git a/include/uart.hpp b/include/uart.hpp index 4cbef0f..8755ddf 100644 --- a/include/uart.hpp +++ b/include/uart.hpp @@ -22,67 +22,67 @@ namespace UniversalAsynchronousReceiverTransmitter { - /** - * @brief Serial ports. (if available) - */ - enum SerialPorts - { - COMNULL = 0, - COM1 = 0x3F8, - COM2 = 0x2F8, - COM3 = 0x3E8, - COM4 = 0x2E8, - COM5 = 0x5F8, - COM6 = 0x4F8, - COM7 = 0x5E8, - COM8 = 0x4E8 - }; + /** + * @brief Serial ports. (if available) + */ + enum SerialPorts + { + COMNULL = 0, + COM1 = 0x3F8, + COM2 = 0x2F8, + COM3 = 0x3E8, + COM4 = 0x2E8, + COM5 = 0x5F8, + COM6 = 0x4F8, + COM7 = 0x5E8, + COM8 = 0x4E8 + }; - class UART - { - private: - SerialPorts Port; - bool IsAvailable; + class UART + { + private: + SerialPorts Port; + bool IsAvailable; - public: - UART(SerialPorts Port = COMNULL); - ~UART(); - void Write(uint8_t Char); - uint8_t Read(); - }; + public: + UART(SerialPorts Port = COMNULL); + ~UART(); + void Write(uint8_t Char); + uint8_t Read(); + }; - class Events - { - private: - SerialPorts Port; + class Events + { + private: + SerialPorts Port; - protected: - /** - * @brief UART events. - * @param Port if none, all ports are registered for events. - */ - Events(SerialPorts Port = COMNULL); - ~Events(); + protected: + /** + * @brief UART events. + * @param Port if none, all ports are registered for events. + */ + Events(SerialPorts Port = COMNULL); + ~Events(); - public: - /** - * @brief Get the Registered Port object - * @return SerialPorts - */ - SafeFunction NIF SerialPorts GetRegisteredPort() { return this->Port; } + public: + /** + * @brief Get the Registered Port object + * @return SerialPorts + */ + SafeFunction NIF SerialPorts GetRegisteredPort() { return this->Port; } - /** - * @brief Called when a character is sent. - * @param Char the sent character. - */ + /** + * @brief Called when a character is sent. + * @param Char the sent character. + */ - virtual void OnSent(uint8_t Char) { UNUSED(Char); } - /** - * @brief Called when a character is received. - * @param Char the received character. - */ - virtual void OnReceived(uint8_t Char) { UNUSED(Char); } - }; + virtual void OnSent(uint8_t Char) { UNUSED(Char); } + /** + * @brief Called when a character is received. + * @param Char the received character. + */ + virtual void OnReceived(uint8_t Char) { UNUSED(Char); } + }; } diff --git a/include_std/algorithm b/include_std/algorithm index 0e0cb55..4febbdd 100644 --- a/include_std/algorithm +++ b/include_std/algorithm @@ -53,14 +53,54 @@ namespace std } template - InputIt find(InputIt first, InputIt last, const T &value) + constexpr InputIt find(InputIt first, InputIt last, const T &value) { - while (first != last) - { + for (; first != last; ++first) if (*first == value) return first; - ++first; - } + return last; } + + template + constexpr InputIt find_if(InputIt first, InputIt last, UnaryPredicate p) + { + for (; first != last; ++first) + if (p(*first)) + return first; + + return last; + } + + template + constexpr InputIt find_if_not(InputIt first, InputIt last, UnaryPredicate q) + { + for (; first != last; ++first) + if (!q(*first)) + return first; + + return last; + } + + template + ForwardIt remove(ForwardIt first, ForwardIt last, const T &value) + { + first = std::find(first, last, value); + if (first != last) + for (ForwardIt i = first; ++i != last;) + if (!(*i == value)) + *first++ = std::move(*i); + return first; + } + + template + ForwardIt remove_if(ForwardIt first, ForwardIt last, UnaryPredicate p) + { + first = std::find_if(first, last, p); + if (first != last) + for (ForwardIt i = first; ++i != last;) + if (!p(*i)) + *first++ = std::move(*i); + return first; + } } diff --git a/include_std/assert.h b/include_std/assert.h index 51678ae..6270014 100644 --- a/include_std/assert.h +++ b/include_std/assert.h @@ -20,27 +20,24 @@ #include -#define assert(x) \ - do \ - { \ - if (!(x)) \ - { \ - error("Assertion failed! [%s] [%s:%s:%d]", \ - #x, __FILE__, __FUNCTION__, __LINE__); \ - int3; \ - while (true) \ - ; \ - } \ +#define assert(x) \ + do \ + { \ + if (__builtin_expect(!!(!(x)), 0)) \ + { \ + error("Assertion failed! [%s]", #x); \ + int3; \ + __builtin_unreachable(); \ + } \ } while (0) -#define assert_allow_continue(x) \ - do \ - { \ - if (!(x)) \ - { \ - error("Assertion failed! [%s] [%s:%s:%d]", \ - #x, __FILE__, __FUNCTION__, __LINE__); \ - } \ +#define assert_allow_continue(x) \ + do \ + { \ + if (__builtin_expect(!!(!(x)), 0)) \ + { \ + error("Assertion failed! [%s]", #x); \ + } \ } while (0) #if __STDC_VERSION__ >= 201112L && !defined(__cplusplus) diff --git a/include_std/atomic b/include_std/atomic index 54c0b04..9343584 100644 --- a/include_std/atomic +++ b/include_std/atomic @@ -68,12 +68,12 @@ namespace std */ enum class memory_order : int { - relaxed, - consume, - acquire, - release, - acq_rel, - seq_cst + relaxed = __ATOMIC_RELAXED, + consume = __ATOMIC_CONSUME, + acquire = __ATOMIC_ACQUIRE, + release = __ATOMIC_RELEASE, + acq_rel = __ATOMIC_ACQ_REL, + seq_cst = __ATOMIC_SEQ_CST }; /** @@ -172,7 +172,7 @@ namespace std * @param order Memory order constraint to use * @return The value of the atomic variable */ - T load(memory_order order = memory_order::seq_cst) const + inline __always_inline T load(memory_order order = memory_order::seq_cst) const { return builtin_atomic_n(load)(&this->value, static_cast(order)); @@ -181,7 +181,7 @@ namespace std /** * @copydoc load() */ - T load(memory_order order = memory_order::seq_cst) const volatile + inline __always_inline T load(memory_order order = memory_order::seq_cst) const volatile { return builtin_atomic_n(load)(&this->value, static_cast(order)); @@ -196,7 +196,7 @@ namespace std * @param desired The value to store * @param order Memory order constraint to use */ - void store(T desired, memory_order order = memory_order::seq_cst) + inline __always_inline void store(T desired, memory_order order = memory_order::seq_cst) { builtin_atomic_n(store)(&this->value, desired, static_cast(order)); @@ -205,8 +205,8 @@ namespace std /** * @copydoc store() */ - void store(T desired, - memory_order order = memory_order::seq_cst) volatile + inline __always_inline void store(T desired, + memory_order order = memory_order::seq_cst) volatile { builtin_atomic_n(store)(&this->value, desired, static_cast(order)); @@ -219,7 +219,7 @@ namespace std * @param order Memory order constraint to use * @return The value of the atomic variable before the exchange */ - T exchange(T desired, memory_order order = memory_order::seq_cst) + inline __always_inline T exchange(T desired, memory_order order = memory_order::seq_cst) { return builtin_atomic_n(exchange)(&this->value, desired, static_cast(order)); @@ -228,8 +228,8 @@ namespace std /** * @copydoc exchange() */ - T exchange(T desired, - memory_order order = memory_order::seq_cst) volatile + inline __always_inline T exchange(T desired, + memory_order order = memory_order::seq_cst) volatile { return builtin_atomic_n(exchange)(&this->value, desired, static_cast(order)); @@ -244,9 +244,9 @@ namespace std * @param failure Memory order constraint to use if the exchange fails * @return True if the exchange succeeded, false otherwise */ - bool compare_exchange_weak(T &expected, T desired, - memory_order success, - memory_order failure) + inline __always_inline bool compare_exchange_weak(T &expected, T desired, + memory_order success, + memory_order failure) { return builtin_atomic(compare_exchange_weak)(&this->value, &expected, desired, false, success, @@ -256,9 +256,9 @@ namespace std /** * @copydoc compare_exchange_weak() */ - bool compare_exchange_weak(T &expected, T desired, - memory_order success, - memory_order failure) volatile + inline __always_inline bool compare_exchange_weak(T &expected, T desired, + memory_order success, + memory_order failure) volatile { return builtin_atomic(compare_exchange_weak)(&this->value, &expected, desired, false, success, @@ -273,9 +273,9 @@ namespace std * @param order Memory order constraint to use * @return True if the exchange succeeded, false otherwise */ - bool compare_exchange_weak(T &expected, T desired, - memory_order order = - memory_order_seq_cst) + inline __always_inline bool compare_exchange_weak(T &expected, T desired, + memory_order order = + memory_order_seq_cst) { return builtin_atomic(compare_exchange_weak)(&this->value, &expected, desired, false, order, @@ -285,9 +285,9 @@ namespace std /** * @copydoc compare_exchange_weak() */ - bool compare_exchange_weak(T &expected, T desired, - memory_order order = - memory_order_seq_cst) volatile + inline __always_inline bool compare_exchange_weak(T &expected, T desired, + memory_order order = + memory_order_seq_cst) volatile { return builtin_atomic(compare_exchange_weak)(&this->value, &expected, desired, false, order, @@ -303,9 +303,9 @@ namespace std * @param failure Memory order constraint to use if the exchange fails * @return True if the exchange succeeded, false otherwise */ - bool compare_exchange_strong(T &expected, T desired, - memory_order success, - memory_order failure) + inline __always_inline bool compare_exchange_strong(T &expected, T desired, + memory_order success, + memory_order failure) { return builtin_atomic(compare_exchange_strong)(&this->value, &expected, desired, true, success, @@ -315,9 +315,9 @@ namespace std /** * @copydoc compare_exchange_strong() */ - bool compare_exchange_strong(T &expected, T desired, - memory_order success, - memory_order failure) volatile + inline __always_inline bool compare_exchange_strong(T &expected, T desired, + memory_order success, + memory_order failure) volatile { return builtin_atomic(compare_exchange_strong)(&this->value, &expected, desired, true, success, @@ -332,9 +332,9 @@ namespace std * @param order Memory order constraint to use * @return True if the exchange succeeded, false otherwise */ - bool compare_exchange_strong(T &expected, T desired, - memory_order order = - memory_order_seq_cst) + inline __always_inline bool compare_exchange_strong(T &expected, T desired, + memory_order order = + memory_order_seq_cst) { return builtin_atomic(compare_exchange_strong)(&this->value, &expected, desired, true, order, @@ -344,9 +344,9 @@ namespace std /** * @copydoc compare_exchange_strong() */ - bool compare_exchange_strong(T &expected, T desired, - memory_order order = - memory_order_seq_cst) volatile + inline __always_inline bool compare_exchange_strong(T &expected, T desired, + memory_order order = + memory_order_seq_cst) volatile { return builtin_atomic(compare_exchange_strong)(&this->value, &expected, desired, true, order, @@ -360,8 +360,8 @@ namespace std * @param order Memory order constraint to use * @return The value of the atomic variable before the addition */ - T fetch_add(T arg, memory_order order = - memory_order_seq_cst) + inline __always_inline T fetch_add(T arg, memory_order order = + memory_order_seq_cst) { return builtin_atomic(fetch_add)(&this->value, arg, static_cast(order)); @@ -370,8 +370,8 @@ namespace std /** * @copydoc fetch_add() */ - T fetch_add(T arg, memory_order order = - memory_order_seq_cst) volatile + inline __always_inline T fetch_add(T arg, memory_order order = + memory_order_seq_cst) volatile { return builtin_atomic(fetch_add)(&this->value, arg, static_cast(order)); @@ -384,8 +384,8 @@ namespace std * @param order Memory order constraint to use * @return The value of the atomic variable before the subtraction */ - T fetch_sub(T arg, memory_order order = - memory_order_seq_cst) + inline __always_inline T fetch_sub(T arg, memory_order order = + memory_order_seq_cst) { return builtin_atomic(fetch_sub)(&this->value, arg, static_cast(order)); @@ -394,8 +394,8 @@ namespace std /** * @copydoc fetch_sub() */ - T fetch_sub(T arg, memory_order order = - memory_order_seq_cst) volatile + inline __always_inline T fetch_sub(T arg, memory_order order = + memory_order_seq_cst) volatile { return builtin_atomic(fetch_sub)(&this->value, arg, static_cast(order)); @@ -408,8 +408,8 @@ namespace std * @param order Memory order constraint to use * @return The value of the atomic variable before the AND */ - T fetch_and(T arg, memory_order order = - memory_order_seq_cst) + inline __always_inline T fetch_and(T arg, memory_order order = + memory_order_seq_cst) { return builtin_atomic(fetch_and)(&this->value, arg, static_cast(order)); @@ -418,8 +418,8 @@ namespace std /** * @copydoc fetch_and() */ - T fetch_and(T arg, memory_order order = - memory_order_seq_cst) volatile + inline __always_inline T fetch_and(T arg, memory_order order = + memory_order_seq_cst) volatile { return builtin_atomic(fetch_and)(&this->value, arg, static_cast(order)); @@ -432,8 +432,8 @@ namespace std * @param order Memory order constraint to use * @return The value of the atomic variable before the OR */ - T fetch_or(T arg, memory_order order = - memory_order_seq_cst) + inline __always_inline T fetch_or(T arg, memory_order order = + memory_order_seq_cst) { return builtin_atomic(fetch_or)(&this->value, arg, static_cast(order)); @@ -442,8 +442,8 @@ namespace std /** * @copydoc fetch_or() */ - T fetch_or(T arg, memory_order order = - memory_order_seq_cst) volatile + inline __always_inline T fetch_or(T arg, memory_order order = + memory_order_seq_cst) volatile { return builtin_atomic(fetch_or)(&this->value, arg, static_cast(order)); @@ -456,8 +456,8 @@ namespace std * @param order Memory order constraint to use * @return The value of the atomic variable before the XOR */ - T fetch_xor(T arg, memory_order order = - memory_order_seq_cst) + inline __always_inline T fetch_xor(T arg, memory_order order = + memory_order_seq_cst) { return builtin_atomic(fetch_xor)(&this->value, arg, static_cast(order)); @@ -466,8 +466,8 @@ namespace std /** * @copydoc fetch_xor() */ - T fetch_xor(T arg, memory_order order = - memory_order_seq_cst) volatile + inline __always_inline T fetch_xor(T arg, memory_order order = + memory_order_seq_cst) volatile { return builtin_atomic(fetch_xor)(&this->value, arg, static_cast(order)); @@ -480,8 +480,8 @@ namespace std * @param order Memory order constraint to use * @return The value of the atomic variable before the NAND */ - T fetch_nand(T arg, memory_order order = - memory_order_seq_cst) + inline __always_inline T fetch_nand(T arg, memory_order order = + memory_order_seq_cst) { return builtin_atomic(fetch_nand)(&this->value, arg, static_cast(order)); @@ -490,8 +490,8 @@ namespace std /** * @copydoc fetch_nand() */ - T fetch_nand(T arg, memory_order order = - memory_order_seq_cst) volatile + inline __always_inline T fetch_nand(T arg, memory_order order = + memory_order_seq_cst) volatile { return builtin_atomic(fetch_nand)(&this->value, arg, static_cast(order)); diff --git a/include/emmintrin.h b/include_std/cassert similarity index 83% rename from include/emmintrin.h rename to include_std/cassert index 6f3af05..f6d8df8 100644 --- a/include/emmintrin.h +++ b/include_std/cassert @@ -15,9 +15,5 @@ along with Fennix Kernel. If not, see . */ -#ifndef __FENNIX_KERNEL_EMMINTRIN_H__ -#define __FENNIX_KERNEL_EMMINTRIN_H__ - -/* stub header */ - -#endif // !__FENNIX_KERNEL_EMMINTRIN_H__ +#pragma once +#include diff --git a/include_std/errno.h b/include_std/errno.h index 96f642c..6fb98d0 100644 --- a/include_std/errno.h +++ b/include_std/errno.h @@ -405,7 +405,17 @@ /** State not recoverable */ #define ENOTRECOVERABLE 131 -extern int *__errno_location(void) __attribute__((const)); +#include +EXTERNC int *__errno_location(void) __attribute__((const)); #define errno (*__errno_location()) +#ifdef __cplusplus +extern "C" +{ +#endif + const char *strerror(int errnum); +#ifdef __cplusplus +} +#endif + #endif // !_ERRNO_H diff --git a/include_std/functional b/include_std/functional index 95a5298..c88bfbf 100644 --- a/include_std/functional +++ b/include_std/functional @@ -19,12 +19,43 @@ namespace std { - template - struct equal_to - { - bool operator()(const T &lhs, const T &rhs) const - { - return lhs == rhs; - } - }; + template + struct equal_to + { + bool operator()(const T &lhs, const T &rhs) const + { + return lhs == rhs; + } + }; + + template + struct hash + { + size_t operator()(const Key &key) const + { +#if defined(a64) + static_assert(sizeof(uintptr_t) == sizeof(uint64_t)); + const uint64_t FNV_OFFSET_BASIS = 14695981039346656037ull; + const uint64_t FNV_PRIME = 1099511628211ull; +#elif defined(a32) + static_assert(sizeof(uintptr_t) == sizeof(uint32_t)); + const uint32_t FNV_OFFSET_BASIS = 2166136261u; + const uint32_t FNV_PRIME = 16777619u; +#else +#error "Unsupported architecture" +#endif + + const uint8_t *data = reinterpret_cast(&key); + const size_t size = sizeof(Key); + uintptr_t hash = FNV_OFFSET_BASIS; + + for (size_t i = 0; i < size; ++i) + { + hash ^= static_cast(data[i]); + hash *= FNV_PRIME; + } + + return static_cast(hash); + } + }; } diff --git a/include_std/list b/include_std/list index 480e570..7c3ec0f 100644 --- a/include_std/list +++ b/include_std/list @@ -18,6 +18,8 @@ #pragma once #include +#include +#include namespace std { @@ -25,75 +27,77 @@ namespace std class list { private: - struct lNode + NewLock(lock); + + struct node { T value; - lNode *prev; - lNode *next; + node *prev; + node *next; - lNode(const T &v, lNode *p = nullptr, lNode *n = nullptr) + node(const T &v, node *p = nullptr, node *n = nullptr) : value(v), prev(p), next(n) {} }; - lNode *head; - lNode *tail; - size_t size; + node *head = nullptr; + node *tail = nullptr; + std::atomic_size_t lSize = 0; public: - list() : head(nullptr), tail(nullptr), size(0) {} + list() {} ~list() { clear(); } - list(const list &other) : head(nullptr), tail(nullptr), size(0) { *this = other; } + list(const list &other) { *this = other; } void push_back(const T &value) { - lNode *new_node = new lNode(value, tail, nullptr); + SmartLock(this->lock); + + node *nNode = new node(value, tail); if (empty()) - { - head = tail = new_node; - } + head = tail = nNode; else { - tail->next = new_node; - tail = new_node; + tail->next = nNode; + tail = nNode; } - ++size; + ++lSize; } void pop_back() { + SmartLock(this->lock); + if (unlikely(empty())) - { assert(!"list is empty"); - } else if (head == tail) { delete tail; head = tail = nullptr; - --size; + --lSize; } else { - lNode *old_tail = tail; + node *oldTail = tail; tail = tail->prev; tail->next = nullptr; - delete old_tail; - --size; + delete oldTail; + --lSize; } } void push_front(const T &value) { - lNode *new_node = new lNode(value, nullptr, head); + SmartLock(this->lock); + + node *nNode = new node(value, nullptr, head); if (empty()) - { - head = tail = new_node; - } + head = tail = nNode; else { - head->prev = new_node; - head = new_node; + head->prev = nNode; + head = nNode; } - ++size; + ++lSize; } void pop_front() @@ -105,21 +109,84 @@ namespace std if (head == tail) { + SmartLock(this->lock); delete head; head = tail = nullptr; - --size; + --lSize; } else { - lNode *old_head = head; + SmartLock(this->lock); + node *old_head = head; head = head->next; head->prev = nullptr; delete old_head; - --size; + --lSize; } } - bool empty() const { return size == 0; } + template + void emplace_back(Args &&...args) + { + assert(sizeof...(args) > 0); + + SmartLock(this->lock); + + node *nNode = new node(T(std::forward(args)...), tail); + if (this->empty()) + head = tail = nNode; + else + { + tail->next = nNode; + tail = nNode; + } + ++lSize; + } + + template + void emplace_front(Args &&...args) + { + assert(sizeof...(args) > 0); + + SmartLock(this->lock); + + node *nNode = new node(T(std::forward(args)...), nullptr, head); + if (this->empty()) + head = tail = nNode; + else + { + head->prev = nNode; + head = nNode; + } + ++lSize; + } + + T &front() + { + SmartLock(this->lock); + return head->value; + } + + const T &front() const + { + SmartLock(this->lock); + return head->value; + } + + T &back() + { + SmartLock(this->lock); + return tail->value; + } + + const T &back() const + { + SmartLock(this->lock); + return tail->value; + } + + bool empty() const { return lSize.load() == 0; } + size_t size() const { return lSize; } void clear() { @@ -127,39 +194,179 @@ namespace std pop_back(); } - list &operator=(const list &other) + void merge(list &other) { - if (this != &other) + if (this == &other) + return; + + while (other.empty() == false) { - clear(); - for (const T &value : other) + T &fr = other.front(); + push_back(fr); + other.pop_front(); + } + } + + void remove(const T &value) + { + SmartLock(this->lock); + node *p = head; + while (p != nullptr) + { + if (p->value == value) { - push_back(value); + if (p->prev) + p->prev->next = p->next; + if (p->next) + p->next->prev = p->prev; + if (p == head) + head = p->next; + if (p == tail) + tail = p->prev; + delete p; + --lSize; + return; + } + p = p->next; + } + } + + template + void remove_if(UnaryPredicate p) + { + SmartLock(this->lock); + node *n = head; + while (n != nullptr) + { + if (p(n->value)) + { + if (n->prev) + n->prev->next = n->next; + if (n->next) + n->next->prev = n->prev; + if (n == head) + head = n->next; + if (n == tail) + tail = n->prev; + delete n; + --lSize; + return; + } + n = n->next; + } + } + + void reverse() + { + if (empty()) + return; + + SmartLock(this->lock); + node *p = head; + while (p != nullptr) + { + node *tmp = p->next; + p->next = p->prev; + p->prev = tmp; + p = tmp; + } + node *tmp = head; + head = tail; + tail = tmp; + } + + void sort() + { + if (empty()) + return; + + SmartLock(this->lock); + bool swapped = true; + while (swapped) + { + swapped = false; + node *p = head; + while (p->next != nullptr) + { + if (p->value > p->next->value) + { + T tmp = p->value; + p->value = p->next->value; + p->next->value = tmp; + swapped = true; + } + p = p->next; } } + } + + template + void sort(Compare comp) + { + if (empty()) + return; + + SmartLock(this->lock); + bool swapped = true; + while (swapped) + { + swapped = false; + node *p = head; + while (p->next != nullptr) + { + if (comp(p->value, p->next->value)) + { + T tmp = p->value; + p->value = p->next->value; + p->next->value = tmp; + swapped = true; + } + p = p->next; + } + } + } + + /* Non-STL function */ + T &operator[](size_t Index) + { + SmartLock(this->lock); + node *p = head; + for (size_t i = 0; i < Index; ++i) + p = p->next; + return p->value; + } + + list &operator=(const list &other) + { + if (this == &other) + return *this; + + for (const T &value : other) + push_back(value); + return *this; } class iterator { private: - lNode *node; + node *_node; friend class list; public: - iterator(lNode *p = nullptr) : node(p) {} - T &operator*() const { return node->value; } - T *operator->() const { return &node->value; } + iterator(node *p = nullptr) : _node(p) {} + T &operator*() const { return _node->value; } + T *operator->() const { return &_node->value; } iterator &operator++() { - node = node->next; + _node = _node->next; return *this; } iterator &operator--() { - node = node->prev; + _node = _node->prev; return *this; } @@ -177,12 +384,14 @@ namespace std return tmp; } - bool operator==(const iterator &rhs) const { return node == rhs.node; } - bool operator!=(const iterator &rhs) const { return node != rhs.node; } + bool operator==(const iterator &rhs) const { return _node == rhs._node; } + bool operator!=(const iterator &rhs) const { return _node != rhs._node; } }; iterator begin() { return iterator(head); } iterator end() { return iterator(nullptr); } + const iterator begin() const { return iterator(head); } + const iterator end() const { return iterator(nullptr); } iterator insert(iterator pos, const T &value) { @@ -198,24 +407,46 @@ namespace std } else { - lNode *p = pos.node; - lNode *new_node = new lNode(value, p->prev, p); - p->prev->next = new_node; - p->prev = new_node; - ++size; - return iterator(new_node); + SmartLock(this->lock); + node *p = pos.node; + node *nNode = new node(value, p->prev, p); + p->prev->next = nNode; + p->prev = nNode; + ++lSize; + return iterator(nNode); } } iterator erase(iterator pos) { - lNode *p = pos.node; - iterator next(p->next); - p->prev->next = p->next; - p->next->prev = p->prev; - delete p; - --size; - return next; + if (pos == end()) + return end(); + else if (pos == begin()) + { + pop_front(); + return begin(); + } + else + { + SmartLock(this->lock); + node *p = pos._node; + if (p->prev) + p->prev->next = p->next; + + if (p->next) + p->next->prev = p->prev; + + if (head == p) + head = p->next; + + if (tail == p) + tail = p->prev; + + iterator ret(p->next); + delete p; + --lSize; + return ret; + } } }; } diff --git a/include_std/sched.h b/include_std/sched.h index 4f82fcd..07551d8 100644 --- a/include_std/sched.h +++ b/include_std/sched.h @@ -15,7 +15,4 @@ along with Fennix Kernel. If not, see . */ -#ifndef _SCHED_H -#define _SCHED_H - -#endif // !_SCHED_H +#pragma once diff --git a/include_std/std/functional.hpp b/include_std/std/functional.hpp deleted file mode 100644 index bd8cfd1..0000000 --- a/include_std/std/functional.hpp +++ /dev/null @@ -1,50 +0,0 @@ -/* - This file is part of Fennix Kernel. - - Fennix Kernel is free software: you can redistribute it and/or - modify it under the terms of the GNU General Public License as - published by the Free Software Foundation, either version 3 of - the License, or (at your option) any later version. - - Fennix Kernel is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Fennix Kernel. If not, see . -*/ - -#ifndef __FENNIX_KERNEL_STD_FUNCTIONAL_H__ -#define __FENNIX_KERNEL_STD_FUNCTIONAL_H__ - -#include -#include - -namespace std -{ - template - struct hash - { - size_t operator()(const Key &key) const - { - static_assert(sizeof(size_t) == sizeof(uint64_t)); // size_t and uint64_t must have the same size - const uint64_t fnv_offset_basis = 14695981039346656037ull; - const uint64_t fnv_prime = 1099511628211ull; - - const uint8_t *data = reinterpret_cast(&key); - const size_t size = sizeof(Key); - uint64_t ret = fnv_offset_basis; - - for (size_t i = 0; i < size; ++i) - { - ret ^= static_cast(data[i]); - ret *= fnv_prime; - } - - return static_cast(ret); - } - }; -} - -#endif // !__FENNIX_KERNEL_STD_FUNCTIONAL_H__ diff --git a/include_std/std/smart_ptr.hpp b/include_std/std/smart_ptr.hpp index 996fd59..529b421 100644 --- a/include_std/std/smart_ptr.hpp +++ b/include_std/std/smart_ptr.hpp @@ -250,15 +250,6 @@ namespace std } }; - template - using remove_reference_t = typename remove_reference::type; - - template - T &&forward(remove_reference_t &t) { return static_cast(t); }; - - template - T &&forward(remove_reference_t &&t) { return static_cast(t); }; - template shared_ptr make_shared(Args &&...args) { diff --git a/include_std/std/unordered_map.hpp b/include_std/std/unordered_map.hpp deleted file mode 100644 index 1532b16..0000000 --- a/include_std/std/unordered_map.hpp +++ /dev/null @@ -1,131 +0,0 @@ -/* - This file is part of Fennix Kernel. - - Fennix Kernel is free software: you can redistribute it and/or - modify it under the terms of the GNU General Public License as - published by the Free Software Foundation, either version 3 of - the License, or (at your option) any later version. - - Fennix Kernel is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Fennix Kernel. If not, see . -*/ - -#ifndef __FENNIX_KERNEL_STD_UNORDERED_MAP_H__ -#define __FENNIX_KERNEL_STD_UNORDERED_MAP_H__ - -#include -#include -#include -#include -#include - -namespace std -{ - template - class unordered_map - { - public: - typedef std::pair key_value_pair; - typedef std::list bucket; - typedef typename std::vector::iterator iterator; - typedef typename std::vector::const_iterator const_iterator; - - private: - static const size_t DEFAULT_NUM_BUCKETS = 10; - std::vector bkts; - - size_t hash(const key_type &key) const - { - std::hash hash_function; - return hash_function(key) % this->bkts.size(); - } - - public: - unordered_map() : bkts(DEFAULT_NUM_BUCKETS) {} - unordered_map(size_t num_buckets) : bkts(num_buckets) {} - - void insert(const key_value_pair &pair) - { - size_t bucket_index = hash(pair.first); - bucket &bkt = this->bkts[bucket_index]; - for (auto it = bkt.begin(); it != bkt.end(); ++it) - { - if (it->first == pair.first) - { - it->second = pair.second; - return; - } - } - bkt.push_back(pair); - } - - bool contains(const key_type &key) const - { - size_t bucket_index = hash(key); - const bucket &bkt = this->bkts[bucket_index]; - for (auto it = bkt.begin(); it != bkt.end(); ++it) - { - if (it->first == key) - { - return true; - } - } - return false; - } - - iterator find(const key_type &k) - { - size_t bucket_index = hash(k); - bucket &bkt = this->bkts[bucket_index]; - for (auto it = bkt.begin(); it != bkt.end(); ++it) - { - if (it->first == k) - return it; - } - return bkt.end(); - } - - const_iterator find(const key_type &k) const - { - size_t bucket_index = hash(k); - const bucket &bkt = this->bkts[bucket_index]; - for (auto it = bkt.begin(); it != bkt.end(); ++it) - { - if (it->first == k) - return it; - } - return bkt.end(); - } - - iterator end() { return this->bkts.end(); } - - size_t size() const - { - size_t count = 0; - foreach (const auto &bkt in this->bkts) - count += bkt.size(); - - return count; - } - - value_type &operator[](const key_type &key) - { - size_t bucket_index = hash(key); - bucket &bkt = this->bkts[bucket_index]; - for (auto it = bkt.begin(); it != bkt.end(); ++it) - { - if (it->first == key) - return it->second; - } - bkt.emplace_back(key, value_type()); - return bkt.back().second; - } - }; -} - -#endif // !__FENNIX_KERNEL_STD_UNORDERED_MAP_H__ diff --git a/include_std/stdatomic.h b/include_std/stdatomic.h new file mode 100644 index 0000000..72bfae1 --- /dev/null +++ b/include_std/stdatomic.h @@ -0,0 +1,88 @@ +/* + 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 . +*/ + +#pragma once + +typedef enum +{ + memory_order_relaxed = __ATOMIC_RELAXED, + memory_order_consume = __ATOMIC_CONSUME, + memory_order_acquire = __ATOMIC_ACQUIRE, + memory_order_release = __ATOMIC_RELEASE, + memory_order_acq_rel = __ATOMIC_ACQ_REL, + memory_order_seq_cst = __ATOMIC_SEQ_CST +} memory_order; + +#define atomic_store_explicit(object, desired, order) \ + __atomic_store_n(object, desired, order) + +#define atomic_store(object, desired) \ + __atomic_store_n(object, desired, __ATOMIC_SEQ_CST) + +#define atomic_load_explicit(object, order) \ + __atomic_load_n(object, order) + +#define atomic_load(object) \ + __atomic_load_n(object, __ATOMIC_SEQ_CST) + +#define atomic_exchange_explicit(object, desired, order) \ + __atomic_exchange_n(object, desired, order) + +#define atomic_exchange(object, desired) \ + __atomic_exchange_n(object, desired, __ATOMIC_SEQ_CST) + +#define atomic_compare_exchange_strong_explicit(object, expected, desired, success, failure) \ + __atomic_compare_exchange_n(object, expected, desired, 0, success, failure) + +#define atomic_compare_exchange_strong(object, expected, desired) \ + __atomic_compare_exchange_n(object, expected, desired, 0, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST) + +#define atomic_compare_exchange_weak_explicit(object, expected, desired, success, failure) \ + __atomic_compare_exchange_n(object, expected, desired, 1, success, failure) + +#define atomic_compare_exchange_weak(object, expected, desired) \ + __atomic_compare_exchange_n(object, expected, desired, 1, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST) + +#define atomic_fetch_add(object, operand) \ + __atomic_fetch_add(object, operand, __ATOMIC_SEQ_CST) + +#define atomic_fetch_add_explicit(object, operand, order) \ + __atomic_fetch_add(object, operand, order) + +#define atomic_fetch_sub(object, operand) \ + __atomic_fetch_sub(object, operand, __ATOMIC_SEQ_CST) + +#define atomic_fetch_sub_explicit(object, operand, order) \ + __atomic_fetch_sub(object, operand, order) + +#define atomic_fetch_or(object, operand) \ + __atomic_fetch_or(object, operand, __ATOMIC_SEQ_CST) + +#define atomic_fetch_or_explicit(object, operand, order) \ + __atomic_fetch_or(object, operand, order) + +#define atomic_fetch_xor(object, operand) \ + __atomic_fetch_xor(object, operand, __ATOMIC_SEQ_CST) + +#define atomic_fetch_xor_explicit(object, operand, order) \ + __atomic_fetch_xor(object, operand, order) + +#define atomic_fetch_and(object, operand) \ + __atomic_fetch_and(object, operand, __ATOMIC_SEQ_CST) + +#define atomic_fetch_and_explicit(object, operand, order) \ + __atomic_fetch_and(object, operand, order) diff --git a/include_std/string b/include_std/string index a1ba00d..65a80ab 100644 --- a/include_std/string +++ b/include_std/string @@ -113,14 +113,14 @@ namespace std delete[] this->Data, this->Data = nullptr; } - size_t length() const + size_t length() { v_strdbg("%#lx: String length: %d", this, this->Length); return this->Length; } - size_t capacity() const + size_t capacity() { v_strdbg("%#lx: String capacity: %d", this, this->Capacity); @@ -174,14 +174,14 @@ namespace std this, this->Data, this->Data, this->Length, this->Capacity); } - bool empty() const + bool empty() { strdbg("%#lx: String empty: %d", this, this->Length == 0); return this->Length == 0; } - size_t size() const + size_t size() { strdbg("%#lx: String size: %d", this, this->Length); @@ -530,7 +530,7 @@ namespace std return *this; } - /* warning: implicitly-declared ‘constexpr String::String(const String&)’ is deprecated [-Wdeprecated-copy] */ + /* warning: implicitly-declared 'constexpr String::String(const String&)' is deprecated [-Wdeprecated-copy] */ string &operator=(const string &Other) = default; // string &operator=(const string &Other) diff --git a/include_std/string.h b/include_std/string.h index 0330644..0a2b63d 100644 --- a/include_std/string.h +++ b/include_std/string.h @@ -18,4 +18,6 @@ #ifndef _STRING_H #define _STRING_H +#include + #endif // !_STRING_H diff --git a/modules/Realtek/rtl8139.hpp b/include_std/sys/mman.h similarity index 66% rename from modules/Realtek/rtl8139.hpp rename to include_std/sys/mman.h index cf801e6..0a29ab5 100644 --- a/modules/Realtek/rtl8139.hpp +++ b/include_std/sys/mman.h @@ -15,24 +15,31 @@ along with Fennix Kernel. If not, see . */ -#ifndef __FENNIX_KERNEL_RTL8139_H__ -#define __FENNIX_KERNEL_RTL8139_H__ - +#pragma once #include -#include "../../mapi.hpp" -namespace RTL8139 -{ - struct BARData - { - uint8_t Type; - uint16_t IOBase; - uint64_t MemoryBase; - }; +/* stubs */ - int DriverEntry(void *); - int CallbackHandler(KernelCallback *); - int InterruptCallback(CPURegisters *); -} +#ifndef MAP_PRIVATE +#define MAP_PRIVATE 0x0 +#endif -#endif // !__FENNIX_KERNEL_RTL8139_H__ +#ifndef MAP_ANONYMOUS +#define MAP_ANONYMOUS 0x0 +#endif + +#ifndef PROT_READ +#define PROT_READ 0x0 +#endif + +#ifndef PROT_WRITE +#define PROT_WRITE 0x0 +#endif + +#ifndef MAP_FAILED +#define MAP_FAILED 0x0 +#endif + +#ifndef POSIX_MADV_DONTNEED +#define POSIX_MADV_DONTNEED 0x0 +#endif diff --git a/include_std/sys/time.h b/include_std/time.h similarity index 81% rename from include_std/sys/time.h rename to include_std/time.h index 9da4e6f..ed967a8 100644 --- a/include_std/sys/time.h +++ b/include_std/time.h @@ -15,7 +15,15 @@ along with Fennix Kernel. If not, see . */ -#ifndef _SYS_TIME_H -#define _SYS_TIME_H +#ifndef _TIME_H +#define _TIME_H -#endif // !_SYS_TIME_H +#include + +struct timespec +{ + time_t tv_sec; /* seconds */ + long tv_nsec; /* nanoseconds */ +}; + +#endif // !_TIME_H diff --git a/include_std/unistd.h b/include_std/unistd.h index 0c04855..8161ef2 100644 --- a/include_std/unistd.h +++ b/include_std/unistd.h @@ -18,4 +18,9 @@ #ifndef _UNISTD_H #define _UNISTD_H +#include + +#define _SC_PAGESIZE 30 +#define _SC_PAGE_SIZE _SC_PAGESIZE + #endif // !_UNISTD_H diff --git a/include_std/unordered_map b/include_std/unordered_map new file mode 100644 index 0000000..10fc46c --- /dev/null +++ b/include_std/unordered_map @@ -0,0 +1,282 @@ +/* + 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 . +*/ + +#pragma once + +#include +#include +#include +#include + +#define DEBUG_UMAP_MESSAGES 1 + +#ifdef DEBUG_UMAP_MESSAGES +#define umDebug(m, ...) debug("%#lx: " m, this, ##__VA_ARGS__) +#else +#define umDebug(m, ...) +#endif + +namespace std +{ + template + class unordered_map + { + public: + typedef std::pair pair_t; + typedef std::list bucket_t; + + private: + NewLock(lock); + std::vector Buckets; + + size_t hash(const Key &key) const + { + size_t ret = std::hash()(key) % this->Buckets.size(); + // debug("Hashed %#lx to %d", key, ret); + return ret; + } + + public: + unordered_map() + : Buckets(16) + { + umDebug("Created unordered_map with 16 buckets (default)"); + } + + unordered_map(size_t num) + : Buckets(num) + { + umDebug("Created unordered_map with %d buckets", num); + } + + ~unordered_map() + { + umDebug("Destroyed unordered_map"); + } + + void insert(const pair_t &p) + { + SmartLock(this->lock); + size_t bucketIndex = hash(p.first) % Buckets.size(); + auto &bucket = Buckets[bucketIndex]; + + for (auto &element : bucket) + { + if (element.first == p.first) + { + element.second = p.second; + return; + } + } + + bucket.push_back(p); + } + + void erase(const Key &key) + { + SmartLock(this->lock); + size_t bucketIndex = hash(key) % Buckets.size(); + auto &bucket = Buckets[bucketIndex]; + + bucket.remove_if([key](const pair_t &element) + { return element.first == key; }); + } + + void clear() + { + SmartLock(this->lock); + for (auto &bucket : Buckets) + { + bucket.clear(); + } + } + + bool contains(const Key &key) + { + SmartLock(this->lock); + size_t bucketIndex = hash(key) % Buckets.size(); + const auto &bucket = Buckets[bucketIndex]; + + for (const auto &element : bucket) + { + if (element.first == key) + return true; + } + + return false; + } + + size_t size() + { + SmartLock(this->lock); + size_t count = 0; + for (const auto &bucket : Buckets) + { + count += bucket.size(); + } + return count; + } + + bool empty() { return size() == 0; } + + T &operator[](const Key &key) + { + SmartLock(this->lock); + size_t bucketIndex = hash(key) % Buckets.size(); + auto &bucket = Buckets[bucketIndex]; + + for (auto &element : bucket) + { + if (element.first == key) + return element.second; + } + + bucket.emplace_back(key, T{}); + return bucket.back().second; + } + + class iterator + { + private: + using BucketIterator = typename std::list::iterator; + size_t bucketIndex; + BucketIterator bucketIterator; + std::vector> *buckets; + + public: + size_t GetBucketIndex() const { return bucketIndex; } + BucketIterator &GetBucketIterator() const { return bucketIterator; } + + iterator(size_t index, + BucketIterator it, + std::vector> *buckets) + : bucketIndex(index), + bucketIterator(it), + buckets(buckets) {} + + iterator &operator++() + { + ++bucketIterator; + + while (bucketIndex < buckets->size() && + bucketIterator == (*buckets)[bucketIndex].end()) + { + ++bucketIndex; + if (bucketIndex < buckets->size()) + { + bucketIterator = (*buckets)[bucketIndex].begin(); + } + } + + return *this; + } + + bool operator!=(const iterator &other) const + { + return bucketIndex != other.bucketIndex || + bucketIterator != other.bucketIterator; + } + + pair_t &operator*() + { + return *bucketIterator; + } + + pair_t *operator->() + { + return &(*bucketIterator); + } + + operator bool() const + { + return bucketIndex < buckets->size(); + } + }; + + iterator find(const Key &key) + { + SmartLock(this->lock); + size_t bucketIndex = hash(key) % Buckets.size(); + auto &bucket = Buckets[bucketIndex]; + + auto it = std::find_if(bucket.begin(), bucket.end(), + [key](const pair_t &element) + { return element.first == key; }); + + if (it != bucket.end()) + { + return iterator(bucketIndex, + it, + &Buckets); + } + + return end(); + } + + iterator begin() + { + SmartLock(this->lock); + for (size_t i = 0; i < Buckets.size(); ++i) + { + if (!Buckets[i].empty()) + { + return iterator(i, + Buckets[i].begin(), + &Buckets); + } + } + + return end(); + } + + iterator end() + { + return iterator(Buckets.size(), + Buckets.back().end(), + &Buckets); + } + + iterator insert(iterator pos, const pair_t &p) + { + SmartLock(this->lock); + size_t bucketIndex = hash(p.first) % Buckets.size(); + auto &bucket = Buckets[bucketIndex]; + + auto itr = std::find_if(bucket.begin(), bucket.end(), + [p](const pair_t &element) + { return element.first == p.first; }); + + if (itr != bucket.end()) + return end(); + + return iterator(bucketIndex, + bucket.insert(pos.bucketIterator, p), + &Buckets); + } + + iterator erase(iterator pos) + { + SmartLock(this->lock); + size_t bucketIndex = pos.GetBucketIndex(); + auto &bucket = Buckets[bucketIndex]; + + return iterator(bucketIndex, + bucket.erase(pos.GetBucketIterator()), + &Buckets); + } + }; +} diff --git a/include_std/utility b/include_std/utility index f2b21e4..cad654c 100644 --- a/include_std/utility +++ b/include_std/utility @@ -26,4 +26,29 @@ namespace std { return static_cast::type &&>(arg); } + + template + struct pair + { + typedef T1 first_type; + typedef T2 second_type; + + T1 first; + T2 second; + + pair() : first(T1()), second(T2()) {} + pair(const T1 &x, const T2 &y) : first(x), second(y) {} + }; + + template + pair make_pair(T1 x, T2 y) + { + return pair(x, y); + } + + template + T &&forward(typename std::remove_reference::type &arg) + { + return static_cast(arg); + } } diff --git a/modules/mod.hpp b/include_std/utsname.h similarity index 68% rename from modules/mod.hpp rename to include_std/utsname.h index 031949c..1633b69 100644 --- a/modules/mod.hpp +++ b/include_std/utsname.h @@ -15,21 +15,20 @@ along with Fennix Kernel. If not, see . */ -#ifndef __FENNIX_KERNEL_MOD_H__ -#define __FENNIX_KERNEL_MOD_H__ +#ifndef __FENNIX_KERNEL_UTSNAME_H__ +#define __FENNIX_KERNEL_UTSNAME_H__ #include -bool StartAHCI(); -bool StartVMwareMouse(); -bool StartPS2Mouse(); -bool StartPS2Keyboard(); -bool StartATA(); -bool StartAC97(); -bool StartRTL8139(); -bool StartPCNET(); -bool StartGigabit(); +#define _UTSNAME_LENGTH 65 -void StartBuiltInModules(); +struct utsname +{ + char sysname[_UTSNAME_LENGTH]; + char nodename[_UTSNAME_LENGTH]; + char release[_UTSNAME_LENGTH]; + char version[_UTSNAME_LENGTH]; + char machine[_UTSNAME_LENGTH]; +}; -#endif // !__FENNIX_KERNEL_MOD_H__ +#endif // !__FENNIX_KERNEL_UTSNAME_H__ diff --git a/include_std/vector b/include_std/vector index 105c098..eadc8e1 100644 --- a/include_std/vector +++ b/include_std/vector @@ -23,13 +23,14 @@ #include #include #include +#include #include #include // #define DEBUG_VECTOR_MESSAGES 1 #ifdef DEBUG_VECTOR_MESSAGES -#define vDebug(m, ...) debug(m, ##__VA_ARGS__) +#define vDebug(m, ...) debug("%#lx: " m, this, ##__VA_ARGS__) #else #define vDebug(m, ...) #endif @@ -40,22 +41,23 @@ namespace std class vector { private: - size_t VectorSize = 0; - size_t VectorCapacity = 0; + NewLock(lock); + std::atomic_size_t VectorSize = 0; + std::atomic_size_t VectorCapacity = 0; T *VectorBuffer = nullptr; public: typedef T *iterator; typedef const T *const_iterator; - vector() { vDebug("%#lx: ( empty init )", this); } + vector() { vDebug("( empty init )"); } vector(size_t Size) : VectorSize(Size), VectorCapacity(Size), VectorBuffer(new T[Size]) { - vDebug("%#lx: ( init w/size: %lld )", this, Size); + vDebug("( init w/size: %lld )", Size); } vector(size_t Size, const T &Initial) @@ -63,34 +65,40 @@ namespace std VectorCapacity(Size), VectorBuffer(new T[Size]) { - vDebug("%#lx: ( init w/size: %lld, initial vector: %llx )", this, + vDebug("( init w/size: %lld, initial vector: %llx )", Size, Initial); assert(Size > 0); + + SmartLock(this->lock); for (size_t i = 0; i < Size; i++) VectorBuffer[i] = Initial; } vector(const vector &v) - : VectorSize(v.VectorSize), - VectorCapacity(v.VectorCapacity), + : VectorSize(v.VectorSize.load()), + VectorCapacity(v.VectorCapacity.load()), VectorBuffer(nullptr) { - vDebug("%#lx: ( vector copy: %#lx )", this, &v); + vDebug("( vector copy: %#lx )", &v); - if (!v.VectorBuffer || VectorSize <= 0) + if (!v.VectorBuffer || VectorSize.load() <= 0) return; - VectorBuffer = new T[VectorSize]; - std::copy(v.VectorBuffer, v.VectorBuffer + VectorSize, VectorBuffer); + SmartLock(this->lock); + VectorBuffer = new T[VectorSize.load()]; + std::copy(v.VectorBuffer, v.VectorBuffer + VectorSize.load(), VectorBuffer); } ~vector() { - vDebug("%#lx: ( deinit )", this); + vDebug("( deinit )"); + + VectorSize.store(0); + VectorCapacity.store(0); + + SmartLock(this->lock); - VectorSize = 0; - VectorCapacity = 0; if (VectorBuffer != nullptr) { delete[] VectorBuffer; @@ -100,8 +108,8 @@ namespace std void erase(iterator Position) { - vDebug("%#lx: Erasing element at position %lld (v. size: %lld)", this, - Position - this->VectorBuffer, this->VectorSize); + vDebug("Erasing element at position %lld (v. size: %lld)", + Position - this->VectorBuffer, this->VectorSize.load()); if (Position == this->end()) { @@ -112,24 +120,25 @@ namespace std assert(Position <= this->end()); assert(Position >= this->VectorBuffer); - assert(Position < this->VectorBuffer + this->VectorSize); + assert(Position < this->VectorBuffer + this->VectorSize.load()); + SmartLock(this->lock); size_t index = Position - this->VectorBuffer; if (std::is_trivially_copyable::value) { this->VectorBuffer[index] = T(); - vDebug("%#lx: %#lx is trivially copyable", this, + vDebug("%#lx is trivially copyable", &this->VectorBuffer[index]); } else { this->VectorBuffer[index].~T(); - vDebug("%#lx: %#lx is not trivially copyable", this, + vDebug("%#lx is not trivially copyable", &this->VectorBuffer[index]); } - for (size_t i = index; i < this->VectorSize - 1; ++i) + for (size_t i = index; i < this->VectorSize.load() - 1; ++i) { this->VectorBuffer[i] = std::move(this->VectorBuffer[i + 1]); } @@ -138,7 +147,9 @@ namespace std T &next(size_t Position) { - if (Position + 1 < this->VectorSize) + SmartLock(this->lock); + + if (Position + 1 < this->VectorSize.load()) return this->VectorBuffer[Position + 1]; warn("%#lx: next( %lld ) is null (requested by %#lx)", this, @@ -149,6 +160,8 @@ namespace std T &prev(size_t Position) { + SmartLock(this->lock); + if (Position > 0) return this->VectorBuffer[Position - 1]; @@ -160,11 +173,13 @@ namespace std T &next(const T &Value) { - for (size_t i = 0; i < this->VectorSize; i++) + SmartLock(this->lock); + + for (size_t i = 0; i < this->VectorSize.load(); i++) { if (std::equal_to()(this->VectorBuffer[i], Value)) { - if (i + 1 < this->VectorSize) + if (i + 1 < this->VectorSize.load()) return this->VectorBuffer[i + 1]; else break; @@ -179,7 +194,9 @@ namespace std T &prev(const T &Value) { - for (size_t i = 0; i < this->VectorSize; i++) + SmartLock(this->lock); + + for (size_t i = 0; i < this->VectorSize.load(); i++) { if (std::equal_to()(this->VectorBuffer[i], Value)) { @@ -198,25 +215,44 @@ namespace std void push_back(const T &Value) { - vDebug("%#lx: push_back( %#lx )", this, Value); + vDebug("push_back( %#lx )", Value); - if (this->VectorSize >= this->VectorCapacity) + if (this->VectorSize.load() >= this->VectorCapacity.load()) { - size_t newCapacity = this->VectorCapacity == 0 + size_t newCapacity = this->VectorCapacity.load() == 0 ? 1 - : this->VectorCapacity * 2; + : this->VectorCapacity.load() * 2; reserve(newCapacity); } + SmartLock(this->lock); this->VectorBuffer[this->VectorSize++] = Value; } + template + void emplace_back(Args &&...args) + { + vDebug("emplace_back( %#lx )", args...); + + if (this->VectorSize.load() >= this->VectorCapacity.load()) + { + size_t newCapacity = this->VectorCapacity.load() == 0 + ? 1 + : this->VectorCapacity.load() * 2; + reserve(newCapacity); + } + + SmartLock(this->lock); + this->VectorBuffer[this->VectorSize++] = T(std::forward(args)...); + } + void reverse() { - if (this->VectorSize <= 1) + if (this->VectorSize.load() <= 1) return; - for (size_t i = 0, j = this->VectorSize - 1; i < j; i++, j--) + SmartLock(this->lock); + for (size_t i = 0, j = this->VectorSize.load() - 1; i < j; i++, j--) { T &elem1 = this->VectorBuffer[i]; T &elem2 = this->VectorBuffer[j]; @@ -226,31 +262,35 @@ namespace std void reserve(size_t Capacity) { - assert(!(Capacity <= VectorCapacity)); + assert(!(Capacity <= VectorCapacity.load())); + + SmartLock(this->lock); T *NewBuffer = new T[Capacity]; - size_t Size = std::min(Capacity, this->VectorSize); + size_t Size = std::min(Capacity, this->VectorSize.load()); for (size_t i = 0; i < Size; i++) NewBuffer[i] = std::move(this->VectorBuffer[i]); - vDebug("%#lx: reserve( %lld )->Buffer:~%#lx", this, + vDebug("reserve( %lld )->Buffer:~%#lx", Capacity, this->VectorBuffer); delete[] this->VectorBuffer; this->VectorBuffer = NewBuffer; - this->VectorCapacity = Capacity; + this->VectorCapacity.store(Capacity); } void resize(size_t Size) { reserve(Size); - this->VectorSize = Size; + this->VectorSize.store(Size); } void clear() { - this->VectorCapacity = 0; - this->VectorSize = 0; + this->VectorCapacity.store(0); + this->VectorSize.store(0); + + SmartLock(this->lock); if (VectorBuffer != nullptr) { delete[] this->VectorBuffer; @@ -260,7 +300,8 @@ namespace std T &operator[](size_t Index) { - if (Index >= this->VectorSize || !this->VectorBuffer) + SmartLock(this->lock); + if (Index >= this->VectorSize.load() || !this->VectorBuffer) { warn("%#lx: operator[]( %lld ) is null (requested by %#lx)", this, Index, __builtin_return_address(0)); @@ -273,33 +314,71 @@ namespace std vector &operator=(const vector &v) { + SmartLock(this->lock); + if (this == &v) return *this; delete[] this->VectorBuffer; - this->VectorSize = v.VectorSize; - this->VectorCapacity = v.VectorCapacity; + this->VectorSize.store(v.VectorSize.load()); + this->VectorCapacity.store(v.VectorCapacity.load()); - vDebug("%#lx: operator=( )->Size:%lld", this, - this->VectorSize); + vDebug("operator=( )->Size:%lld", + this->VectorSize.load()); - this->VectorBuffer = new T[this->VectorSize]; - for (size_t i = 0; i < this->VectorSize; i++) + this->VectorBuffer = new T[this->VectorSize.load()]; + for (size_t i = 0; i < this->VectorSize.load(); i++) this->VectorBuffer[i] = v.VectorBuffer[i]; return *this; } void pop_back() { this->VectorSize--; } - T &front() { return this->VectorBuffer[0]; } - T &back() { return this->VectorBuffer[this->VectorSize - 1]; } - T *data() { return this->VectorBuffer; } - bool empty() const { return this->VectorSize == 0; } - size_t capacity() const { return this->VectorCapacity; } - size_t size() const { return this->VectorSize; } - iterator begin() { return this->VectorBuffer; } - iterator end() { return this->VectorBuffer + size(); } - const_iterator begin() const { return this->VectorBuffer; } - const_iterator end() const { return this->VectorBuffer + size(); } + + T &front() + { + SmartLock(this->lock); + return this->VectorBuffer[0]; + } + + T &back() + { + SmartLock(this->lock); + return this->VectorBuffer[this->VectorSize.load() - 1]; + } + + T *data() + { + SmartLock(this->lock); + return this->VectorBuffer; + } + + bool empty() const { return this->VectorSize.load() == 0; } + size_t capacity() const { return this->VectorCapacity.load(); } + size_t size() const { return this->VectorSize.load(); } + + iterator begin() + { + SmartLock(this->lock); + return this->VectorBuffer; + } + + iterator end() + { + SmartLock(this->lock); + return this->VectorBuffer + size(); + } + + const_iterator begin() const + { + SmartLock(this->lock); + return this->VectorBuffer; + } + + const_iterator end() const + { + SmartLock(this->lock); + return this->VectorBuffer + size(); + } }; } diff --git a/ipc.h b/ipc.h deleted file mode 100644 index 74b3328..0000000 --- a/ipc.h +++ /dev/null @@ -1,109 +0,0 @@ -/* - BSD 3-Clause License - - Copyright (c) 2023, EnderIce2 - All rights reserved. - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the copyright holder nor the names of its - contributors may be used to endorse or promote products derived from - this software without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ - -#ifndef __FENNIX_KERNEL_IPC_SYSCALLS_H__ -#define __FENNIX_KERNEL_IPC_SYSCALLS_H__ - -enum IPCCommand -{ - IPC_NULL, - - /** - * @brief Create a new IPC - * Creating a new IPC will return a new ID for the IPC. - * - * @return The ID of the new IPC. - */ - IPC_CREATE, - - /** - * @brief Read from IPC - * This will read from an IPC. - */ - IPC_READ, - - /** - * @brief Write to IPC - * This will write to an IPC. - * @see Flags is used as process ID. - */ - IPC_WRITE, - - IPC_DELETE, - - /** - * @brief Wait for an IPC to be ready - * This will wait for an IPC to be ready to read/write. - * If it's message passing, it will wait for a message to be received. - */ - IPC_WAIT, - - /** - * @brief Listen to a IPC - * @see Flags is used as a boolean - */ - IPC_LISTEN, -}; - -/* This must be a clone of IPCType inside ipc.hpp */ -enum IPCType -{ - IPC_TYPE_None, - - /** - * @brief Message Passing - * Message passing is a way to send messages between processes. - * - */ - IPC_TYPE_MessagePassing, - IPC_TYPE_Port, - IPC_TYPE_SharedMemory, - IPC_TYPE_Pipe, - IPC_TYPE_Socket -}; - -/* This must be a clone of IPCErrorCode inside ipc.hpp */ -enum IPCErrorCode -{ - IPC_E_CODE_Error = -1, - IPC_E_CODE_Success, - IPC_E_CODE_NotListening, - IPC_E_CODE_Timeout, - IPC_E_CODE_InvalidCommand, - IPC_E_CODE_AlreadyAllocated, - IPC_E_CODE_NotAllocated, - IPC_E_CODE_IDInUse, - IPC_E_CODE_IDNotRegistered, - IPC_E_CODE_IDNotFound, -}; - -#endif // !__FENNIX_KERNEL_IPC_SYSCALLS_H__ diff --git a/kernel.cpp b/kernel.cpp index c051a6e..4bf3388 100644 --- a/kernel.cpp +++ b/kernel.cpp @@ -45,7 +45,7 @@ __aligned(16) BootInfo bInfo{}; struct KernelConfig Config = { .AllocatorType = Memory::liballoc11, .SchedulerType = Multi, - .ModuleDirectory = {'/', 'm', 'o', 'd', 'u', 'l', 'e', 's', '\0'}, + .DriverDirectory = {'/', 'u', 's', 'r', '/', 'l', 'i', 'b', '/', 'd', 'r', 'i', 'v', 'e', 'r', 's', '\0'}, .InitPath = {'/', 'b', 'i', 'n', '/', 'i', 'n', 'i', 't', '\0'}, .UseLinuxSyscalls = false, .InterruptsOnCrash = true, @@ -53,20 +53,15 @@ struct KernelConfig Config = { .IOAPICInterruptCore = 0, .UnlockDeadLock = false, .SIMD = false, - .BootAnimation = false, + .Quiet = false, }; Video::Display *Display = nullptr; SymbolResolver::Symbols *KernelSymbolTable = nullptr; Power::Power *PowerManager = nullptr; Time::time *TimeManager = nullptr; -PCI::PCI *PCIManager = nullptr; -vfs::Virtual *fs = nullptr; -vfs::Node *DevFS = nullptr; -vfs::Node *MntFS = nullptr; -vfs::Node *ProcFS = nullptr; -vfs::Node *VarLogFS = nullptr; Tasking::Task *TaskManager = nullptr; +PCI::Manager *PCIManager = nullptr; // For the Display class. Printing on first buffer as default. int PutCharBufferIndex = 0; @@ -78,7 +73,7 @@ EXTERNC void putchar(char c) UniversalAsynchronousReceiverTransmitter::UART(UniversalAsynchronousReceiverTransmitter::COM1).Write(c); } -EXTERNC void KPrint(const char *Format, ...) +EXTERNC void _KPrint(const char *Format, va_list Args) { SmartLock(KernelLock); @@ -100,14 +95,29 @@ EXTERNC void KPrint(const char *Format, ...) } } + vprintf(Format, Args); + printf("\eCCCCCC\n"); + if (!Config.Quiet && Display) + Display->SetBuffer(0); +} + +EXTERNC void KPrint(const char *Format, ...) +{ va_list args; va_start(args, Format); - vprintf(Format, args); + _KPrint(Format, args); va_end(args); - printf("\eCCCCCC\n"); - if (!Config.BootAnimation && Display) - Display->SetBuffer(0); +#ifdef DEBUG + va_start(args, Format); + vfctprintf(uart_wrapper, nullptr, "PRINT| ", args); + va_end(args); + + va_start(args, Format); + vfctprintf(uart_wrapper, nullptr, Format, args); + va_end(args); + uart_wrapper('\n', nullptr); +#endif } EXTERNC NIF void Main() @@ -169,6 +179,11 @@ EXTERNC NIF void Main() Display->GetFramebufferStruct().GreenMaskShift, Display->GetFramebufferStruct().BlueMaskSize, Display->GetFramebufferStruct().BlueMaskShift); + + KPrint("%lld MiB / %lld MiB (%lld MiB reserved)", + TO_MiB(KernelAllocator.GetUsedMemory()), + TO_MiB(KernelAllocator.GetTotalMemory()), + TO_MiB(KernelAllocator.GetReservedMemory())); #endif /**************************************************************************************/ @@ -192,7 +207,7 @@ EXTERNC NIF void Main() bInfo.Kernel.Symbols.Shndx, bInfo.Kernel.Symbols.Sections); - if (Config.BootAnimation) + if (Config.Quiet) { Display->CreateBuffer(0, 0, 1); @@ -223,21 +238,7 @@ EXTERNC NIF void Main() TimeManager->FindTimers(PowerManager->GetACPI()); KPrint("Initializing PCI Manager"); - PCIManager = new PCI::PCI; - - foreach (auto Device in PCIManager->GetDevices()) - { - KPrint("PCI: \e8888FF%s \eCCCCCC/ \e8888FF%s \eCCCCCC/ \e8888FF%s \eCCCCCC/ \e8888FF%s \eCCCCCC/ \e8888FF%s", - PCI::Descriptors::GetVendorName(Device.Header->VendorID), - PCI::Descriptors::GetDeviceName(Device.Header->VendorID, - Device.Header->DeviceID), - PCI::Descriptors::DeviceClasses[Device.Header->Class], - PCI::Descriptors::GetSubclassName(Device.Header->Class, - Device.Header->Subclass), - PCI::Descriptors::GetProgIFName(Device.Header->Class, - Device.Header->Subclass, - Device.Header->ProgIF)); - } + PCIManager = new PCI::Manager; KPrint("Initializing Bootstrap Processor Timer"); Interrupts::InitializeTimer(0); @@ -245,109 +246,12 @@ EXTERNC NIF void Main() KPrint("Initializing SMP"); SMP::Initialize(PowerManager->GetMADT()); - KPrint("Initializing Filesystem..."); - fs = new vfs::Virtual; - vfs::Node *root = fs->GetRootNode(); - if (root->Children.size() == 0) - fs->nRoot = new vfs::vfsRoot("/", fs); - - for (size_t i = 0; i < MAX_MODULES; i++) - { - if (!bInfo.Modules[i].Address) - continue; - - if (strcmp(bInfo.Modules[i].CommandLine, "initrd") == 0) - { - debug("Found initrd at %p", bInfo.Modules[i].Address); - static char initrd = 0; - if (!initrd++) - { - uintptr_t initrdAddress = (uintptr_t)bInfo.Modules[i].Address; - vfs::USTAR *ustar = new vfs::USTAR; - ustar->ReadArchive(initrdAddress, fs); - } - } - } - - if (!fs->PathExists("/dev")) - DevFS = new vfs::Node(fs->nRoot, "dev", vfs::DIRECTORY); - else - { - vfs::RefNode *dev = fs->Open("/dev"); - if (dev->node->Type != NodeType::DIRECTORY) - { - KPrint("\eE85230/dev is not a directory! Halting..."); - CPU::Stop(); - } - DevFS = dev->node; - delete dev; - } - - new vfs::NullDevice(); - new vfs::RandomDevice(); - new vfs::ZeroDevice(); - - if (!fs->PathExists("/mnt")) - MntFS = new vfs::Node(fs->nRoot, "mnt", vfs::DIRECTORY); - else - { - vfs::RefNode *mnt = fs->Open("/mnt"); - if (mnt->node->Type != NodeType::DIRECTORY) - { - KPrint("\eE85230/mnt is not a directory! Halting..."); - CPU::Stop(); - } - MntFS = mnt->node; - delete mnt; - } - - if (!fs->PathExists("/proc")) - ProcFS = new vfs::Node(fs->nRoot, "proc", vfs::DIRECTORY); - else - { - vfs::RefNode *proc = fs->Open("/proc", nullptr); - if (proc->node->Type != NodeType::DIRECTORY) - { - KPrint("\eE85230/proc is not a directory! Halting..."); - CPU::Stop(); - } - ProcFS = proc->node; - delete proc; - } - - if (!fs->PathExists("/var")) - { - vfs::Node *var = new vfs::Node(fs->nRoot, "var", vfs::DIRECTORY); - VarLogFS = new vfs::Node(var, "log", vfs::DIRECTORY); - } - else - { - vfs::RefNode *var = fs->Open("/var", nullptr); - if (var->node->Type != NodeType::DIRECTORY) - { - KPrint("\eE85230/var is not a directory! Halting..."); - CPU::Stop(); - } - VarLogFS = var->node; - delete var; - - if (!fs->PathExists("/var/log")) - VarLogFS = new vfs::Node(VarLogFS, "log", vfs::DIRECTORY); - else - { - vfs::RefNode *var_log = fs->Open("/var/log", nullptr); - if (var_log->node->Type != NodeType::DIRECTORY) - { - KPrint("\eE85230/var/log is not a directory! Halting..."); - CPU::Stop(); - } - VarLogFS = var_log->node; - delete var_log; - } - } + KPrint("Initializing Filesystem"); + KernelVFS(); KPrint("\e058C19################################"); TaskManager = new Tasking::Task(Tasking::IP(KernelMainThread)); + TaskManager->StartScheduler(); CPU::Halt(true); } @@ -361,7 +265,7 @@ EXTERNC __no_stack_protector NIF void Entry(BootInfo *Info) if (strcmp(CPU::Hypervisor(), x86_CPUID_VENDOR_TCG) == 0) { - debug("\n\n----------------------------------------\nDEBUGGER DETECTED\n----------------------------------------\n\n"); + info("\n\n----------------------------------------\nDEBUGGER DETECTED\n----------------------------------------\n\n"); DebuggerIsAttached = true; } @@ -472,33 +376,37 @@ EXTERNC __no_stack_protector void BeforeShutdown(bool Reboot) KPrint("%s...", Reboot ? "Rebooting" : "Shutting down"); + KPrint("Stopping network interfaces"); if (NIManager) delete NIManager, NIManager = nullptr; + KPrint("Stopping disk manager"); if (DiskManager) delete DiskManager, DiskManager = nullptr; - if (ModuleManager) - delete ModuleManager, ModuleManager = nullptr; + KPrint("Unloading all drivers"); + if (DriverManager) + delete DriverManager, DriverManager = nullptr; + KPrint("Stopping scheduling"); if (TaskManager && !TaskManager->IsPanic()) { TaskManager->SignalShutdown(); delete TaskManager, TaskManager = nullptr; } + KPrint("Unloading filesystems"); if (fs) delete fs, fs = nullptr; + KPrint("Stopping timers"); if (TimeManager) delete TimeManager, TimeManager = nullptr; - // if (Display) - // delete Display, Display = nullptr; // PowerManager should not be called // https://wiki.osdev.org/Calling_Global_Constructors - debug("Calling destructors..."); + KPrint("Calling destructors"); for (CallPtr *func = __fini_array_start; func != __fini_array_end; func++) (*func)(); __cxa_finalize(nullptr); diff --git a/kernel.h b/kernel.h index f82a4a2..7b0cce7 100644 --- a/kernel.h +++ b/kernel.h @@ -22,51 +22,54 @@ #include #ifdef __cplusplus +#include #include #include #include #include #include -#include +#include #include #include #include #include #include +#include #endif extern struct BootInfo bInfo; extern struct KernelConfig Config; extern bool DebuggerIsAttached; + #ifdef __cplusplus extern Video::Display *Display; extern SymbolResolver::Symbols *KernelSymbolTable; extern Power::Power *PowerManager; extern Time::time *TimeManager; -extern PCI::PCI *PCIManager; +extern PCI::Manager *PCIManager; extern vfs::Virtual *fs; extern vfs::Node *DevFS; extern vfs::Node *MntFS; extern vfs::Node *ProcFS; extern vfs::Node *VarLogFS; +extern vfs::PTMXDevice *ptmx; extern Tasking::Task *TaskManager; extern Disk::Manager *DiskManager; -extern Module::Module *ModuleManager; +extern Driver::Manager *DriverManager; extern NetworkInterfaceManager::NetworkInterface *NIManager; #endif // __cplusplus EXTERNC void putchar(char c); -EXTERNC void KPrint(const char *format, ...); +EXTERNC void _KPrint(const char *Format, va_list Args); +EXTERNC void KPrint(const char *Format, ...); EXTERNC void Entry(struct BootInfo *Info); EXTERNC void BeforeShutdown(bool Reboot); EXTERNC void TaskingPanic(); -EXTERNC void BootLogoAnimationThread(); -EXTERNC void ExitLogoAnimationThread(); - +EXTERNC void KernelVFS(); EXTERNC void KernelMainThread(); EXTERNC void KernelShutdownThread(bool Reboot); EXTERNC void KST_Reboot(); diff --git a/kernel_config.cpp b/kernel_config.cpp index b0206d4..cc6d334 100644 --- a/kernel_config.cpp +++ b/kernel_config.cpp @@ -70,7 +70,7 @@ static struct cag_option ConfigOptions[] = { .access_letters = "dD", .access_name = "drvdir", .value_name = "PATH", - .description = "Directory to load modules from"}, + .description = "Directory to load drivers from"}, {.identifier = 'i', .access_letters = "iI", @@ -104,9 +104,9 @@ static struct cag_option ConfigOptions[] = { {.identifier = 'b', .access_letters = NULL, - .access_name = "bootanim", + .access_name = "quiet", .value_name = "BOOL", - .description = "Enable boot animation"}, + .description = "Enable quiet boot"}, {.identifier = 'h', .access_letters = "h", @@ -218,7 +218,7 @@ void ParseConfig(char *ConfigString, KernelConfig *ModConfig) case 'd': { value = cag_option_get_value(&context); - strncpy(ModConfig->ModuleDirectory, value, strlen(value)); + strncpy(ModConfig->DriverDirectory, value, strlen(value)); KPrint("\eAAFFAAUsing %s as module directory", value); break; } @@ -267,14 +267,14 @@ void ParseConfig(char *ConfigString, KernelConfig *ModConfig) case 'b': { value = cag_option_get_value(&context); - strcmp(value, "true") == 0 ? ModConfig->BootAnimation = true - : ModConfig->BootAnimation = false; - KPrint("\eAAFFAABoot animation: %s", value); + strcmp(value, "true") == 0 ? ModConfig->Quiet = true + : ModConfig->Quiet = false; + KPrint("\eAAFFAAQuiet boot: %s", value); break; } case 'h': { - KPrint("\n---------------------------------------------------------------------------\nUsage: kernel.fsys [OPTION]...\nKernel configuration."); + KPrint("\n---------------------------------------------------------------------------\nUsage: fennix.elf [OPTION]...\nKernel configuration."); cag_option_print(ConfigOptions, CAG_ARRAY_SIZE(ConfigOptions), nullptr); KPrint("\eFF2200System Halted."); diff --git a/kernel_thread.cpp b/kernel_thread.cpp index b70eb8d..047c7b0 100644 --- a/kernel_thread.cpp +++ b/kernel_thread.cpp @@ -30,14 +30,11 @@ #include #include -#include "mapi.hpp" -#include "Fex.hpp" - using vfs::Node; using vfs::NodeType; Disk::Manager *DiskManager = nullptr; -Module::Module *ModuleManager = nullptr; +Driver::Manager *DriverManager = nullptr; NetworkInterfaceManager::NetworkInterface *NIManager = nullptr; int SpawnInit() @@ -55,42 +52,27 @@ int SpawnInit() "--critical", nullptr}; - return Execute::Spawn(Config.InitPath, argv, envp, - nullptr, - Tasking::TaskCompatibility::Native, - true); -} + Tasking::TaskCompatibility compat = Tasking::Native; + if (Config.UseLinuxSyscalls) + compat = Tasking::Linux; -void CleanupProcessesThreadWrapper() -{ - TaskManager->CleanupProcessesThread(); + return Execute::Spawn(Config.InitPath, argv, envp, + nullptr, false, + compat, true); } void KernelMainThread() { - Tasking::TCB *clnThd = - TaskManager->CreateThread(thisProcess, - Tasking::IP(CleanupProcessesThreadWrapper)); - clnThd->SetPriority(Tasking::Idle); - TaskManager->SetCleanupThread(clnThd); thisThread->SetPriority(Tasking::Critical); - Tasking::TCB *blaThread = nullptr; - - if (Config.BootAnimation) - { - blaThread = - TaskManager->CreateThread(thisProcess, - Tasking::IP(BootLogoAnimationThread)); - blaThread->Rename("Logo Animation"); - } - #ifdef DEBUG + StressKernel(); // TaskManager->CreateThread(thisProcess, Tasking::IP(tasking_test_fb)); // TaskManager->CreateThread(thisProcess, Tasking::IP(tasking_test_mutex)); // ilp; TaskManager->CreateThread(thisProcess, Tasking::IP(TaskMgr)); TaskManager->CreateThread(thisProcess, Tasking::IP(lsof)); + TaskManager->CreateThread(thisProcess, Tasking::IP(TaskHeartbeat)); TreeFS(fs->GetRootNode(), 0); #endif @@ -101,66 +83,62 @@ void KernelMainThread() if (IsVirtualizedEnvironment()) KPrint("Running in a virtualized environment"); - KPrint("Initializing Disk Manager..."); + KPrint("Initializing Disk Manager"); DiskManager = new Disk::Manager; - KPrint("Loading Modules..."); - ModuleManager = new Module::Module; - ModuleManager->LoadModules(); + KPrint("Loading Drivers"); + DriverManager = new Driver::Manager; + DriverManager->LoadAllDrivers(); - KPrint("Fetching Disks..."); - if (ModuleManager->GetModules().size() > 0) - { - foreach (auto mod in ModuleManager->GetModules()) - if (((FexExtended *)mod.ExtendedHeaderAddress)->Module.Type == FexModuleType::FexModuleType_Storage) - DiskManager->FetchDisks(mod.modUniqueID); - } - else - KPrint("\eE85230No disk modules found! Cannot fetch disks!"); + // KPrint("Fetching Disks"); + /* KernelCallback */ + // if (DriverManager->GetModules().size() > 0) + // { + // foreach (auto mod in DriverManager->GetModules()) + // if (((FexExtended *)mod.ExtendedHeaderAddress)->Driver.Type == FexDriverType::FexDriverType_Storage) + // DiskManager->FetchDisks(mod.modUniqueID); + // } + // else + // KPrint("\eE85230No disk driver found! Cannot fetch disks!"); - KPrint("Initializing Network Interface Manager..."); - NIManager = new NetworkInterfaceManager::NetworkInterface; - KPrint("Starting Network Interface Manager..."); - NIManager->StartService(); + // KPrint("Initializing Network Interface Manager"); + // NIManager = new NetworkInterfaceManager::NetworkInterface; + // KPrint("Starting Network Interface Manager"); + // NIManager->StartService(); - KPrint("Setting up userspace"); +#ifdef DEBUG + // TaskManager->CreateThread(thisProcess, + // Tasking::IP(KShellThread)) + // ->Rename("Kernel Shell"); +#endif + + KPrint("Executing %s", Config.InitPath); int ExitCode = -1; Tasking::TCB *initThread = nullptr; int tid = SpawnInit(); if (tid < 0) { - KPrint("\eE85230Failed to start %s! Code: %d", Config.InitPath, tid); + KPrint("\eE85230Failed to start %s! Code: %d", + Config.InitPath, tid); goto Exit; } - KPrint("Waiting for \e22AAFF%s\eCCCCCC to start...", Config.InitPath); + KPrint("Waiting for \e22AAFF%s\eCCCCCC to start...", + Config.InitPath); thisThread->SetPriority(Tasking::Idle); initThread = TaskManager->GetThreadByID(tid); - initThread->KeepInMemory = true; TaskManager->WaitForThread(initThread); ExitCode = initThread->GetExitCode(); Exit: - if (ExitCode == 0) - { - KPrint("\eFF7900%s process exited with code %d and it didn't invoked the shutdown function.", - Config.InitPath, ExitCode); - KPrint("System Halted"); - CPU::Halt(true); - } - KPrint("\eE85230Userspace process exited with code %d (%#x)", ExitCode, ExitCode < 0 ? -ExitCode : ExitCode); - KPrint("Dropping to kernel shell..."); + KPrint("Dropping to kernel shell"); TaskManager->Sleep(1000); - TaskManager->WaitForThread(blaThread); TaskManager->CreateThread(thisProcess, Tasking::IP(KShellThread)) ->Rename("Kernel Shell"); - - if (initThread) - initThread->KeepInMemory = false; CPU::Halt(true); } @@ -169,22 +147,16 @@ void __no_stack_protector KernelShutdownThread(bool Reboot) { SmartLock(ShutdownLock); debug("KernelShutdownThread(%s)", Reboot ? "true" : "false"); - if (Config.BootAnimation && TaskManager) - { - Tasking::TCB *elaThread = - TaskManager->CreateThread(thisProcess, - Tasking::IP(ExitLogoAnimationThread)); - elaThread->Rename("Logo Animation"); - TaskManager->WaitForThread(elaThread); - } BeforeShutdown(Reboot); trace("%s...", Reboot ? "Rebooting" : "Shutting down"); + KPrint("Waiting for ACPI..."); if (Reboot) PowerManager->Reboot(); else PowerManager->Shutdown(); + KPrint("CPU Halted"); CPU::Stop(); } diff --git a/kernel_vfs.cpp b/kernel_vfs.cpp new file mode 100644 index 0000000..d63db1f --- /dev/null +++ b/kernel_vfs.cpp @@ -0,0 +1,145 @@ +/* + 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 "kernel.h" + +#include +#include +#include + +vfs::Virtual *fs = nullptr; +vfs::Node *DevFS = nullptr; +vfs::Node *MntFS = nullptr; +vfs::Node *ProcFS = nullptr; +vfs::Node *VarLogFS = nullptr; +vfs::PTMXDevice *ptmx = nullptr; + +EXTERNC NIF void KernelVFS() +{ + fs = new vfs::Virtual; + vfs::Node *root = fs->GetRootNode(); + if (root->Children.size() == 0) + fs->nRoot = new vfs::vfsRoot("/", fs); + + for (size_t i = 0; i < MAX_MODULES; i++) + { + if (!bInfo.Modules[i].Address) + continue; + + if (strcmp(bInfo.Modules[i].CommandLine, "initrd") == 0) + { + debug("Found initrd at %p", bInfo.Modules[i].Address); + static char initrd = 0; + if (!initrd++) + { + uintptr_t initrdAddress = (uintptr_t)bInfo.Modules[i].Address; + + Memory::Virtual vmm; + if (!vmm.Check((void *)initrdAddress)) + { + warn("Initrd is not mapped!"); + vmm.Map((void *)initrdAddress, (void *)initrdAddress, + bInfo.Modules[i].Size, Memory::RW); + } + + vfs::USTAR *ustar = new vfs::USTAR; + ustar->ReadArchive(initrdAddress, fs); + } + } + } + + KPrint("Mounting filesystems"); + + if (!fs->PathExists("/dev")) + DevFS = new vfs::Node(fs->nRoot, "dev", vfs::DIRECTORY); + else + { + vfs::RefNode *dev = fs->Open("/dev"); + if (dev->node->Type != vfs::NodeType::DIRECTORY) + { + KPrint("\eE85230/dev is not a directory!"); + CPU::Stop(); + } + DevFS = dev->node; + delete dev; + } + + if (!fs->PathExists("/mnt")) + MntFS = new vfs::Node(fs->nRoot, "mnt", vfs::DIRECTORY); + else + { + vfs::RefNode *mnt = fs->Open("/mnt"); + if (mnt->node->Type != vfs::NodeType::DIRECTORY) + { + KPrint("\eE85230/mnt is not a directory!"); + CPU::Stop(); + } + MntFS = mnt->node; + delete mnt; + } + + if (!fs->PathExists("/proc")) + ProcFS = new vfs::Node(fs->nRoot, "proc", vfs::DIRECTORY); + else + { + vfs::RefNode *proc = fs->Open("/proc", nullptr); + if (proc->node->Type != vfs::NodeType::DIRECTORY) + { + KPrint("\eE85230/proc is not a directory!"); + CPU::Stop(); + } + ProcFS = proc->node; + delete proc; + } + + if (!fs->PathExists("/var")) + { + vfs::Node *var = new vfs::Node(fs->nRoot, "var", vfs::DIRECTORY); + VarLogFS = new vfs::Node(var, "log", vfs::DIRECTORY); + } + else + { + vfs::RefNode *var = fs->Open("/var", nullptr); + if (var->node->Type != vfs::NodeType::DIRECTORY) + { + KPrint("\eE85230/var is not a directory!"); + CPU::Stop(); + } + VarLogFS = var->node; + delete var; + + if (!fs->PathExists("/var/log")) + VarLogFS = new vfs::Node(VarLogFS, "log", vfs::DIRECTORY); + else + { + vfs::RefNode *var_log = fs->Open("/var/log", nullptr); + if (var_log->node->Type != vfs::NodeType::DIRECTORY) + { + KPrint("\eE85230/var/log is not a directory!"); + CPU::Stop(); + } + VarLogFS = var_log->node; + delete var_log; + } + } + + new vfs::NullDevice(); + new vfs::RandomDevice(); + new vfs::ZeroDevice(); + new vfs::KConDevice(); + ptmx = new vfs::PTMXDevice(); +} diff --git a/kshell/cmds.hpp b/kshell/cmds.hpp index d120022..e523061 100644 --- a/kshell/cmds.hpp +++ b/kshell/cmds.hpp @@ -21,8 +21,10 @@ #include void cmd_lsof(const char *args); +void cmd_clear(const char *args); void cmd_echo(const char *args); void cmd_ls(const char *args); +void cmd_tree(const char *args); void cmd_cd(const char *args); void cmd_cat(const char *args); void cmd_ps(const char *args); @@ -37,5 +39,10 @@ void cmd_exit(const char *args); void cmd_shutdown(const char *args); void cmd_reboot(const char *args); void cmd_lspci(const char *args); +void cmd_lsacpi(const char *args); +void cmd_lsmod(const char *args); +void cmd_modinfo(const char *args); + +#define IF_ARG(x) strcmp(args, x) == 0 #endif // !__FENNIX_KERNEL_SHELL_CMDS_H__ diff --git a/kshell/commands/cat.cpp b/kshell/commands/cat.cpp index eefeb73..ec61a67 100644 --- a/kshell/commands/cat.cpp +++ b/kshell/commands/cat.cpp @@ -47,8 +47,11 @@ void cmd_cat(const char *args) fstat(fd, &st); char *buffer = new char[st.st_size + 1]; - fread(fd, buffer, st.st_size); - printf("%s\n", buffer); + ssize_t rBytes = fread(fd, buffer, st.st_size); + if (rBytes > 0) + printf("%s\n", buffer); + else + printf("cat: %s: Could not read file\n", args); delete[] buffer; fclose(fd); } diff --git a/core/module/api.hpp b/kshell/commands/clear.cpp similarity index 76% rename from core/module/api.hpp rename to kshell/commands/clear.cpp index 8598198..d518561 100644 --- a/core/module/api.hpp +++ b/kshell/commands/clear.cpp @@ -15,13 +15,12 @@ along with Fennix Kernel. If not, see . */ -#ifndef __FENNIX_KERNEL_MODULE_API_H__ -#define __FENNIX_KERNEL_MODULE_API_H__ +#include "../cmds.hpp" -#include +#include "../../kernel.h" -#include "../../mapi.hpp" - -extern KernelAPI KernelAPITemplate; - -#endif // !__FENNIX_KERNEL_MODULE_API_H__ +void cmd_clear(const char *) +{ + Display->SetBufferCursor(0, 0, 0); + Display->ClearBuffer(0); +} diff --git a/kshell/commands/lsacpi.cpp b/kshell/commands/lsacpi.cpp new file mode 100644 index 0000000..e7228f0 --- /dev/null +++ b/kshell/commands/lsacpi.cpp @@ -0,0 +1,35 @@ +/* + 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 "../cmds.hpp" + +#include +#include + +#include "../../kernel.h" + +using namespace vfs; + +void cmd_lsacpi(const char *) +{ + ACPI::ACPI *acpi = (ACPI::ACPI *)PowerManager->GetACPI(); + foreach (auto Table in acpi->Tables) + { + printf("%s ", Table.first); + } + putchar('\n'); +} diff --git a/include_std/std/utility.hpp b/kshell/commands/lsmod.cpp similarity index 60% rename from include_std/std/utility.hpp rename to kshell/commands/lsmod.cpp index 9c2b16e..5a4b561 100644 --- a/include_std/std/utility.hpp +++ b/kshell/commands/lsmod.cpp @@ -15,25 +15,23 @@ along with Fennix Kernel. If not, see . */ -#ifndef __FENNIX_KERNEL_STD_UTILITY_H__ -#define __FENNIX_KERNEL_STD_UTILITY_H__ +#include "../cmds.hpp" -#include +#include "../../kernel.h" -namespace std +void cmd_lsmod(const char *) { - template - struct pair + std::unordered_map drivers = + DriverManager->GetDrivers(); + + printf("DRIVER | ID | INIT | MEMORY\n"); + + foreach (auto &drv in drivers) { - typedef T1 first_type; - typedef T2 second_type; - - T1 first; - T2 second; - - pair() : first(T1()), second(T2()) {} - pair(const T1 &x, const T2 &y) : first(x), second(y) {} - }; + printf("%-15s | %5ld | %s | %ld KiB\n", + drv.second.Name, + drv.first, + drv.second.Initialized ? "Y" : "N", + TO_KiB(drv.second.vma->GetAllocatedMemorySize())); + } } - -#endif // !__FENNIX_KERNEL_STD_UTILITY_H__ diff --git a/kshell/commands/lspci.cpp b/kshell/commands/lspci.cpp index ddf66e9..ef985fc 100644 --- a/kshell/commands/lspci.cpp +++ b/kshell/commands/lspci.cpp @@ -23,8 +23,48 @@ using namespace vfs; -void cmd_lspci(const char *) +void cmd_lspci(const char *args) { + if (args) + { + if (IF_ARG("-i") || IF_ARG("--info")) + { + foreach (auto Device in PCIManager->GetDevices()) + { + const char *HdrType; + switch (Device.Header->HeaderType) + { + case 0: + HdrType = "Normal "; + break; + case 1: + HdrType = "PCI-PCI"; + break; + case 2: + HdrType = "Cardbus"; + break; + default: + HdrType = "Unknown"; + break; + } + + printf("%04x:%04x | %s:%03d | %02x:%02x.%d | %s: %s %s\n", + Device.Header->VendorID, + Device.Header->DeviceID, + HdrType, Device.Header->HeaderType, + Device.Bus, + Device.Device, + Device.Function, + PCI::Descriptors::GetSubclassName(Device.Header->Class, + Device.Header->Subclass), + PCI::Descriptors::GetVendorName(Device.Header->VendorID), + PCI::Descriptors::GetDeviceName(Device.Header->VendorID, + Device.Header->DeviceID)); + } + return; + } + } + foreach (auto Device in PCIManager->GetDevices()) { printf("%02x:%02x.%d: %s: %s %s\n", diff --git a/kshell/commands/modinfo.cpp b/kshell/commands/modinfo.cpp new file mode 100644 index 0000000..286631d --- /dev/null +++ b/kshell/commands/modinfo.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 "../cmds.hpp" + +#include "../../kernel.h" + +void cmd_modinfo(const char *args) +{ + if (args[0] == '\0') + { + printf("Usage: modinfo \n"); + return; + } + + dev_t id = atoi(args); + + std::unordered_map drivers = + DriverManager->GetDrivers(); + + if (drivers.find(id) == drivers.end()) + { + bool found = false; + foreach (auto var in drivers) + { + if (strcmp(var.second.Name, args) == 0) + { + id = var.first; + found = true; + break; + } + } + + if (!found) + { + printf("Driver not found\n"); + return; + } + } + + Driver::DriverObject drv = drivers[id]; + printf("Base Info:\n"); + printf(" Name: %s\n", drv.Name); + printf(" Description: %s\n", drv.Description); + printf(" Author: %s\n", drv.Author); + printf(" Version: %s\n", drv.Version); + printf(" License: %s\n", drv.License); + printf("Resource Info:\n"); + printf(" Initialized: %s\n", drv.Initialized ? "yes" : "no"); + printf(" Error Code: %i (%s)\n", drv.ErrorCode, strerror(drv.ErrorCode)); + printf(" Path: %s\n", drv.Path); + printf(" Used Memory: %ld KiB\n", TO_KiB(drv.vma->GetAllocatedMemorySize())); + printf(" Used IRQs:%s\n", drv.InterruptHandlers->empty() ? " none" : ""); + foreach (auto var in *drv.InterruptHandlers) + { + printf(" IRQ%-2d: %#lx\n", + var.first, (uintptr_t)var.second); + } +} diff --git a/kshell/commands/top.cpp b/kshell/commands/top.cpp index 4076e44..0f73477 100644 --- a/kshell/commands/top.cpp +++ b/kshell/commands/top.cpp @@ -25,6 +25,20 @@ using namespace vfs; using namespace Tasking; +const char *TaskStateStrings[] = { + "Unknown", // Unknown + "Ready", // Ready + "Running", // Running + "Sleeping", // Sleeping + "Blocked", // Blocked + "Stopped", // Stopped + "Waiting", // Waiting + + "CoreDump", // Core dump + "Zombie", // Zombie + "Terminated", // Terminated +}; + void cmd_top(const char *) { printf("\e9400A1PID \e9CA100Name \e00A15BState \eCCCCCCPriority Memory Usage CPU Usage\n"); @@ -32,12 +46,12 @@ void cmd_top(const char *) { #if defined(a64) printf("\e9400A1%-4d \e9CA100%-20s \e00A15B%s \eCCCCCC%d %ld KiB %ld\n", - Proc->ID, Proc->Name, Proc->State == Running ? "Running" : "Stopped", + Proc->ID, Proc->Name, TaskStateStrings[Proc->State.load()], Proc->Info.Priority, TO_KiB(Proc->GetSize()), Proc->Info.UserTime + Proc->Info.KernelTime); #elif defined(a32) printf("\e9400A1%-4d \e9CA100%-20s \e00A15B%s \eCCCCCC%d %lld KiB %lld\n", - Proc->ID, Proc->Name, Proc->State == Running ? "Running" : "Stopped", + Proc->ID, Proc->Name, TaskStateStrings[Proc->State.load()], Proc->Info.Priority, TO_KiB(Proc->GetSize()), Proc->Info.UserTime + Proc->Info.KernelTime); #endif @@ -46,12 +60,12 @@ void cmd_top(const char *) { #if defined(a64) printf(" \eA80011%-4d \e9CA100%-20s \e00A15B%s \eCCCCCC%d %ld KiB %ld\n", - Thrd->ID, Thrd->Name, Thrd->State == Running ? "Running" : "Stopped", + Thrd->ID, Thrd->Name, TaskStateStrings[Thrd->State.load()], Thrd->Info.Priority, TO_KiB(Thrd->GetSize()), Thrd->Info.UserTime + Thrd->Info.KernelTime); #elif defined(a32) printf(" \eA80011%-4d \e9CA100%-20s \e00A15B%s \eCCCCCC%d %lld KiB %lld\n", - Thrd->ID, Thrd->Name, Thrd->State == Running ? "Running" : "Stopped", + Thrd->ID, Thrd->Name, TaskStateStrings[Thrd->State.load()], Thrd->Info.Priority, TO_KiB(Thrd->GetSize()), Thrd->Info.UserTime + Thrd->Info.KernelTime); #endif diff --git a/kshell/commands/tree.cpp b/kshell/commands/tree.cpp new file mode 100644 index 0000000..9166b5d --- /dev/null +++ b/kshell/commands/tree.cpp @@ -0,0 +1,75 @@ +/* + 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 "../cmds.hpp" + +#include + +#include "../../kernel.h" + +using namespace vfs; + +void tree_loop(Node *rootNode, int depth = 0) +{ + foreach (auto Child in rootNode->Children) + { + Display->SetBuffer(0); + if (Child->Type == NodeType::DIRECTORY || + Child->Type == NodeType::MOUNTPOINT) + { + printf("%*s%*s%*s|- %s\n", + depth, "", + depth, "", + depth, "", + Child->Name); + tree_loop(Child, depth + 1); + } + else + printf("%*s%*s%*s|- %s\n", + depth, "", + depth, "", + depth, "", + Child->Name); + } +} + +void cmd_tree(const char *args) +{ + Node *rootNode = thisProcess->CurrentWorkingDirectory; + if (args[0] == '\0') + { + if (rootNode == nullptr) + rootNode = fs->GetRootNode()->Children[0]; + } + else + { + rootNode = fs->GetNodeFromPath(args, thisProcess->CurrentWorkingDirectory); + if (rootNode == nullptr) + { + printf("ls: %s: No such file or directory\n", args); + return; + } + if (rootNode->Type != NodeType::DIRECTORY) + { + printf("%s\n", rootNode->Name); + return; + } + } + + printf("%s\n", rootNode->Name); + tree_loop(rootNode); +} diff --git a/kshell/commands/uname.cpp b/kshell/commands/uname.cpp index e4e59a7..0a525e6 100644 --- a/kshell/commands/uname.cpp +++ b/kshell/commands/uname.cpp @@ -27,29 +27,29 @@ void cmd_uname(const char *args) { if (args) { - if (strcmp(args, "-a") == 0) + if (IF_ARG("-a") || IF_ARG("--all")) { printf("Fennix Kernel %s %s %s %s\n", KERNEL_VERSION, KERNEL_NAME, __DATE__, KERNEL_ARCH); } - else if (strcmp(args, "-s") == 0) + else if (IF_ARG("-s") || IF_ARG("--kernel-name")) { printf("%s\n", KERNEL_NAME); } - else if (strcmp(args, "-v") == 0) + else if (IF_ARG("-v") || IF_ARG("--kernel-version")) { printf("%s\n", KERNEL_VERSION); } - else if (strcmp(args, "-n") == 0) + else if (IF_ARG("-n") || IF_ARG("--nodename")) { printf("unknown\n"); } - else if (strcmp(args, "-r") == 0) + else if (IF_ARG("-r") || IF_ARG("--kernel-release")) { printf("%s\n", KERNEL_NAME); } - else if (strcmp(args, "-m") == 0) + else if (IF_ARG("-m") || IF_ARG("--machine")) { printf("%s\n", KERNEL_ARCH); } diff --git a/kshell/shell.cpp b/kshell/shell.cpp index 0073903..f16b36f 100644 --- a/kshell/shell.cpp +++ b/kshell/shell.cpp @@ -18,83 +18,15 @@ #include #include -#include +#include #include #include -#include "../modules/PersonalSystem2/keyboard.hpp" #include "../kernel.h" -#include "../Fex.hpp" -#include "../mapi.hpp" +#include "../driver.h" #include "cmds.hpp" -using namespace PS2Keyboard; - NewLock(ShellLock); - -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; - -char GetLetterFromScanCode(uint8_t ScanCode) -{ - if (ScanCode & 0x80) - { - switch (ScanCode) - { - case KEY_U_LSHIFT: - LowerCase = true; - return 0; - case KEY_U_RSHIFT: - LowerCase = true; - return 0; - default: - return 0; - } - } - else - { - switch (ScanCode) - { - case KEY_D_RETURN: - return '\n'; - case KEY_D_LSHIFT: - LowerCase = false; - return 0; - case KEY_D_RSHIFT: - LowerCase = false; - return 0; - 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 0; -} - -int GetChar() -{ - return 0; -} - struct Command { const char *Name; @@ -104,6 +36,7 @@ struct Command static Command commands[] = { {"lsof", cmd_lsof}, {"ls", cmd_ls}, + {"tree", cmd_tree}, {"cd", cmd_cd}, {"cat", cmd_cat}, {"echo", cmd_echo}, @@ -113,7 +46,7 @@ static Command commands[] = { {"rmdir", nullptr}, {"mv", nullptr}, {"cp", nullptr}, - {"clear", nullptr}, + {"clear", cmd_clear}, {"help", nullptr}, {"exit", cmd_exit}, {"reboot", cmd_reboot}, @@ -136,40 +69,42 @@ static Command commands[] = { {"chgrp", nullptr}, {"chmod", nullptr}, {"chroot", nullptr}, - {"lspci", cmd_lspci}}; + {"lspci", cmd_lspci}, + {"lsacpi", cmd_lsacpi}, + {"lsmod", cmd_lsmod}, + {"modinfo", cmd_modinfo}, + {"insmod", nullptr}, + {"rmmod", nullptr}, + {"modprobe", nullptr}, + {"depmod", nullptr}, +}; void StartKernelShell() { + if (ShellLock.Locked()) + return; SmartLock(ShellLock); debug("Starting kernel shell..."); - printf("Starting kernel shell...\n"); + KPrint("Starting kernel shell..."); thisThread->SetPriority(Tasking::TaskPriority::High); - Display->SetBuffer(0); - Module::ModuleFile KeyboardModule; - if (likely(ModuleManager->GetModules().size() > 0)) - { - foreach (auto Module in ModuleManager->GetModules()) - { - if (((FexExtended *)Module.ExtendedHeaderAddress)->Module.Type == FexModuleType::FexModuleType_Input && - ((FexExtended *)Module.ExtendedHeaderAddress)->Module.TypeFlags & FexDriverInputTypes::FexDriverInputTypes_Keyboard) - { - KeyboardModule = Module; - printf("Using driver \eCA21F6%s\eCCCCCC for keyboard input.\n", - ((FexExtended *)Module.ExtendedHeaderAddress)->Module.Name); - break; - } - } - } - - Display->SetBuffer(0); std::string Buffer; std::vector History; size_t HistoryIndex = 0; bool CtrlDown = false; + bool UpperCase = false; bool TabDoublePress = false; + int kfd = fopen("/dev/key", "r"); + if (kfd < 0) + { + KPrint("Failed to open keyboard device! %s", + strerror(kfd)); + return; + } + + printf("Using \eCA21F6/dev/key\eCCCCCC for keyboard input.\n"); while (true) { size_t BackspaceCount = 0; @@ -185,27 +120,50 @@ void StartKernelShell() cwd->FullPath); Display->SetBuffer(0); + uint8_t scBuf[2]; + scBuf[1] = 0x00; /* Request scan code */ + ssize_t nBytes; while (true) { - KernelCallback callback{}; - callback.Reason = PollWaitReason; - ModuleManager->IOCB(KeyboardModule.modUniqueID, &callback); - char c = GetLetterFromScanCode(callback.InputCallback.Keyboard.Key); + nBytes = fread(kfd, scBuf, 2); + if (nBytes == 0) + continue; + if (nBytes < 0) + { + KPrint("Failed to read from keyboard device: %s", + strerror((int)nBytes)); + return; + } - switch (callback.InputCallback.Keyboard.Key) + if (scBuf[0] == 0x00) + continue; + + uint8_t sc = scBuf[0]; + switch (sc & ~KEY_PRESSED) { - case KEY_D_LCTRL: + case KEY_LEFT_CTRL: + case KEY_RIGHT_CTRL: { - CtrlDown = true; + if (sc & KEY_PRESSED) + CtrlDown = true; + else + CtrlDown = false; continue; } - case KEY_U_LCTRL: + case KEY_LEFT_SHIFT: + case KEY_RIGHT_SHIFT: { - CtrlDown = false; + if (sc & KEY_PRESSED) + UpperCase = true; + else + UpperCase = false; continue; } - case KEY_D_BACKSPACE: + case KEY_BACKSPACE: { + if (!(sc & KEY_PRESSED)) + continue; + if (BackspaceCount == 0) continue; @@ -215,8 +173,11 @@ void StartKernelShell() Display->SetBuffer(0); continue; } - case KEY_D_UP: + case KEY_UP_ARROW: { + if (!(sc & KEY_PRESSED)) + continue; + if (History.size() == 0 || HistoryIndex == 0) continue; @@ -235,8 +196,11 @@ void StartKernelShell() Display->SetBuffer(0); continue; } - case KEY_D_DOWN: + case KEY_DOWN_ARROW: { + if (!(sc & KEY_PRESSED)) + continue; + if (History.size() == 0 || HistoryIndex == History.size()) continue; @@ -265,8 +229,11 @@ void StartKernelShell() Display->SetBuffer(0); continue; } - case KEY_D_TAB: + case KEY_TAB: { + if (!(sc & KEY_PRESSED)) + continue; + if (!TabDoublePress) { TabDoublePress = true; @@ -276,10 +243,8 @@ void StartKernelShell() if (Buffer.size() == 0) { for (size_t i = 0; i < sizeof(commands) / sizeof(commands[0]); i++) - { printf("%s ", commands[i].Name); - Display->SetBuffer(0); - } + Display->Print('\n', 0); Display->SetBuffer(0); goto SecLoopEnd; @@ -307,9 +272,14 @@ void StartKernelShell() break; } - if (c == 0) + if (!(sc & KEY_PRESSED)) continue; + if (!Driver::IsValidChar(sc)) + continue; + + char c = Driver::GetScanCode(sc, UpperCase); + if (CtrlDown) { switch (std::toupper((char)c)) @@ -369,7 +339,7 @@ void StartKernelShell() cmd_extracted += Buffer[i]; } - debug("cmd: %s, array[%d]: %s", cmd_extracted.c_str(), i, commands[i].Name); + // debug("cmd: %s, array[%d]: %s", cmd_extracted.c_str(), i, commands[i].Name); if (strncmp(commands[i].Name, cmd_extracted.c_str(), cmd_extracted.size()) == 0) { if (strlen(commands[i].Name) != cmd_extracted.size()) diff --git a/library/convert.cpp b/library/convert.cpp index 9fd969b..afaf1d5 100644 --- a/library/convert.cpp +++ b/library/convert.cpp @@ -63,11 +63,23 @@ EXTERNC int strncmp(const char *s1, const char *s2, size_t n) EXTERNC long unsigned strlen(const char s[]) { - long unsigned i = 0; - if (s) - while (s[i] != '\0') - ++i; - return i; + if (Config.SIMD) + { + uint64_t simd = CPU::CheckSIMD(); + if (simd & CPU::x86SIMDType::SIMD_SSE42) + return strlen_sse4_2(s); + else if (simd & CPU::x86SIMDType::SIMD_SSE41) + return strlen_sse4_1(s); + else if (simd & CPU::x86SIMDType::SIMD_SSSE3) + return strlen_ssse3(s); + else if (simd & CPU::x86SIMDType::SIMD_SSE3) + return strlen_sse3(s); + else if (simd & CPU::x86SIMDType::SIMD_SSE2) + return strlen_sse2(s); + else if (simd & CPU::x86SIMDType::SIMD_SSE) + return strlen_sse(s); + } + return __strlen(s); } EXTERNC char *strcat_unsafe(char *destination, const char *source) @@ -128,6 +140,19 @@ EXTERNC int strcmp(const char *l, const char *r) return *(unsigned char *)l - *(unsigned char *)r; } +EXTERNC int strncasecmp(const char *string1, const char *string2, size_t count) +{ + int result = 0; + while (count--) + { + if ((result = std::tolower(*string1) - std::tolower(*string2)) != 0 || !*string1) + break; + string1++; + string2++; + } + return result; +} + EXTERNC char *strstr(const char *haystack, const char *needle) { const char *a = haystack, *b = needle; @@ -147,6 +172,8 @@ EXTERNC char *strstr(const char *haystack, const char *needle) EXTERNC char *strchr(const char *String, int Char) { + assert(String != NULL); + while (*String != (char)Char) { if (!*String++) @@ -774,7 +801,7 @@ EXTERNC __no_stack_protector void *__memcpy_chk(void *dest, const void *src, siz { error("dest is NULL (for %#lx %s)", __builtin_return_address(0), - KernelSymbolTable ? KernelSymbolTable->GetSymbolFromAddress((uintptr_t)__builtin_return_address(0)) + KernelSymbolTable ? KernelSymbolTable->GetSymbol((uintptr_t)__builtin_return_address(0)) : "Unknown"); __convert_chk_fail(); } @@ -783,7 +810,7 @@ EXTERNC __no_stack_protector void *__memcpy_chk(void *dest, const void *src, siz { error("src is NULL (for %#lx %s)", __builtin_return_address(0), - KernelSymbolTable ? KernelSymbolTable->GetSymbolFromAddress((uintptr_t)__builtin_return_address(0)) + KernelSymbolTable ? KernelSymbolTable->GetSymbol((uintptr_t)__builtin_return_address(0)) : "Unknown"); __convert_chk_fail(); } @@ -792,7 +819,7 @@ EXTERNC __no_stack_protector void *__memcpy_chk(void *dest, const void *src, siz { error("len is 0 (for %#lx %s)", __builtin_return_address(0), - KernelSymbolTable ? KernelSymbolTable->GetSymbolFromAddress((uintptr_t)__builtin_return_address(0)) + KernelSymbolTable ? KernelSymbolTable->GetSymbol((uintptr_t)__builtin_return_address(0)) : "Unknown"); __convert_chk_fail(); } @@ -801,7 +828,7 @@ EXTERNC __no_stack_protector void *__memcpy_chk(void *dest, const void *src, siz { error("slen is 0 (for %#lx %s)", __builtin_return_address(0), - KernelSymbolTable ? KernelSymbolTable->GetSymbolFromAddress((uintptr_t)__builtin_return_address(0)) + KernelSymbolTable ? KernelSymbolTable->GetSymbol((uintptr_t)__builtin_return_address(0)) : "Unknown"); __convert_chk_fail(); } @@ -810,7 +837,7 @@ EXTERNC __no_stack_protector void *__memcpy_chk(void *dest, const void *src, siz __chk_fail(); void *ret = nullptr; - if (0) /* FIXME */ + if (Config.SIMD) { uint64_t simd = CPU::CheckSIMD(); if (simd & CPU::x86SIMDType::SIMD_SSE42) @@ -847,7 +874,7 @@ EXTERNC __no_stack_protector void *__memset_chk(void *dest, int val, size_t len, { error("dest is NULL (for %#lx %s)", __builtin_return_address(0), - KernelSymbolTable ? KernelSymbolTable->GetSymbolFromAddress((uintptr_t)__builtin_return_address(0)) + KernelSymbolTable ? KernelSymbolTable->GetSymbol((uintptr_t)__builtin_return_address(0)) : "Unknown"); __convert_chk_fail(); } @@ -856,7 +883,7 @@ EXTERNC __no_stack_protector void *__memset_chk(void *dest, int val, size_t len, { error("len is 0 (for %#lx %s)", __builtin_return_address(0), - KernelSymbolTable ? KernelSymbolTable->GetSymbolFromAddress((uintptr_t)__builtin_return_address(0)) + KernelSymbolTable ? KernelSymbolTable->GetSymbol((uintptr_t)__builtin_return_address(0)) : "Unknown"); __convert_chk_fail(); } @@ -865,7 +892,7 @@ EXTERNC __no_stack_protector void *__memset_chk(void *dest, int val, size_t len, { error("slen is 0 (for %#lx %s)", __builtin_return_address(0), - KernelSymbolTable ? KernelSymbolTable->GetSymbolFromAddress((uintptr_t)__builtin_return_address(0)) + KernelSymbolTable ? KernelSymbolTable->GetSymbol((uintptr_t)__builtin_return_address(0)) : "Unknown"); __convert_chk_fail(); } @@ -874,7 +901,7 @@ EXTERNC __no_stack_protector void *__memset_chk(void *dest, int val, size_t len, __chk_fail(); void *ret = nullptr; - if (0) /* FIXME */ + if (Config.SIMD) { uint64_t simd = CPU::CheckSIMD(); if (simd & CPU::x86SIMDType::SIMD_SSE42) @@ -912,7 +939,7 @@ EXTERNC __no_stack_protector void *__memmove_chk(void *dest, const void *src, si { error("dest is NULL (for %#lx %s)", __builtin_return_address(0), - KernelSymbolTable ? KernelSymbolTable->GetSymbolFromAddress((uintptr_t)__builtin_return_address(0)) + KernelSymbolTable ? KernelSymbolTable->GetSymbol((uintptr_t)__builtin_return_address(0)) : "Unknown"); __convert_chk_fail(); } @@ -921,7 +948,7 @@ EXTERNC __no_stack_protector void *__memmove_chk(void *dest, const void *src, si { error("src is NULL (for %#lx %s)", __builtin_return_address(0), - KernelSymbolTable ? KernelSymbolTable->GetSymbolFromAddress((uintptr_t)__builtin_return_address(0)) + KernelSymbolTable ? KernelSymbolTable->GetSymbol((uintptr_t)__builtin_return_address(0)) : "Unknown"); __convert_chk_fail(); } @@ -930,7 +957,7 @@ EXTERNC __no_stack_protector void *__memmove_chk(void *dest, const void *src, si { error("len is 0 (for %#lx %s)", __builtin_return_address(0), - KernelSymbolTable ? KernelSymbolTable->GetSymbolFromAddress((uintptr_t)__builtin_return_address(0)) + KernelSymbolTable ? KernelSymbolTable->GetSymbol((uintptr_t)__builtin_return_address(0)) : "Unknown"); __convert_chk_fail(); } @@ -939,7 +966,7 @@ EXTERNC __no_stack_protector void *__memmove_chk(void *dest, const void *src, si { error("slen is 0 (for %#lx %s)", __builtin_return_address(0), - KernelSymbolTable ? KernelSymbolTable->GetSymbolFromAddress((uintptr_t)__builtin_return_address(0)) + KernelSymbolTable ? KernelSymbolTable->GetSymbol((uintptr_t)__builtin_return_address(0)) : "Unknown"); __convert_chk_fail(); } @@ -948,7 +975,7 @@ EXTERNC __no_stack_protector void *__memmove_chk(void *dest, const void *src, si __chk_fail(); void *ret = nullptr; - if (0) /* FIXME */ + if (Config.SIMD) { uint64_t simd = CPU::CheckSIMD(); if (simd & CPU::x86SIMDType::SIMD_SSE42) @@ -986,7 +1013,7 @@ EXTERNC __no_stack_protector char *__strcat_chk(char *dest, const char *src, siz { error("dest is NULL (for %#lx %s)", __builtin_return_address(0), - KernelSymbolTable ? KernelSymbolTable->GetSymbolFromAddress((uintptr_t)__builtin_return_address(0)) + KernelSymbolTable ? KernelSymbolTable->GetSymbol((uintptr_t)__builtin_return_address(0)) : "Unknown"); __convert_chk_fail(); } @@ -995,7 +1022,7 @@ EXTERNC __no_stack_protector char *__strcat_chk(char *dest, const char *src, siz { error("src is NULL (for %#lx %s)", __builtin_return_address(0), - KernelSymbolTable ? KernelSymbolTable->GetSymbolFromAddress((uintptr_t)__builtin_return_address(0)) + KernelSymbolTable ? KernelSymbolTable->GetSymbol((uintptr_t)__builtin_return_address(0)) : "Unknown"); __convert_chk_fail(); } @@ -1004,7 +1031,7 @@ EXTERNC __no_stack_protector char *__strcat_chk(char *dest, const char *src, siz { error("slen is 0 (for %#lx %s)", __builtin_return_address(0), - KernelSymbolTable ? KernelSymbolTable->GetSymbolFromAddress((uintptr_t)__builtin_return_address(0)) + KernelSymbolTable ? KernelSymbolTable->GetSymbol((uintptr_t)__builtin_return_address(0)) : "Unknown"); __convert_chk_fail(); } @@ -1025,7 +1052,7 @@ EXTERNC __no_stack_protector char *__strcpy_chk(char *dest, const char *src, siz { error("dest is NULL (for %#lx %s)", __builtin_return_address(0), - KernelSymbolTable ? KernelSymbolTable->GetSymbolFromAddress((uintptr_t)__builtin_return_address(0)) + KernelSymbolTable ? KernelSymbolTable->GetSymbol((uintptr_t)__builtin_return_address(0)) : "Unknown"); __convert_chk_fail(); } @@ -1034,7 +1061,7 @@ EXTERNC __no_stack_protector char *__strcpy_chk(char *dest, const char *src, siz { error("src is NULL (for %#lx %s)", __builtin_return_address(0), - KernelSymbolTable ? KernelSymbolTable->GetSymbolFromAddress((uintptr_t)__builtin_return_address(0)) + KernelSymbolTable ? KernelSymbolTable->GetSymbol((uintptr_t)__builtin_return_address(0)) : "Unknown"); __convert_chk_fail(); } @@ -1043,7 +1070,7 @@ EXTERNC __no_stack_protector char *__strcpy_chk(char *dest, const char *src, siz { error("slen is 0 (for %#lx %s)", __builtin_return_address(0), - KernelSymbolTable ? KernelSymbolTable->GetSymbolFromAddress((uintptr_t)__builtin_return_address(0)) + KernelSymbolTable ? KernelSymbolTable->GetSymbol((uintptr_t)__builtin_return_address(0)) : "Unknown"); __convert_chk_fail(); } diff --git a/library/crc32.c b/library/crc32.c index 1ca4821..ba1e4a3 100644 --- a/library/crc32.c +++ b/library/crc32.c @@ -18,79 +18,79 @@ #include uint32_t LookupTable[256] = - { - 0x00000000, 0x04c11db7, 0x09823b6e, 0x0d4326d9, - 0x130476dc, 0x17c56b6b, 0x1a864db2, 0x1e475005, - 0x2608edb8, 0x22c9f00f, 0x2f8ad6d6, 0x2b4bcb61, - 0x350c9b64, 0x31cd86d3, 0x3c8ea00a, 0x384fbdbd, - 0x4c11db70, 0x48d0c6c7, 0x4593e01e, 0x4152fda9, - 0x5f15adac, 0x5bd4b01b, 0x569796c2, 0x52568b75, - 0x6a1936c8, 0x6ed82b7f, 0x639b0da6, 0x675a1011, - 0x791d4014, 0x7ddc5da3, 0x709f7b7a, 0x745e66cd, - 0x9823b6e0, 0x9ce2ab57, 0x91a18d8e, 0x95609039, - 0x8b27c03c, 0x8fe6dd8b, 0x82a5fb52, 0x8664e6e5, - 0xbe2b5b58, 0xbaea46ef, 0xb7a96036, 0xb3687d81, - 0xad2f2d84, 0xa9ee3033, 0xa4ad16ea, 0xa06c0b5d, - 0xd4326d90, 0xd0f37027, 0xddb056fe, 0xd9714b49, - 0xc7361b4c, 0xc3f706fb, 0xceb42022, 0xca753d95, - 0xf23a8028, 0xf6fb9d9f, 0xfbb8bb46, 0xff79a6f1, - 0xe13ef6f4, 0xe5ffeb43, 0xe8bccd9a, 0xec7dd02d, - 0x34867077, 0x30476dc0, 0x3d044b19, 0x39c556ae, - 0x278206ab, 0x23431b1c, 0x2e003dc5, 0x2ac12072, - 0x128e9dcf, 0x164f8078, 0x1b0ca6a1, 0x1fcdbb16, - 0x018aeb13, 0x054bf6a4, 0x0808d07d, 0x0cc9cdca, - 0x7897ab07, 0x7c56b6b0, 0x71159069, 0x75d48dde, - 0x6b93dddb, 0x6f52c06c, 0x6211e6b5, 0x66d0fb02, - 0x5e9f46bf, 0x5a5e5b08, 0x571d7dd1, 0x53dc6066, - 0x4d9b3063, 0x495a2dd4, 0x44190b0d, 0x40d816ba, - 0xaca5c697, 0xa864db20, 0xa527fdf9, 0xa1e6e04e, - 0xbfa1b04b, 0xbb60adfc, 0xb6238b25, 0xb2e29692, - 0x8aad2b2f, 0x8e6c3698, 0x832f1041, 0x87ee0df6, - 0x99a95df3, 0x9d684044, 0x902b669d, 0x94ea7b2a, - 0xe0b41de7, 0xe4750050, 0xe9362689, 0xedf73b3e, - 0xf3b06b3b, 0xf771768c, 0xfa325055, 0xfef34de2, - 0xc6bcf05f, 0xc27dede8, 0xcf3ecb31, 0xcbffd686, - 0xd5b88683, 0xd1799b34, 0xdc3abded, 0xd8fba05a, - 0x690ce0ee, 0x6dcdfd59, 0x608edb80, 0x644fc637, - 0x7a089632, 0x7ec98b85, 0x738aad5c, 0x774bb0eb, - 0x4f040d56, 0x4bc510e1, 0x46863638, 0x42472b8f, - 0x5c007b8a, 0x58c1663d, 0x558240e4, 0x51435d53, - 0x251d3b9e, 0x21dc2629, 0x2c9f00f0, 0x285e1d47, - 0x36194d42, 0x32d850f5, 0x3f9b762c, 0x3b5a6b9b, - 0x0315d626, 0x07d4cb91, 0x0a97ed48, 0x0e56f0ff, - 0x1011a0fa, 0x14d0bd4d, 0x19939b94, 0x1d528623, - 0xf12f560e, 0xf5ee4bb9, 0xf8ad6d60, 0xfc6c70d7, - 0xe22b20d2, 0xe6ea3d65, 0xeba91bbc, 0xef68060b, - 0xd727bbb6, 0xd3e6a601, 0xdea580d8, 0xda649d6f, - 0xc423cd6a, 0xc0e2d0dd, 0xcda1f604, 0xc960ebb3, - 0xbd3e8d7e, 0xb9ff90c9, 0xb4bcb610, 0xb07daba7, - 0xae3afba2, 0xaafbe615, 0xa7b8c0cc, 0xa379dd7b, - 0x9b3660c6, 0x9ff77d71, 0x92b45ba8, 0x9675461f, - 0x8832161a, 0x8cf30bad, 0x81b02d74, 0x857130c3, - 0x5d8a9099, 0x594b8d2e, 0x5408abf7, 0x50c9b640, - 0x4e8ee645, 0x4a4ffbf2, 0x470cdd2b, 0x43cdc09c, - 0x7b827d21, 0x7f436096, 0x7200464f, 0x76c15bf8, - 0x68860bfd, 0x6c47164a, 0x61043093, 0x65c52d24, - 0x119b4be9, 0x155a565e, 0x18197087, 0x1cd86d30, - 0x029f3d35, 0x065e2082, 0x0b1d065b, 0x0fdc1bec, - 0x3793a651, 0x3352bbe6, 0x3e119d3f, 0x3ad08088, - 0x2497d08d, 0x2056cd3a, 0x2d15ebe3, 0x29d4f654, - 0xc5a92679, 0xc1683bce, 0xcc2b1d17, 0xc8ea00a0, - 0xd6ad50a5, 0xd26c4d12, 0xdf2f6bcb, 0xdbee767c, - 0xe3a1cbc1, 0xe760d676, 0xea23f0af, 0xeee2ed18, - 0xf0a5bd1d, 0xf464a0aa, 0xf9278673, 0xfde69bc4, - 0x89b8fd09, 0x8d79e0be, 0x803ac667, 0x84fbdbd0, - 0x9abc8bd5, 0x9e7d9662, 0x933eb0bb, 0x97ffad0c, - 0xafb010b1, 0xab710d06, 0xa6322bdf, 0xa2f33668, - 0xbcb4666d, 0xb8757bda, 0xb5365d03, 0xb1f740b4}; + { + 0x00000000, 0x04c11db7, 0x09823b6e, 0x0d4326d9, + 0x130476dc, 0x17c56b6b, 0x1a864db2, 0x1e475005, + 0x2608edb8, 0x22c9f00f, 0x2f8ad6d6, 0x2b4bcb61, + 0x350c9b64, 0x31cd86d3, 0x3c8ea00a, 0x384fbdbd, + 0x4c11db70, 0x48d0c6c7, 0x4593e01e, 0x4152fda9, + 0x5f15adac, 0x5bd4b01b, 0x569796c2, 0x52568b75, + 0x6a1936c8, 0x6ed82b7f, 0x639b0da6, 0x675a1011, + 0x791d4014, 0x7ddc5da3, 0x709f7b7a, 0x745e66cd, + 0x9823b6e0, 0x9ce2ab57, 0x91a18d8e, 0x95609039, + 0x8b27c03c, 0x8fe6dd8b, 0x82a5fb52, 0x8664e6e5, + 0xbe2b5b58, 0xbaea46ef, 0xb7a96036, 0xb3687d81, + 0xad2f2d84, 0xa9ee3033, 0xa4ad16ea, 0xa06c0b5d, + 0xd4326d90, 0xd0f37027, 0xddb056fe, 0xd9714b49, + 0xc7361b4c, 0xc3f706fb, 0xceb42022, 0xca753d95, + 0xf23a8028, 0xf6fb9d9f, 0xfbb8bb46, 0xff79a6f1, + 0xe13ef6f4, 0xe5ffeb43, 0xe8bccd9a, 0xec7dd02d, + 0x34867077, 0x30476dc0, 0x3d044b19, 0x39c556ae, + 0x278206ab, 0x23431b1c, 0x2e003dc5, 0x2ac12072, + 0x128e9dcf, 0x164f8078, 0x1b0ca6a1, 0x1fcdbb16, + 0x018aeb13, 0x054bf6a4, 0x0808d07d, 0x0cc9cdca, + 0x7897ab07, 0x7c56b6b0, 0x71159069, 0x75d48dde, + 0x6b93dddb, 0x6f52c06c, 0x6211e6b5, 0x66d0fb02, + 0x5e9f46bf, 0x5a5e5b08, 0x571d7dd1, 0x53dc6066, + 0x4d9b3063, 0x495a2dd4, 0x44190b0d, 0x40d816ba, + 0xaca5c697, 0xa864db20, 0xa527fdf9, 0xa1e6e04e, + 0xbfa1b04b, 0xbb60adfc, 0xb6238b25, 0xb2e29692, + 0x8aad2b2f, 0x8e6c3698, 0x832f1041, 0x87ee0df6, + 0x99a95df3, 0x9d684044, 0x902b669d, 0x94ea7b2a, + 0xe0b41de7, 0xe4750050, 0xe9362689, 0xedf73b3e, + 0xf3b06b3b, 0xf771768c, 0xfa325055, 0xfef34de2, + 0xc6bcf05f, 0xc27dede8, 0xcf3ecb31, 0xcbffd686, + 0xd5b88683, 0xd1799b34, 0xdc3abded, 0xd8fba05a, + 0x690ce0ee, 0x6dcdfd59, 0x608edb80, 0x644fc637, + 0x7a089632, 0x7ec98b85, 0x738aad5c, 0x774bb0eb, + 0x4f040d56, 0x4bc510e1, 0x46863638, 0x42472b8f, + 0x5c007b8a, 0x58c1663d, 0x558240e4, 0x51435d53, + 0x251d3b9e, 0x21dc2629, 0x2c9f00f0, 0x285e1d47, + 0x36194d42, 0x32d850f5, 0x3f9b762c, 0x3b5a6b9b, + 0x0315d626, 0x07d4cb91, 0x0a97ed48, 0x0e56f0ff, + 0x1011a0fa, 0x14d0bd4d, 0x19939b94, 0x1d528623, + 0xf12f560e, 0xf5ee4bb9, 0xf8ad6d60, 0xfc6c70d7, + 0xe22b20d2, 0xe6ea3d65, 0xeba91bbc, 0xef68060b, + 0xd727bbb6, 0xd3e6a601, 0xdea580d8, 0xda649d6f, + 0xc423cd6a, 0xc0e2d0dd, 0xcda1f604, 0xc960ebb3, + 0xbd3e8d7e, 0xb9ff90c9, 0xb4bcb610, 0xb07daba7, + 0xae3afba2, 0xaafbe615, 0xa7b8c0cc, 0xa379dd7b, + 0x9b3660c6, 0x9ff77d71, 0x92b45ba8, 0x9675461f, + 0x8832161a, 0x8cf30bad, 0x81b02d74, 0x857130c3, + 0x5d8a9099, 0x594b8d2e, 0x5408abf7, 0x50c9b640, + 0x4e8ee645, 0x4a4ffbf2, 0x470cdd2b, 0x43cdc09c, + 0x7b827d21, 0x7f436096, 0x7200464f, 0x76c15bf8, + 0x68860bfd, 0x6c47164a, 0x61043093, 0x65c52d24, + 0x119b4be9, 0x155a565e, 0x18197087, 0x1cd86d30, + 0x029f3d35, 0x065e2082, 0x0b1d065b, 0x0fdc1bec, + 0x3793a651, 0x3352bbe6, 0x3e119d3f, 0x3ad08088, + 0x2497d08d, 0x2056cd3a, 0x2d15ebe3, 0x29d4f654, + 0xc5a92679, 0xc1683bce, 0xcc2b1d17, 0xc8ea00a0, + 0xd6ad50a5, 0xd26c4d12, 0xdf2f6bcb, 0xdbee767c, + 0xe3a1cbc1, 0xe760d676, 0xea23f0af, 0xeee2ed18, + 0xf0a5bd1d, 0xf464a0aa, 0xf9278673, 0xfde69bc4, + 0x89b8fd09, 0x8d79e0be, 0x803ac667, 0x84fbdbd0, + 0x9abc8bd5, 0x9e7d9662, 0x933eb0bb, 0x97ffad0c, + 0xafb010b1, 0xab710d06, 0xa6322bdf, 0xa2f33668, + 0xbcb4666d, 0xb8757bda, 0xb5365d03, 0xb1f740b4}; uint32_t crc32(const uint8_t *Buffer, int Length) { - uint32_t ret = 0xffffffff; - while (Length--) - { - ret = (ret << 8) ^ LookupTable[((ret >> 24) ^ *Buffer) & 255]; - Buffer++; - } - return ret; + uint32_t ret = 0xffffffff; + while (Length--) + { + ret = (ret << 8) ^ LookupTable[((ret >> 24) ^ *Buffer) & 255]; + Buffer++; + } + return ret; } diff --git a/library/dumper.cpp b/library/dumper.cpp index 643e388..c492677 100644 --- a/library/dumper.cpp +++ b/library/dumper.cpp @@ -27,65 +27,59 @@ NewLock(DumperLock); using namespace UniversalAsynchronousReceiverTransmitter; -static inline void print_wrapper(char c, void *unused) -{ - UART(COM1).Write(c); - UNUSED(unused); -} - -int vprintf_dumper(const char *format, va_list list) { return vfctprintf(print_wrapper, NULL, format, list); } +int vprintf_dumper(const char *format, va_list list) { return vfctprintf(uart_wrapper, NULL, format, list); } void WriteRaw(const char *format, ...) { - va_list args; - va_start(args, format); - vprintf_dumper(format, args); - va_end(args); + va_list args; + va_start(args, format); + vprintf_dumper(format, args); + va_end(args); } void DumpData(const char *Description, void *Address, unsigned long Length) { - SmartLock(DumperLock); - WriteRaw("-------------------------------------------------------------------------\n"); - unsigned char *AddressChar = (unsigned char *)Address; - unsigned char Buffer[17]; - unsigned long Iterate; + SmartLock(DumperLock); + WriteRaw("-------------------------------------------------------------------------\n"); + unsigned char *AddressChar = (unsigned char *)Address; + unsigned char Buffer[17]; + unsigned long Iterate; - if (Description != nullptr) - WriteRaw("%s:\n", Description); + if (Description != nullptr) + WriteRaw("%s (%d bytes):\n", Description, Length); - for (Iterate = 0; Iterate < Length; Iterate++) - { - if ((Iterate % 16) == 0) - { - if (Iterate != 0) - WriteRaw(" %s\n", Buffer); - WriteRaw(" %04x ", Iterate); - } + for (Iterate = 0; Iterate < Length; Iterate++) + { + if ((Iterate % 16) == 0) + { + if (Iterate != 0) + WriteRaw(" %s\n", Buffer); + WriteRaw(" %04x ", Iterate); + } - WriteRaw(" %02x", AddressChar[Iterate]); + WriteRaw(" %02x", AddressChar[Iterate]); - if ((AddressChar[Iterate] < 0x20) || (AddressChar[Iterate] > 0x7e)) - Buffer[Iterate % 16] = '.'; - else - Buffer[Iterate % 16] = AddressChar[Iterate]; + if ((AddressChar[Iterate] < 0x20) || (AddressChar[Iterate] > 0x7e)) + Buffer[Iterate % 16] = '.'; + else + Buffer[Iterate % 16] = AddressChar[Iterate]; - Buffer[(Iterate % 16) + 1] = '\0'; - } + Buffer[(Iterate % 16) + 1] = '\0'; + } - while ((Iterate % 16) != 0) - { - WriteRaw(" "); - Iterate++; - } + while ((Iterate % 16) != 0) + { + WriteRaw(" "); + Iterate++; + } - WriteRaw(" %s\n", Buffer); - WriteRaw("-------------------------------------------------------------------------\n"); - WriteRaw("Length: %ld bytes\n", Length); - uint8_t *result = md5File(AddressChar, Length); - WriteRaw("MD5: "); - for (int i = 0; i < 16; i++) - WriteRaw("%02x", result[i]); - kfree(result); - WriteRaw("\n-------------------------------------------------------------------------\n"); + WriteRaw(" %s\n", Buffer); + WriteRaw("-------------------------------------------------------------------------\n"); + WriteRaw("Length: %ld bytes\n", Length); + uint8_t *result = md5File(AddressChar, Length); + WriteRaw("MD5: "); + for (int i = 0; i < 16; i++) + WriteRaw("%02x", result[i]); + kfree(result); + WriteRaw("\n-------------------------------------------------------------------------\n"); } diff --git a/library/libstdc++/cxxabi.cpp b/library/libstdc++/cxxabi.cpp index 1417da5..dbe5f49 100644 --- a/library/libstdc++/cxxabi.cpp +++ b/library/libstdc++/cxxabi.cpp @@ -48,8 +48,8 @@ namespace __cxxabiv1 if (KernelSymbolTable) { debug("Registering atexit function for \"%s\" with destructor \"%s\"", - KernelSymbolTable->GetSymbolFromAddress((uintptr_t)objptr), - KernelSymbolTable->GetSymbolFromAddress((uintptr_t)f)); + KernelSymbolTable->GetSymbol((uintptr_t)objptr), + KernelSymbolTable->GetSymbol((uintptr_t)f)); } else { @@ -79,7 +79,7 @@ namespace __cxxabiv1 if (KernelSymbolTable) { debug("Calling atexit function \"%s\"", - KernelSymbolTable->GetSymbolFromAddress((uintptr_t)__atexit_funcs[i].destructor_func)); + KernelSymbolTable->GetSymbol((uintptr_t)__atexit_funcs[i].destructor_func)); } else { diff --git a/library/memop.c b/library/memop.c index c840c00..cf01551 100644 --- a/library/memop.c +++ b/library/memop.c @@ -34,8 +34,8 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. void *memcpy_unsafe(void *dest, const void *src, size_t n) { - unsigned char *d = dest; - const unsigned char *s = src; + unsigned char *d = dest; + const unsigned char *s = src; #ifdef __GNUC__ @@ -47,305 +47,305 @@ void *memcpy_unsafe(void *dest, const void *src, size_t n) #define RS >> #endif - typedef uint32_t __attribute__((__may_alias__)) u32; - uint32_t w, x; + typedef uint32_t __attribute__((__may_alias__)) u32; + uint32_t w, x; - for (; (uintptr_t)s % 4 && n; n--) - *d++ = *s++; + for (; (uintptr_t)s % 4 && n; n--) + *d++ = *s++; - if ((uintptr_t)d % 4 == 0) - { - for (; n >= 16; s += 16, d += 16, n -= 16) - { - *(u32 *)(d + 0) = *(u32 *)(s + 0); - *(u32 *)(d + 4) = *(u32 *)(s + 4); - *(u32 *)(d + 8) = *(u32 *)(s + 8); - *(u32 *)(d + 12) = *(u32 *)(s + 12); - } - if (n & 8) - { - *(u32 *)(d + 0) = *(u32 *)(s + 0); - *(u32 *)(d + 4) = *(u32 *)(s + 4); - d += 8; - s += 8; - } - if (n & 4) - { - *(u32 *)(d + 0) = *(u32 *)(s + 0); - d += 4; - s += 4; - } - if (n & 2) - { - *d++ = *s++; - *d++ = *s++; - } - if (n & 1) - { - *d = *s; - } - return dest; - } + if ((uintptr_t)d % 4 == 0) + { + for (; n >= 16; s += 16, d += 16, n -= 16) + { + *(u32 *)(d + 0) = *(u32 *)(s + 0); + *(u32 *)(d + 4) = *(u32 *)(s + 4); + *(u32 *)(d + 8) = *(u32 *)(s + 8); + *(u32 *)(d + 12) = *(u32 *)(s + 12); + } + if (n & 8) + { + *(u32 *)(d + 0) = *(u32 *)(s + 0); + *(u32 *)(d + 4) = *(u32 *)(s + 4); + d += 8; + s += 8; + } + if (n & 4) + { + *(u32 *)(d + 0) = *(u32 *)(s + 0); + d += 4; + s += 4; + } + if (n & 2) + { + *d++ = *s++; + *d++ = *s++; + } + if (n & 1) + { + *d = *s; + } + return dest; + } - if (n >= 32) - { - switch ((uintptr_t)d % 4) - { - case 1: - { - w = *(u32 *)s; - *d++ = *s++; - *d++ = *s++; - *d++ = *s++; - n -= 3; - for (; n >= 17; s += 16, d += 16, n -= 16) - { - x = *(u32 *)(s + 1); - *(u32 *)(d + 0) = (w LS 24) | (x RS 8); - w = *(u32 *)(s + 5); - *(u32 *)(d + 4) = (x LS 24) | (w RS 8); - x = *(u32 *)(s + 9); - *(u32 *)(d + 8) = (w LS 24) | (x RS 8); - w = *(u32 *)(s + 13); - *(u32 *)(d + 12) = (x LS 24) | (w RS 8); - } - break; - } - case 2: - { - w = *(u32 *)s; - *d++ = *s++; - *d++ = *s++; - n -= 2; - for (; n >= 18; s += 16, d += 16, n -= 16) - { - x = *(u32 *)(s + 2); - *(u32 *)(d + 0) = (w LS 16) | (x RS 16); - w = *(u32 *)(s + 6); - *(u32 *)(d + 4) = (x LS 16) | (w RS 16); - x = *(u32 *)(s + 10); - *(u32 *)(d + 8) = (w LS 16) | (x RS 16); - w = *(u32 *)(s + 14); - *(u32 *)(d + 12) = (x LS 16) | (w RS 16); - } - break; - } - case 3: - { - w = *(u32 *)s; - *d++ = *s++; - n -= 1; - for (; n >= 19; s += 16, d += 16, n -= 16) - { - x = *(u32 *)(s + 3); - *(u32 *)(d + 0) = (w LS 8) | (x RS 24); - w = *(u32 *)(s + 7); - *(u32 *)(d + 4) = (x LS 8) | (w RS 24); - x = *(u32 *)(s + 11); - *(u32 *)(d + 8) = (w LS 8) | (x RS 24); - w = *(u32 *)(s + 15); - *(u32 *)(d + 12) = (x LS 8) | (w RS 24); - } - break; - } - default: - break; - } - } + if (n >= 32) + { + switch ((uintptr_t)d % 4) + { + case 1: + { + w = *(u32 *)s; + *d++ = *s++; + *d++ = *s++; + *d++ = *s++; + n -= 3; + for (; n >= 17; s += 16, d += 16, n -= 16) + { + x = *(u32 *)(s + 1); + *(u32 *)(d + 0) = (w LS 24) | (x RS 8); + w = *(u32 *)(s + 5); + *(u32 *)(d + 4) = (x LS 24) | (w RS 8); + x = *(u32 *)(s + 9); + *(u32 *)(d + 8) = (w LS 24) | (x RS 8); + w = *(u32 *)(s + 13); + *(u32 *)(d + 12) = (x LS 24) | (w RS 8); + } + break; + } + case 2: + { + w = *(u32 *)s; + *d++ = *s++; + *d++ = *s++; + n -= 2; + for (; n >= 18; s += 16, d += 16, n -= 16) + { + x = *(u32 *)(s + 2); + *(u32 *)(d + 0) = (w LS 16) | (x RS 16); + w = *(u32 *)(s + 6); + *(u32 *)(d + 4) = (x LS 16) | (w RS 16); + x = *(u32 *)(s + 10); + *(u32 *)(d + 8) = (w LS 16) | (x RS 16); + w = *(u32 *)(s + 14); + *(u32 *)(d + 12) = (x LS 16) | (w RS 16); + } + break; + } + case 3: + { + w = *(u32 *)s; + *d++ = *s++; + n -= 1; + for (; n >= 19; s += 16, d += 16, n -= 16) + { + x = *(u32 *)(s + 3); + *(u32 *)(d + 0) = (w LS 8) | (x RS 24); + w = *(u32 *)(s + 7); + *(u32 *)(d + 4) = (x LS 8) | (w RS 24); + x = *(u32 *)(s + 11); + *(u32 *)(d + 8) = (w LS 8) | (x RS 24); + w = *(u32 *)(s + 15); + *(u32 *)(d + 12) = (x LS 8) | (w RS 24); + } + break; + } + default: + break; + } + } - if (n & 16) - { - *d++ = *s++; - *d++ = *s++; - *d++ = *s++; - *d++ = *s++; - *d++ = *s++; - *d++ = *s++; - *d++ = *s++; - *d++ = *s++; - *d++ = *s++; - *d++ = *s++; - *d++ = *s++; - *d++ = *s++; - *d++ = *s++; - *d++ = *s++; - *d++ = *s++; - *d++ = *s++; - } + if (n & 16) + { + *d++ = *s++; + *d++ = *s++; + *d++ = *s++; + *d++ = *s++; + *d++ = *s++; + *d++ = *s++; + *d++ = *s++; + *d++ = *s++; + *d++ = *s++; + *d++ = *s++; + *d++ = *s++; + *d++ = *s++; + *d++ = *s++; + *d++ = *s++; + *d++ = *s++; + *d++ = *s++; + } - if (n & 8) - { - *d++ = *s++; - *d++ = *s++; - *d++ = *s++; - *d++ = *s++; - *d++ = *s++; - *d++ = *s++; - *d++ = *s++; - *d++ = *s++; - } + if (n & 8) + { + *d++ = *s++; + *d++ = *s++; + *d++ = *s++; + *d++ = *s++; + *d++ = *s++; + *d++ = *s++; + *d++ = *s++; + *d++ = *s++; + } - if (n & 4) - { - *d++ = *s++; - *d++ = *s++; - *d++ = *s++; - *d++ = *s++; - } + if (n & 4) + { + *d++ = *s++; + *d++ = *s++; + *d++ = *s++; + *d++ = *s++; + } - if (n & 2) - { - *d++ = *s++; - *d++ = *s++; - } + if (n & 2) + { + *d++ = *s++; + *d++ = *s++; + } - if (n & 1) - { - *d = *s; - } - return dest; + if (n & 1) + { + *d = *s; + } + return dest; #endif - for (; n; n--) - *d++ = *s++; - return dest; + for (; n; n--) + *d++ = *s++; + return dest; } void *memset_unsafe(void *dest, int c, size_t n) { - unsigned char *s = dest; - size_t k; + unsigned char *s = dest; + size_t k; - if (!n) - return dest; + if (!n) + return dest; - s[0] = c; - s[n - 1] = c; + s[0] = c; + s[n - 1] = c; - if (n <= 2) - return dest; + if (n <= 2) + return dest; - s[1] = c; - s[2] = c; - s[n - 2] = c; - s[n - 3] = c; + s[1] = c; + s[2] = c; + s[n - 2] = c; + s[n - 3] = c; - if (n <= 6) - return dest; + if (n <= 6) + return dest; - s[3] = c; - s[n - 4] = c; + s[3] = c; + s[n - 4] = c; - if (n <= 8) - return dest; + if (n <= 8) + return dest; - k = -(uintptr_t)s & 3; - s += k; - n -= k; - n &= -4; + k = -(uintptr_t)s & 3; + s += k; + n -= k; + n &= -4; #ifdef __GNUC__ - typedef uint32_t __attribute__((__may_alias__)) u32; - typedef uint64_t __attribute__((__may_alias__)) u64; + typedef uint32_t __attribute__((__may_alias__)) u32; + typedef uint64_t __attribute__((__may_alias__)) u64; - u32 c32 = ((u32)-1) / 255 * (unsigned char)c; - *(u32 *)(s + 0) = c32; - *(u32 *)(s + n - 4) = c32; + u32 c32 = ((u32)-1) / 255 * (unsigned char)c; + *(u32 *)(s + 0) = c32; + *(u32 *)(s + n - 4) = c32; - if (n <= 8) - return dest; + if (n <= 8) + return dest; - *(u32 *)(s + 4) = c32; - *(u32 *)(s + 8) = c32; - *(u32 *)(s + n - 12) = c32; - *(u32 *)(s + n - 8) = c32; + *(u32 *)(s + 4) = c32; + *(u32 *)(s + 8) = c32; + *(u32 *)(s + n - 12) = c32; + *(u32 *)(s + n - 8) = c32; - if (n <= 24) - return dest; + if (n <= 24) + return dest; - *(u32 *)(s + 12) = c32; - *(u32 *)(s + 16) = c32; - *(u32 *)(s + 20) = c32; - *(u32 *)(s + 24) = c32; - *(u32 *)(s + n - 28) = c32; - *(u32 *)(s + n - 24) = c32; - *(u32 *)(s + n - 20) = c32; - *(u32 *)(s + n - 16) = c32; + *(u32 *)(s + 12) = c32; + *(u32 *)(s + 16) = c32; + *(u32 *)(s + 20) = c32; + *(u32 *)(s + 24) = c32; + *(u32 *)(s + n - 28) = c32; + *(u32 *)(s + n - 24) = c32; + *(u32 *)(s + n - 20) = c32; + *(u32 *)(s + n - 16) = c32; - k = 24 + ((uintptr_t)s & 4); - s += k; - n -= k; + k = 24 + ((uintptr_t)s & 4); + s += k; + n -= k; - u64 c64 = c32 | ((u64)c32 << 32); - for (; n >= 32; n -= 32, s += 32) - { - *(u64 *)(s + 0) = c64; - *(u64 *)(s + 8) = c64; - *(u64 *)(s + 16) = c64; - *(u64 *)(s + 24) = c64; - } + u64 c64 = c32 | ((u64)c32 << 32); + for (; n >= 32; n -= 32, s += 32) + { + *(u64 *)(s + 0) = c64; + *(u64 *)(s + 8) = c64; + *(u64 *)(s + 16) = c64; + *(u64 *)(s + 24) = c64; + } #else - for (; n; n--, s++) - *s = c; + for (; n; n--, s++) + *s = c; #endif - return dest; + return dest; } void *memmove_unsafe(void *dest, const void *src, size_t n) { #ifdef __GNUC__ - typedef __attribute__((__may_alias__)) size_t WT; + typedef __attribute__((__may_alias__)) size_t WT; #define WS (sizeof(WT)) #endif - char *d = dest; - const char *s = src; + char *d = dest; + const char *s = src; - if (d == s) - return d; + if (d == s) + return d; - if ((uintptr_t)s - (uintptr_t)d - n <= -2 * n) - return memcpy(d, s, n); + if ((uintptr_t)s - (uintptr_t)d - n <= -2 * n) + return memcpy(d, s, n); - if (d < s) - { + if (d < s) + { #ifdef __GNUC__ - if ((uintptr_t)s % WS == (uintptr_t)d % WS) - { - while ((uintptr_t)d % WS) - { - if (!n--) - return dest; + if ((uintptr_t)s % WS == (uintptr_t)d % WS) + { + while ((uintptr_t)d % WS) + { + if (!n--) + return dest; - *d++ = *s++; - } - for (; n >= WS; n -= WS, d += WS, s += WS) - *(WT *)d = *(WT *)s; - } + *d++ = *s++; + } + for (; n >= WS; n -= WS, d += WS, s += WS) + *(WT *)d = *(WT *)s; + } #endif - for (; n; n--) - *d++ = *s++; - } - else - { + for (; n; n--) + *d++ = *s++; + } + else + { #ifdef __GNUC__ - if ((uintptr_t)s % WS == (uintptr_t)d % WS) - { - while ((uintptr_t)(d + n) % WS) - { - if (!n--) - return dest; + if ((uintptr_t)s % WS == (uintptr_t)d % WS) + { + while ((uintptr_t)(d + n) % WS) + { + if (!n--) + return dest; - d[n] = s[n]; - } - while (n >= WS) - n -= WS, *(WT *)(d + n) = *(WT *)(s + n); - } + d[n] = s[n]; + } + while (n >= WS) + n -= WS, *(WT *)(d + n) = *(WT *)(s + n); + } #endif - while (n) - n--, d[n] = s[n]; - } + while (n) + n--, d[n] = s[n]; + } - return dest; + return dest; } diff --git a/library/simd_memcpy.cpp b/library/simd_memcpy.cpp index af04039..35f8447 100644 --- a/library/simd_memcpy.cpp +++ b/library/simd_memcpy.cpp @@ -24,172 +24,257 @@ /* TODO: Replace these functions with even more optimized versions. - The current versions are fast but not as fast as they could be and also we need implementation for avx, not only sse. + The current versions are fast but not as fast as they could be and also we need implementation for avx, not only sse. */ EXTERNC void *memcpy_sse(void *dest, const void *src, size_t n) { #if defined(a64) - char *d = (char *)dest; - const char *s = (const char *)src; + char *d = (char *)dest; + const char *s = (const char *)src; - if ((((uintptr_t)d | (uintptr_t)s) & 0xF) == 0) - { - size_t num_vectors = n / 16; - for (size_t i = 0; i < num_vectors; i++) - { - asmv("movaps (%0), %%xmm0\n" - "movaps %%xmm0, (%1)\n" - : - : "r"(s), "r"(d) - : "xmm0"); - d += 16; - s += 16; - } - n -= num_vectors * 16; - } + if ((((uintptr_t)d | (uintptr_t)s) & 0xF) == 0) + { + size_t num_vectors = n / 16; + for (size_t i = 0; i < num_vectors; i++) + { + asmv("movaps (%0), %%xmm0\n" + "movaps %%xmm0, (%1)\n" + : + : "r"(s), "r"(d) + : "xmm0"); + d += 16; + s += 16; + } + n -= num_vectors * 16; + } + else + { + size_t num_vectors = n / 16; + for (size_t i = 0; i < num_vectors; i++) + { + asmv("movups (%0), %%xmm0\n" + "movups %%xmm0, (%1)\n" + : + : "r"(s), "r"(d) + : "xmm0"); + d += 16; + s += 16; + } + n -= num_vectors * 16; + } - memcpy_unsafe(d, s, n); + memcpy_unsafe(d, s, n); #endif // defined(a64) - return dest; + return dest; } EXTERNC void *memcpy_sse2(void *dest, const void *src, size_t n) { #if defined(a64) - char *d = (char *)dest; - const char *s = (const char *)src; + char *d = (char *)dest; + const char *s = (const char *)src; - if ((((uintptr_t)d | (uintptr_t)s) & 0xF) == 0) - { - size_t num_vectors = n / 16; - for (size_t i = 0; i < num_vectors; i++) - { - asmv("movdqa (%0), %%xmm0\n" - "movdqa %%xmm0, (%1)\n" - : - : "r"(s), "r"(d) - : "xmm0"); - d += 16; - s += 16; - } - n -= num_vectors * 16; - } + if ((((uintptr_t)d | (uintptr_t)s) & 0xF) == 0) + { + size_t num_vectors = n / 16; + for (size_t i = 0; i < num_vectors; i++) + { + asmv("movdqa (%0), %%xmm0\n" + "movdqa %%xmm0, (%1)\n" + : + : "r"(s), "r"(d) + : "xmm0"); + d += 16; + s += 16; + } + n -= num_vectors * 16; + } + else + { + size_t num_vectors = n / 16; + for (size_t i = 0; i < num_vectors; i++) + { + asmv("movdqu (%0), %%xmm0\n" + "movdqu %%xmm0, (%1)\n" + : + : "r"(s), "r"(d) + : "xmm0"); + d += 16; + s += 16; + } + n -= num_vectors * 16; + } - memcpy_unsafe(d, s, n); + memcpy_unsafe(d, s, n); #endif // defined(a64) - return dest; + return dest; } EXTERNC void *memcpy_sse3(void *dest, const void *src, size_t n) { #if defined(a64) - char *d = (char *)dest; - const char *s = (const char *)src; + char *d = (char *)dest; + const char *s = (const char *)src; - if ((((uintptr_t)d | (uintptr_t)s) & 0x7) == 0) - { - size_t num_vectors = n / 8; - for (size_t i = 0; i < num_vectors; i++) - { - asmv("movq (%0), %%xmm0\n" - "movddup %%xmm0, %%xmm1\n" - "movq %%xmm1, (%1)\n" - : - : "r"(s), "r"(d) - : "xmm0", "xmm1"); - d += 8; - s += 8; - } - n -= num_vectors * 8; - } + if ((((uintptr_t)d | (uintptr_t)s) & 0xF) == 0) + { + size_t num_vectors = n / 16; + for (size_t i = 0; i < num_vectors; i++) + { + asmv("movdqa (%0), %%xmm0\n" + "movdqa %%xmm0, (%1)\n" + : + : "r"(s), "r"(d) + : "xmm0"); + d += 16; + s += 16; + } + n -= num_vectors * 16; + } + else + { + size_t num_vectors = n / 16; + for (size_t i = 0; i < num_vectors; i++) + { + asmv("movdqu (%0), %%xmm0\n" + "movdqu %%xmm0, (%1)\n" + : + : "r"(s), "r"(d) + : "xmm0"); + d += 16; + s += 16; + } + n -= num_vectors * 16; + } - memcpy_unsafe(d, s, n); + memcpy_unsafe(d, s, n); #endif // defined(a64) - return dest; + return dest; } EXTERNC void *memcpy_ssse3(void *dest, const void *src, size_t n) { #if defined(a64) - char *d = (char *)dest; - const char *s = (const char *)src; + char *d = (char *)dest; + const char *s = (const char *)src; - if ((((uintptr_t)d | (uintptr_t)s) & 0xF) == 0) - { - size_t num_vectors = n / 16; - for (size_t i = 0; i < num_vectors; i++) - { - asmv("movdqa (%0), %%xmm0\n" - "movdqa 16(%0), %%xmm1\n" - "palignr $8, %%xmm0, %%xmm1\n" - "movdqa %%xmm1, (%1)\n" - : - : "r"(s), "r"(d) - : "xmm0", "xmm1"); - d += 16; - s += 16; - } - n -= num_vectors * 16; - } + if ((((uintptr_t)d | (uintptr_t)s) & 0xF) == 0) + { + size_t num_vectors = n / 16; + for (size_t i = 0; i < num_vectors; i++) + { + asmv("lddqu (%0), %%xmm0\n" + "movdqa %%xmm0, (%1)\n" + : + : "r"(s), "r"(d) + : "xmm0"); + d += 16; + s += 16; + } + n -= num_vectors * 16; + } + else + { + size_t num_vectors = n / 16; + for (size_t i = 0; i < num_vectors; i++) + { + asmv("lddqu (%0), %%xmm0\n" + "movdqu %%xmm0, (%1)\n" + : + : "r"(s), "r"(d) + : "xmm0"); + d += 16; + s += 16; + } + n -= num_vectors * 16; + } - memcpy_unsafe(d, s, n); + memcpy_unsafe(d, s, n); #endif // defined(a64) - return dest; + return dest; } EXTERNC void *memcpy_sse4_1(void *dest, const void *src, size_t n) { #if defined(a64) - char *d = (char *)dest; - const char *s = (const char *)src; + char *d = (char *)dest; + const char *s = (const char *)src; - if ((((uintptr_t)d | (uintptr_t)s) & 0xF) == 0) - { - size_t num_vectors = n / 16; - for (size_t i = 0; i < num_vectors; i++) - { - // movntdqa - asmv("movdqa (%0), %%xmm0\n" - "movdqa %%xmm0, (%1)\n" - : - : "r"(s), "r"(d) - : "xmm0"); - d += 16; - s += 16; - } - n -= num_vectors * 16; - } + if ((((uintptr_t)d | (uintptr_t)s) & 0xF) == 0) + { + size_t num_vectors = n / 16; + for (size_t i = 0; i < num_vectors; i++) + { + asmv("movdqa (%0), %%xmm0\n" + "movdqa %%xmm0, (%1)\n" + : + : "r"(s), "r"(d) + : "xmm0"); + d += 16; + s += 16; + } + n -= num_vectors * 16; + } + else + { + size_t num_vectors = n / 16; + for (size_t i = 0; i < num_vectors; i++) + { + asmv("movdqu (%0), %%xmm0\n" + "movdqu %%xmm0, (%1)\n" + : + : "r"(s), "r"(d) + : "xmm0"); + d += 16; + s += 16; + } + n -= num_vectors * 16; + } - memcpy_unsafe(d, s, n); + memcpy_unsafe(d, s, n); #endif // defined(a64) - return dest; + return dest; } EXTERNC void *memcpy_sse4_2(void *dest, const void *src, size_t n) { #if defined(a64) - char *d = (char *)dest; - const char *s = (const char *)src; + char *d = (char *)dest; + const char *s = (const char *)src; - if ((((uintptr_t)d | (uintptr_t)s) & 0xF) == 0) - { - size_t num_vectors = n / 16; - for (size_t i = 0; i < num_vectors; i++) - { - asmv("movdqa (%0), %%xmm0\n" - "pcmpistri $0, (%0), %%xmm0\n" - "movdqa %%xmm0, (%1)\n" - : - : "r"(s), "r"(d) - : "xmm0"); - d += 16; - s += 16; - } - n -= num_vectors * 16; - } + if ((((uintptr_t)d | (uintptr_t)s) & 0xF) == 0) + { + size_t num_vectors = n / 16; + for (size_t i = 0; i < num_vectors; i++) + { + asmv("movdqa (%0), %%xmm0\n" + "movdqa %%xmm0, (%1)\n" + : + : "r"(s), "r"(d) + : "xmm0"); + d += 16; + s += 16; + } + n -= num_vectors * 16; + } + else + { + size_t num_vectors = n / 16; + for (size_t i = 0; i < num_vectors; i++) + { + asmv("movdqu (%0), %%xmm0\n" + "movdqu %%xmm0, (%1)\n" + : + : "r"(s), "r"(d) + : "xmm0"); + d += 16; + s += 16; + } + n -= num_vectors * 16; + } - memcpy_unsafe(d, s, n); + memcpy_unsafe(d, s, n); #endif // defined(a64) - return dest; + return dest; } diff --git a/library/simd_memmove.cpp b/library/simd_memmove.cpp index 36e7198..cb22ec3 100644 --- a/library/simd_memmove.cpp +++ b/library/simd_memmove.cpp @@ -24,37 +24,37 @@ /* TODO: Replace these functions with even more optimized versions. - The current versions are fast but not as fast as they could be and also we need implementation for avx, not only sse. + The current versions are fast but not as fast as they could be and also we need implementation for avx, not only sse. */ // TODO: Implement these functions EXTERNC void *memmove_sse(void *dest, const void *src, size_t n) { - return memmove_unsafe(dest, src, n); + return memmove_unsafe(dest, src, n); } EXTERNC void *memmove_sse2(void *dest, const void *src, size_t n) { - return memmove_unsafe(dest, src, n); + return memmove_sse(dest, src, n); } EXTERNC void *memmove_sse3(void *dest, const void *src, size_t n) { - return memmove_unsafe(dest, src, n); + return memmove_sse(dest, src, n); } EXTERNC void *memmove_ssse3(void *dest, const void *src, size_t n) { - return memmove_unsafe(dest, src, n); + return memmove_sse(dest, src, n); } EXTERNC void *memmove_sse4_1(void *dest, const void *src, size_t n) { - return memmove_unsafe(dest, src, n); + return memmove_sse(dest, src, n); } EXTERNC void *memmove_sse4_2(void *dest, const void *src, size_t n) { - return memmove_unsafe(dest, src, n); + return memmove_sse(dest, src, n); } diff --git a/library/simd_memset.cpp b/library/simd_memset.cpp index 8b71e76..f1a0fd0 100644 --- a/library/simd_memset.cpp +++ b/library/simd_memset.cpp @@ -24,58 +24,91 @@ /* TODO: Replace these functions with even more optimized versions. - The current versions are fast but not as fast as they could be and also we need implementation for avx, not only sse. + The current versions are fast but not as fast as they could be and also we need implementation for avx, not only sse. */ // TODO: Implement these functions EXTERNC void *memset_sse(void *dest, int c, size_t n) { - return memset_unsafe(dest, c, n); + return memset_unsafe(dest, c, n); } EXTERNC void *memset_sse2(void *dest, int c, size_t n) { - return memset_unsafe(dest, c, n); + size_t i; + if ((size_t)dest & (16 - 1)) + { + i = 0; + while (((size_t)dest + i) & (16 - 1) && i < n) + { + asmv("stosb\n" + : + : "D"((size_t)dest + i), + "a"(c)); + i++; + } + } + else + i = 0; + + for (; i + 64 <= n; i += 64) + { + asmv("movd %0, %%xmm0\n" + "movdqa %%xmm0, (%1)\n" + "movdqa %%xmm0, 16(%1)\n" + "movdqa %%xmm0, 32(%1)\n" + "movdqa %%xmm0, 48(%1)\n" + : + : "r"(c), "r"(((size_t)dest) + i) + : "xmm0"); + } + + asmv("rep stosb\n" ::"a"((size_t)(c)), + "D"(((size_t)dest) + i), + "c"(n - i)); + + i += n - i; + return (void *)(((size_t)dest) + i); } EXTERNC void *memset_sse3(void *dest, int c, size_t n) { - return memset_unsafe(dest, c, n); + return memset_sse2(dest, c, n); } EXTERNC void *memset_ssse3(void *dest, int c, size_t n) { - return memset_unsafe(dest, c, n); + return memset_sse2(dest, c, n); } EXTERNC void *memset_sse4_1(void *dest, int c, size_t n) { - return memset_unsafe(dest, c, n); + return memset_sse2(dest, c, n); } EXTERNC void *memset_sse4_2(void *dest, int c, size_t n) { #if defined(a64) - char *d = (char *)dest; + char *d = (char *)dest; - if (((uintptr_t)d & 0xF) == 0) - { - size_t num_vectors = n / 16; - for (size_t i = 0; i < num_vectors; i++) - { - asmv("movd %0, %%xmm0\n" - "pshufd $0, %%xmm0, %%xmm0\n" - "movdqa %%xmm0, (%1)\n" - : - : "r"(c), "r"(d) - : "xmm0"); - d += 16; - } - n -= num_vectors * 16; - } + if (((uintptr_t)d & 0xF) == 0) + { + size_t num_vectors = n / 16; + for (size_t i = 0; i < num_vectors; i++) + { + asmv("movd %0, %%xmm0\n" + "pshufd $0, %%xmm0, %%xmm0\n" + "movdqa %%xmm0, (%1)\n" + : + : "r"(c), "r"(d) + : "xmm0"); + d += 16; + } + n -= num_vectors * 16; + } - memset_unsafe(d, c, n); + memset_unsafe(d, c, n); #endif - return dest; + return dest; } diff --git a/library/simd_strlen.cpp b/library/simd_strlen.cpp new file mode 100644 index 0000000..0695a6e --- /dev/null +++ b/library/simd_strlen.cpp @@ -0,0 +1,122 @@ +/* + 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 + +/* +TODO: Replace these functions with even more optimized versions. + The current versions are fast but not as fast as they could be and also we need implementation for avx, not only sse. +*/ + +long unsigned __strlen(const char s[]) +{ + size_t ret = (size_t)s; + + asmv("._strlenLoop:" + "cmpb $0, 0(%1)\n" + "jz ._strlenExit\n" + "cmpb $0, 1(%1)\n" + "jz .scmp1\n" + "cmpb $0, 2(%1)\n" + "jz .scmp2\n" + "cmpb $0, 3(%1)\n" + "jz .scmp3\n" + "cmpb $0, 4(%1)\n" + "jz .scmp4\n" + "cmpb $0, 5(%1)\n" + "jz .scmp5\n" + "cmpb $0, 6(%1)\n" + "jz .scmp6\n" + "cmpb $0, 7(%1)\n" + "jz .scmp7\n" + + "add $8, %1\n" + "jmp ._strlenLoop\n" + + ".scmp1:" + "inc %1\n" + "jmp ._strlenExit\n" + ".scmp2:" + "add $2, %1\n" + "jmp ._strlenExit\n" + ".scmp3:" + "add $3, %1\n" + "jmp ._strlenExit\n" + ".scmp4:" + "add $4, %1\n" + "jmp ._strlenExit\n" + ".scmp5:" + "add $5, %1\n" + "jmp ._strlenExit\n" + ".scmp6:" + "add $6, %1\n" + "jmp ._strlenExit\n" + ".scmp7:" + "add $7, %1\n" + + "._strlenExit:" + "mov %1, %0\n" + : "=r"(ret) : "0"(ret)); + + return ret - (size_t)s; +} + +long unsigned strlen_sse(const char s[]) +{ + return __strlen(s); +} + +long unsigned strlen_sse2(const char s[]) +{ + return __strlen(s); +} + +long unsigned strlen_sse3(const char s[]) +{ + return __strlen(s); +} + +long unsigned strlen_ssse3(const char s[]) +{ + return __strlen(s); +} + +long unsigned strlen_sse4_1(const char s[]) +{ + return __strlen(s); +} + +long unsigned strlen_sse4_2(const char s[]) +{ + size_t ret; + asmv("mov $-16, %0\n" + "pxor %%xmm0, %%xmm0\n" + ".strlen42Loop:" + "add $16, %0\n" + "pcmpistri $0x08, (%0,%1), %%xmm0\n" + "jnz .strlen42Loop\n" + "add %2, %0\n" + : "=a"(ret) + : "d"((size_t)s), "c"((size_t)s)); + + return ret; +} diff --git a/library/std/errno.cpp b/library/std/errno.cpp index be514bf..b0ae4aa 100644 --- a/library/std/errno.cpp +++ b/library/std/errno.cpp @@ -25,9 +25,281 @@ __aligned(16) static int errno_value = 0; -int *__errno_location(void) +EXTERNC int *__errno_location(void) { if (unlikely(!TaskManager || !thisThread)) return &errno_value; return &thisThread->ErrorNumber; } + +const char *strerror(int errnum) +{ + if (errnum < 0) + errnum = -errnum; + + switch (errnum) + { + case 0: + return "Success"; + case EPERM: + return "Operation not permitted"; + case ENOENT: + return "No such file or directory"; + case ESRCH: + return "No such process"; + case EINTR: + return "Interrupted system call"; + case EIO: + return "Input/output error"; + case ENXIO: + return "No such device or address"; + case E2BIG: + return "Argument list too long"; + case ENOEXEC: + return "Exec format error"; + case EBADF: + return "Bad file descriptor"; + case ECHILD: + return "No child processes"; + case EAGAIN: + return "Resource temporarily unavailable"; + case ENOMEM: + return "Cannot allocate memory"; + case EACCES: + return "Permission denied"; + case EFAULT: + return "Bad address"; + case ENOTBLK: + return "Block device required"; + case EBUSY: + return "Device or resource busy"; + case EEXIST: + return "File exists"; + case EXDEV: + return "Invalid cross-device link"; + case ENODEV: + return "No such device"; + case ENOTDIR: + return "Not a directory"; + case EISDIR: + return "Is a directory"; + case EINVAL: + return "Invalid argument"; + case ENFILE: + return "Too many open files in system"; + case EMFILE: + return "Too many open files"; + case ENOTTY: + return "Inappropriate ioctl for device"; + case ETXTBSY: + return "Text file busy"; + case EFBIG: + return "File too large"; + case ENOSPC: + return "No space left on device"; + case ESPIPE: + return "Illegal seek"; + case EROFS: + return "Read-only file system"; + case EMLINK: + return "Too many links"; + case EPIPE: + return "Broken pipe"; + case EDOM: + return "Numerical argument out of domain"; + case ERANGE: + return "Numerical result out of range"; + case EDEADLK: + return "Resource deadlock avoided"; + case ENAMETOOLONG: + return "File name too long"; + case ENOLCK: + return "No locks available"; + case ENOSYS: + return "Function not implemented"; + case ENOTEMPTY: + return "Directory not empty"; + case ELOOP: + return "Too many levels of symbolic links"; + case ENOMSG: + return "No message of desired type"; + case EIDRM: + return "Identifier removed"; + case ECHRNG: + return "Channel number out of range"; + case EL2NSYNC: + return "Level 2 not synchronized"; + case EL3HLT: + return "Level 3 halted"; + case EL3RST: + return "Level 3 reset"; + case ELNRNG: + return "Link number out of range"; + case EUNATCH: + return "Protocol driver not attached"; + case ENOCSI: + return "No CSI structure available"; + case EL2HLT: + return "Level 2 halted"; + case EBADE: + return "Invalid exchange"; + case EBADR: + return "Invalid request descriptor"; + case EXFULL: + return "Exchange full"; + case ENOANO: + return "No anode"; + case EBADRQC: + return "Invalid request code"; + case EBADSLT: + return "Invalid slot"; + case EBFONT: + return "Bad font file format"; + case ENOSTR: + return "Device not a stream"; + case ENODATA: + return "No data available"; + case ETIME: + return "Timer expired"; + case ENOSR: + return "Out of streams resources"; + case ENONET: + return "Machine is not on the network"; + case ENOPKG: + return "Package not installed"; + case EREMOTE: + return "Object is remote"; + case ENOLINK: + return "Link has been severed"; + case EADV: + return "Advertise error"; + case ESRMNT: + return "Srmount error"; + case ECOMM: + return "Communication error on send"; + case EPROTO: + return "Protocol error"; + case EMULTIHOP: + return "Multihop attempted"; + case EDOTDOT: + return "RFS specific error"; + case EBADMSG: + return "Bad message"; + case EOVERFLOW: + return "Value too large for defined data type"; + case ENOTUNIQ: + return "Name not unique on network"; + case EBADFD: + return "File descriptor in bad state"; + case EREMCHG: + return "Remote address changed"; + case ELIBACC: + return "Can not access a needed shared library"; + case ELIBBAD: + return "Accessing a corrupted shared library"; + case ELIBSCN: + return ".lib section in a.out corrupted"; + case ELIBMAX: + return "Attempting to link in too many shared libraries"; + case ELIBEXEC: + return "Cannot exec a shared library directly"; + case EILSEQ: + return "Illegal byte sequence"; + case ERESTART: + return "Interrupted system call should be restarted"; + case ESTRPIPE: + return "Streams pipe error"; + case EUSERS: + return "Too many users"; + case ENOTSOCK: + return "Socket operation on non-socket"; + case EDESTADDRREQ: + return "Destination address required"; + case EMSGSIZE: + return "Message too long"; + case EPROTOTYPE: + return "Protocol wrong type for socket"; + case ENOPROTOOPT: + return "Protocol not available"; + case EPROTONOSUPPORT: + return "Protocol not supported"; + case ESOCKTNOSUPPORT: + return "Socket type not supported"; + case EOPNOTSUPP: + return "Operation not supported"; + case EPFNOSUPPORT: + return "Protocol family not supported"; + case EAFNOSUPPORT: + return "Address family not supported by protocol"; + case EADDRINUSE: + return "Address already in use"; + case EADDRNOTAVAIL: + return "Cannot assign requested address"; + case ENETDOWN: + return "Network is down"; + case ENETUNREACH: + return "Network is unreachable"; + case ENETRESET: + return "Network dropped connection on reset"; + case ECONNABORTED: + return "Software caused connection abort"; + case ECONNRESET: + return "Connection reset by peer"; + case ENOBUFS: + return "No buffer space available"; + case EISCONN: + return "Transport endpoint is already connected"; + case ENOTCONN: + return "Transport endpoint is not connected"; + case ESHUTDOWN: + return "Cannot send after transport endpoint shutdown"; + case ETOOMANYREFS: + return "Too many references: cannot splice"; + case ETIMEDOUT: + return "Connection timed out"; + case ECONNREFUSED: + return "Connection refused"; + case EHOSTDOWN: + return "Host is down"; + case EHOSTUNREACH: + return "No route to host"; + case EALREADY: + return "Operation already in progress"; + case EINPROGRESS: + return "Operation now in progress"; + case ESTALE: + return "Stale file handle"; + case EUCLEAN: + return "Structure needs cleaning"; + case ENOTNAM: + return "Not a XENIX named type file"; + case ENAVAIL: + return "No XENIX semaphores available"; + case EISNAM: + return "Is a named type file"; + case EREMOTEIO: + return "Remote I/O error"; + case EDQUOT: + return "Quota exceeded"; + case ENOMEDIUM: + return "No medium found"; + case EMEDIUMTYPE: + return "Wrong medium type"; + case ECANCELED: + return "Operation Canceled"; + case ENOKEY: + return "Required key not available"; + case EKEYEXPIRED: + return "Key has expired"; + case EKEYREVOKED: + return "Key has been revoked"; + case EKEYREJECTED: + return "Key was rejected by service"; + case EOWNERDEAD: + return "Owner died"; + case ENOTRECOVERABLE: + return "State not recoverable"; + default: + return "Unknown error"; + } +} \ No newline at end of file diff --git a/library/targp.c b/library/targp.c index b39d8ee..6892949 100644 --- a/library/targp.c +++ b/library/targp.c @@ -22,26 +22,26 @@ void targp_parse(const char *cmd, char **argv, int *argc) { - const char delim[] = " "; + const char delim[] = " "; - char *token = strtok((char *)cmd, delim); - while (token != NULL) - { - char *quote = strchr(token, '"'); - if (quote != NULL) - { - memmove(quote, quote + 1, strlen(quote)); - char *endQuote = strchr(quote, '"'); - if (endQuote != NULL) - *endQuote = '\0'; - } + char *token = strtok((char *)cmd, delim); + while (token != NULL) + { + char *quote = strchr(token, '"'); + if (quote != NULL) + { + memmove(quote, quote + 1, strlen(quote)); + char *endQuote = strchr(quote, '"'); + if (endQuote != NULL) + *endQuote = '\0'; + } - char *arg = (char *)kmalloc(strlen(token) + 1); - strcpy(arg, token); + char *arg = (char *)kmalloc(strlen(token) + 1); + strcpy(arg, token); - argv[(*argc)++] = arg; + argv[(*argc)++] = arg; - token = strtok(NULL, delim); - } - argv[(*argc)] = NULL; + token = strtok(NULL, delim); + } + argv[(*argc)] = NULL; } diff --git a/mapi.hpp b/mapi.hpp deleted file mode 100644 index d8f87b6..0000000 --- a/mapi.hpp +++ /dev/null @@ -1,457 +0,0 @@ -/* - BSD 3-Clause License - - Copyright (c) 2023, EnderIce2 - All rights reserved. - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. Neither the name of the copyright holder nor the names of its - contributors may be used to endorse or promote products derived from - this software without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ - -#ifndef __FENNIX_MODULE_API_H__ -#define __FENNIX_MODULE_API_H__ - -/** - * The module API is a set of functions that the kernel provides to the drivers. - * - * - The module is responsible for the memory management. - * - The kernel will NOT free any memory allocated by the module. On @see StopReason the module must free all the memory it allocated and disable the hardware it uses. - * - The module image will be freed after the module is unloaded. - * - The kernel will unbind the interrupt handlers and the process handlers. - * - Kernel API will be freed after the module is unloaded. - * - */ - -enum ModuleReturnCode -{ - ERROR, - OK, - NOT_IMPLEMENTED, - NOT_FOUND, - NOT_READY, - NOT_AVAILABLE, - NOT_AUTHORIZED, - NOT_VALID, - NOT_ACCEPTED, - INVALID_PCI_BAR, - INVALID_KERNEL_API, - INVALID_MEMORY_ALLOCATION, - INVALID_DATA, - DEVICE_NOT_SUPPORTED, - SYSTEM_NOT_SUPPORTED, - KERNEL_API_VERSION_NOT_SUPPORTED, -}; - -enum ModuleBindType -{ - BIND_NULL, - BIND_INTERRUPT, - BIND_PROCESS, - BIND_PCI, - BIND_INPUT -}; - -struct KernelAPI -{ - struct KAPIVersion - { - int Major; - int Minor; - int Patch; - } Version; - - struct KAPIInfo - { - __UINT64_TYPE__ Offset; - __UINT32_TYPE__ modUniqueID; - char KernelDebug; - } Info; - - struct KAPIMemory - { - __UINT64_TYPE__ PageSize; - void *(*RequestPage)(__UINT64_TYPE__ Size); - void (*FreePage)(void *Page, __UINT64_TYPE__ Size); - void (*Map)(void *VirtualAddress, void *PhysicalAddress, __UINT64_TYPE__ Flags); - void (*Unmap)(void *VirtualAddress); - } Memory; - - struct KAPIPCI - { - char *(*GetDeviceName)(__UINT32_TYPE__ VendorID, __UINT32_TYPE__ DeviceID); - } PCI; - - struct KAPIUtilities - { - void (*DebugPrint)(char *String, __UINT64_TYPE__ modUniqueID); - void (*DisplayPrint)(char *Value); - void *(*memcpy)(void *Destination, void *Source, __UINT64_TYPE__ Size); - void *(*memset)(void *Destination, int Value, __UINT64_TYPE__ Size); - void (*Sleep)(__UINT64_TYPE__ Milliseconds); - int (*sprintf)(char *Buffer, const char *Format, ...); - } Util; - - struct KAPIModuleTalk - { - /** Connects to the network manager */ - struct - { - void (*SendPacket)(__UINT32_TYPE__ ModuleID, __UINT8_TYPE__ *Data, __UINT16_TYPE__ Size); - void (*ReceivePacket)(__UINT32_TYPE__ ModuleID, __UINT8_TYPE__ *Data, __UINT16_TYPE__ Size); - } Network; - - /** Connects to the disk manager */ - struct - { - struct - { - void (*ReadSector)(__UINT32_TYPE__ ModuleID, __UINT64_TYPE__ Sector, __UINT8_TYPE__ *Data, __UINT32_TYPE__ SectorCount, __UINT8_TYPE__ Port); - void (*WriteSector)(__UINT32_TYPE__ ModuleID, __UINT64_TYPE__ Sector, __UINT8_TYPE__ *Data, __UINT32_TYPE__ SectorCount, __UINT8_TYPE__ Port); - } AHCI; - } Disk; - } Command; - - struct KAPIDisplay - { - __UINT32_TYPE__ (*GetWidth) - (void); - __UINT32_TYPE__ (*GetHeight) - (void); - /* TODO: Add more */ - } Display; -} __attribute__((packed)); - -enum CallbackReason -{ - /** - * This is used to detect memory corruption, not used. - */ - UnknownReason, - - /** - * This is called once the kernel is ready to use the module and call @see ConfigurationReason . - */ - AcknowledgeReason, - - /** - * This is used after the module is loaded and the kernel is ready to use the module. - * - * For PCI drivers, @see RawPtr will be the PCI device address. - */ - ConfigurationReason, - - /** - * This is used when the kernel wants to stop the module. - * - * The memory allocated by the module will be freed automatically. - */ - StopReason, - - ProcessReason, - InputReason, - - /* Kernel reserved callbacks. */ - /* ------------------------------------------------------- */ - /* Module callbacks for basic usage. */ - - /** - * This is used when the kernel sends data. - * - * - Network - * - Packet - * - Audio - * - PCM Data - */ - SendReason, - - /** - * This is used when the kernel wants to receive data. - * Currently not used. - */ - ReceiveReason, - - /** - * This is used to adjust module settings. - * - * - Audio - * - Volume - * - PCM Encoding - */ - AdjustReason, - - /** - * This is used when the kernel wants to query information about the module. - * - * - Input - * - Mouse - * - Position - * - Buttons - * - Keyboard - * - Key - */ - QueryReason, - - /** - * This is used when the kernel wants to wait for an event. - * - * - Input - * - Mouse - * - Position - * - Buttons - * - Keyboard - * - Key - */ - PollWaitReason, -}; - -union KernelCallback -{ - struct - { - CallbackReason Reason; - void *RawPtr; - __UINT64_TYPE__ RawData; - - /** When the kernel wants to send a packet. */ - struct - { - struct - { - __UINT8_TYPE__ *Data; - __UINT64_TYPE__ Length; - } Send; - - struct - { - char Name[128]; - __UINT64_TYPE__ MAC; - } Fetch; - } NetworkCallback; - - /** When the kernel wants to write to disk. */ - struct - { - struct - { - __UINT64_TYPE__ Sector; - __UINT64_TYPE__ SectorCount; - __UINT8_TYPE__ Port; - __UINT8_TYPE__ *Buffer; - bool Write; - } RW; - - struct - { - __UINT8_TYPE__ Ports; - int BytesPerSector; - } Fetch; - } DiskCallback; - - /** When the kernel wants to get mouse position / keyboard key */ - struct - { - struct - { - __UINT64_TYPE__ X; - __UINT64_TYPE__ Y; - __UINT64_TYPE__ Z; - struct - { - bool Left; - bool Right; - bool Middle; - } Buttons; - } Mouse; - - struct - { - /** - * The key. - * - * @note This is a scancode, not a character. - */ - __UINT8_TYPE__ Key; - } Keyboard; - } InputCallback; - - struct - { - struct - { - bool _Volume; - bool _Encoding; - bool _SampleRate; - bool _Channels; - - /** - * Adjust the volume. - * - * 0 - 100 - */ - __UINT8_TYPE__ Volume; - - /** - * Adjust the encoding. - * - * 0 - None, use default - * - * 1 - Signed PCM 8-bit - * 2 - Unsigned PCM 8-bit - * - * 3 - Signed PCM 16-bit Little Endian - * 4 - Signed PCM 20-bit Little Endian - * 5 - Signed PCM 24-bit Little Endian - * 6 - Signed PCM 32-bit Little Endian - * - * 7 - Unsigned PCM 16-bit Little Endian - * 8 - Unsigned PCM 20-bit Little Endian - * 9 - Unsigned PCM 24-bit Little Endian - * 10 - Unsigned PCM 32-bit Little Endian - * - * 11 - Signed PCM 16-bit Big Endian - * 12 - Signed PCM 20-bit Big Endian - * 13 - Signed PCM 24-bit Big Endian - * 14 - Signed PCM 32-bit Big Endian - * - * 15 - Unsigned PCM 16-bit Big Endian - * 16 - Unsigned PCM 20-bit Big Endian - * 17 - Unsigned PCM 24-bit Big Endian - * 18 - Unsigned PCM 32-bit Big Endian - * - * 19 - Float PCM 32-bit Little Endian - * 20 - Float PCM 64-bit Little Endian - * - * 21 - Float PCM 32-bit Big Endian - * 22 - Float PCM 64-bit Big Endian - * - * 23 - PCM A-law - * 24 - PCM Mu-law - * - * ... - More - */ - __UINT16_TYPE__ Encoding; - - /** - * Adjust the sample rate. - * - * 0 - 8000 Hz - * 1 - 11025 Hz - * 2 - 16000 Hz - * 3 - 22050 Hz - * 4 - 32000 Hz - * 5 - 44100 Hz - * 6 - 48000 Hz - * 7 - 88200 Hz - * 8 - 96000 Hz - */ - __UINT8_TYPE__ SampleRate; - - /** - * Adjust the channels. - * - * 0 - Mono - * 1 - Stereo - */ - __UINT8_TYPE__ Channels; - } Adjust; - - struct - { - __UINT8_TYPE__ *Data; - __UINT64_TYPE__ Length; - } Send; - - struct - { - __UINT8_TYPE__ Volume; - __UINT16_TYPE__ Encoding; - __UINT8_TYPE__ SampleRate; - __UINT8_TYPE__ Channels; - } Fetch; - } AudioCallback; - - struct - { - __UINT8_TYPE__ Vector; - } InterruptInfo; - }; - __UINT64_TYPE__ raw; -} __attribute__((packed)); - -union CPURegisters -{ - struct - { -#if defined(__x86_64__) || defined(__amd64__) - __UINT64_TYPE__ r15; - __UINT64_TYPE__ r14; - __UINT64_TYPE__ r13; - __UINT64_TYPE__ r12; - __UINT64_TYPE__ r11; - __UINT64_TYPE__ r10; - __UINT64_TYPE__ r9; - __UINT64_TYPE__ r8; - - __UINT64_TYPE__ rbp; - __UINT64_TYPE__ rdi; - __UINT64_TYPE__ rsi; - __UINT64_TYPE__ rdx; - __UINT64_TYPE__ rcx; - __UINT64_TYPE__ rbx; - __UINT64_TYPE__ rax; - - __UINT64_TYPE__ InterruptNumber; - __UINT64_TYPE__ ErrorCode; - __UINT64_TYPE__ rip; - __UINT64_TYPE__ cs; - __UINT64_TYPE__ rflags; - __UINT64_TYPE__ rsp; - __UINT64_TYPE__ ss; -#elif defined(__i386__) - __UINT32_TYPE__ edi; - __UINT32_TYPE__ esi; - __UINT32_TYPE__ ebp; - __UINT32_TYPE__ esp; - __UINT32_TYPE__ ebx; - __UINT32_TYPE__ edx; - __UINT32_TYPE__ ecx; - __UINT32_TYPE__ eax; - - __UINT32_TYPE__ InterruptNumber; - __UINT32_TYPE__ ErrorCode; - - __UINT32_TYPE__ eip; - __UINT32_TYPE__ cs; - __UINT32_TYPE__ eflags; - __UINT32_TYPE__ r3_esp; - __UINT32_TYPE__ r3_ss; -#else -#warning "Unsupported architecture" -#endif - }; - __UINT64_TYPE__ raw; -} __attribute__((packed)); - -#endif // !__FENNIX_MODULE_API_H__ diff --git a/modules/AHCI/AdvancedHostControllerInterface.cpp b/modules/AHCI/AdvancedHostControllerInterface.cpp deleted file mode 100644 index 9dda165..0000000 --- a/modules/AHCI/AdvancedHostControllerInterface.cpp +++ /dev/null @@ -1,312 +0,0 @@ -/* - This file is part of Fennix Kernel. - - Fennix Kernel is free software: you can redistribute it and/or - modify it under the terms of the GNU General Public License as - published by the Free Software Foundation, either version 3 of - the License, or (at your option) any later version. - - Fennix Kernel is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Fennix Kernel. If not, see . -*/ - -#include "ahci.hpp" - -#include -#include - -#include "../../mapi.hpp" -#include "../mod.hpp" - -using namespace PCI; - -namespace AdvancedHostControllerInterface -{ - KernelAPI KAPI; - - HBAMemory *AHBA; - Port *Ports[32]; - uint8_t PortCount = 0; - - PCIDeviceHeader *PCIBaseAddress; - - const char *PortTypeName[] = {"None", - "SATA", - "SEMB", - "PM", - "SATAPI"}; - - PortType CheckPortType(HBAPort *Port) - { - uint32_t SataStatus = Port->SataStatus; - uint8_t InterfacePowerManagement = (SataStatus >> 8) & 0b111; - uint8_t DeviceDetection = SataStatus & 0b111; - - if (DeviceDetection != HBA_PORT_DEV_PRESENT) - return PortType::None; - if (InterfacePowerManagement != HBA_PORT_IPM_ACTIVE) - return PortType::None; - - switch (Port->Signature) - { - case SATA_SIG_ATAPI: - return PortType::SATAPI; - case SATA_SIG_ATA: - return PortType::SATA; - case SATA_SIG_PM: - return PortType::PM; - case SATA_SIG_SEMB: - return PortType::SEMB; - default: - return PortType::None; - } - } - - Port::Port(PortType Type, HBAPort *PortPtr, uint8_t PortNumber) - { - this->AHCIPortType = Type; - this->HBAPortPtr = PortPtr; - this->Buffer = static_cast(KAPI.Memory.RequestPage(1)); - memset(this->Buffer, 0, size_t(KAPI.Memory.PageSize)); - this->PortNumber = PortNumber; - } - - Port::~Port() - { - KAPI.Memory.FreePage(this->Buffer, 1); - } - - void Port::StartCMD() - { - while (HBAPortPtr->CommandStatus & HBA_PxCMD_CR) - ; - HBAPortPtr->CommandStatus |= HBA_PxCMD_FRE; - HBAPortPtr->CommandStatus |= HBA_PxCMD_ST; - } - - void Port::StopCMD() - { - HBAPortPtr->CommandStatus &= ~HBA_PxCMD_ST; - HBAPortPtr->CommandStatus &= ~HBA_PxCMD_FRE; - while (true) - { - if (HBAPortPtr->CommandStatus & HBA_PxCMD_FR) - continue; - if (HBAPortPtr->CommandStatus & HBA_PxCMD_CR) - continue; - break; - } - } - - void Port::Configure() - { - StopCMD(); - void *NewBase = KAPI.Memory.RequestPage(1); - HBAPortPtr->CommandListBase = (uint32_t)(uint64_t)NewBase; - HBAPortPtr->CommandListBaseUpper = (uint32_t)((uint64_t)NewBase >> 32); - memset(reinterpret_cast(HBAPortPtr->CommandListBase), 0, 1024); - - void *FISBase = KAPI.Memory.RequestPage(1); - HBAPortPtr->FISBaseAddress = (uint32_t)(uint64_t)FISBase; - HBAPortPtr->FISBaseAddressUpper = (uint32_t)((uint64_t)FISBase >> 32); - memset(FISBase, 0, 256); - - HBACommandHeader *CommandHeader = (HBACommandHeader *)((uint64_t)HBAPortPtr->CommandListBase + ((uint64_t)HBAPortPtr->CommandListBaseUpper << 32)); - for (int i = 0; i < 32; i++) - { - CommandHeader[i].PRDTLength = 8; - void *CommandTableAddress = KAPI.Memory.RequestPage(1); - uint64_t Address = (uint64_t)CommandTableAddress + (i << 8); - CommandHeader[i].CommandTableBaseAddress = (uint32_t)(uint64_t)Address; - CommandHeader[i].CommandTableBaseAddressUpper = (uint32_t)((uint64_t)Address >> 32); - memset(CommandTableAddress, 0, 256); - } - StartCMD(); - } - - bool Port::ReadWrite(uint64_t Sector, uint32_t SectorCount, uint8_t *Buffer, bool Write) - { - if (this->PortNumber == PortType::SATAPI && Write) - { - error("SATAPI port does not support write."); - return false; - } - - uint32_t SectorL = (uint32_t)Sector; - uint32_t SectorH = (uint32_t)(Sector >> 32); - - HBAPortPtr->InterruptStatus = (uint32_t)-1; // Clear pending interrupt bits - - HBACommandHeader *CommandHeader = reinterpret_cast(HBAPortPtr->CommandListBase); - CommandHeader->CommandFISLength = sizeof(FIS_REG_H2D) / sizeof(uint32_t); - if (Write) - CommandHeader->Write = 1; - else - CommandHeader->Write = 0; - CommandHeader->PRDTLength = 1; - - HBACommandTable *CommandTable = reinterpret_cast(CommandHeader->CommandTableBaseAddress); - memset(CommandTable, 0, sizeof(HBACommandTable) + (CommandHeader->PRDTLength - 1) * sizeof(HBAPRDTEntry)); - - CommandTable->PRDTEntry[0].DataBaseAddress = (uint32_t)(uint64_t)Buffer; - CommandTable->PRDTEntry[0].DataBaseAddressUpper = (uint32_t)((uint64_t)Buffer >> 32); - -#pragma GCC diagnostic push -/* conversion from ‘uint32_t’ {aka ‘unsigned int’} to ‘unsigned int:22’ may change value */ -#pragma GCC diagnostic ignored "-Wconversion" - CommandTable->PRDTEntry[0].ByteCount = (SectorCount << 9) - 1; /* 512 bytes per sector */ -#pragma GCC diagnostic pop - - CommandTable->PRDTEntry[0].InterruptOnCompletion = 1; - - FIS_REG_H2D *CommandFIS = (FIS_REG_H2D *)(&CommandTable->CommandFIS); - - CommandFIS->FISType = FIS_TYPE_REG_H2D; - CommandFIS->CommandControl = 1; - if (Write) - CommandFIS->Command = ATA_CMD_WRITE_DMA_EX; - else - CommandFIS->Command = ATA_CMD_READ_DMA_EX; - - CommandFIS->LBA0 = (uint8_t)SectorL; - CommandFIS->LBA1 = (uint8_t)(SectorL >> 8); - CommandFIS->LBA2 = (uint8_t)(SectorL >> 16); - CommandFIS->LBA3 = (uint8_t)SectorH; - CommandFIS->LBA4 = (uint8_t)(SectorH >> 8); - CommandFIS->LBA5 = (uint8_t)(SectorH >> 16); - - CommandFIS->DeviceRegister = 1 << 6; // LBA mode - CommandFIS->CountLow = SectorCount & 0xFF; - CommandFIS->CountHigh = (SectorCount >> 8) & 0xFF; - - uint64_t Spin = 0; - - while ((HBAPortPtr->TaskFileData & (ATA_DEV_BUSY | ATA_DEV_DRQ)) && Spin < 1000000) - Spin++; - if (Spin == 1000000) - { - error("Port not responding."); - return false; - } - - HBAPortPtr->CommandIssue = 1; - - Spin = 0; - int TryCount = 0; - - while (true) - { - if (Spin > 100000000) - { - error("Port %d not responding. (%d)", this->PortNumber, TryCount); - Spin = 0; - TryCount++; - if (TryCount > 10) - return false; - } - if (HBAPortPtr->CommandIssue == 0) - break; - Spin++; - if (HBAPortPtr->InterruptStatus & HBA_PxIS_TFES) - { - error("Error reading/writing (%d).", Write); - return false; - } - } - - return true; - } - - int DriverEntry(void *Data) - { - if (!Data) - return INVALID_KERNEL_API; - KAPI = *(KernelAPI *)Data; - if (KAPI.Version.Major < 0 || KAPI.Version.Minor < 0 || KAPI.Version.Patch < 0) - return KERNEL_API_VERSION_NOT_SUPPORTED; - - return OK; - } - - int CallbackHandler(KernelCallback *Data) - { - switch (Data->Reason) - { - case AcknowledgeReason: - { - debug("Kernel acknowledged the driver."); - break; - } - case ConfigurationReason: - { - debug("Module received configuration data."); - PCIBaseAddress = reinterpret_cast(Data->RawPtr); - AHBA = reinterpret_cast(((PCIHeader0 *)PCIBaseAddress)->BAR5); - KAPI.Memory.Map((void *)AHBA, (void *)AHBA, (1 << 1)); - - uint32_t PortsImplemented = AHBA->PortsImplemented; - for (int i = 0; i < 32; i++) - { - if (PortsImplemented & (1 << i)) - { - PortType portType = CheckPortType(&AHBA->Ports[i]); - if (portType == PortType::SATA || portType == PortType::SATAPI) - { - trace("%s drive found at port %d", PortTypeName[portType], i); - Ports[PortCount] = new Port(portType, &AHBA->Ports[i], PortCount); - PortCount++; - } - else - { - if (portType != PortType::None) - warn("Unsupported drive type %s found at port %d", - PortTypeName[portType], i); - } - } - } - - for (int i = 0; i < PortCount; i++) - Ports[i]->Configure(); - break; - } - case QueryReason: - { - Data->DiskCallback.Fetch.Ports = PortCount; - Data->DiskCallback.Fetch.BytesPerSector = 512; - break; - } - case StopReason: - { - // TODO: Stop the driver. - debug("Module stopped."); - break; - } - case SendReason: - case ReceiveReason: - { - Ports[Data->DiskCallback.RW.Port]->ReadWrite(Data->DiskCallback.RW.Sector, - (uint32_t)Data->DiskCallback.RW.SectorCount, - Data->DiskCallback.RW.Buffer, - Data->DiskCallback.RW.Write); - break; - } - default: - { - warn("Unknown reason."); - break; - } - } - return OK; - } - - int InterruptCallback(CPURegisters *) - { - /* There is no interrupt handler for AHCI. */ - return OK; - } -} diff --git a/modules/AHCI/ahci.hpp b/modules/AHCI/ahci.hpp deleted file mode 100644 index 5ffae2e..0000000 --- a/modules/AHCI/ahci.hpp +++ /dev/null @@ -1,193 +0,0 @@ -/* - This file is part of Fennix Kernel. - - Fennix Kernel is free software: you can redistribute it and/or - modify it under the terms of the GNU General Public License as - published by the Free Software Foundation, either version 3 of - the License, or (at your option) any later version. - - Fennix Kernel is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Fennix Kernel. If not, see . -*/ - -#ifndef __FENNIX_KERNEL_AHCI_H__ -#define __FENNIX_KERNEL_AHCI_H__ - -#include -#include "../../mapi.hpp" - -namespace AdvancedHostControllerInterface -{ -#define ATA_DEV_BUSY 0x80 -#define ATA_DEV_DRQ 0x08 -#define ATA_CMD_WRITE_DMA_EX 0x35 -#define ATA_CMD_READ_DMA_EX 0x25 -#define HBA_PxIS_TFES (1 << 30) - -#define HBA_PORT_DEV_PRESENT 0x3 -#define HBA_PORT_IPM_ACTIVE 0x1 -#define SATA_SIG_ATAPI 0xEB140101 -#define SATA_SIG_ATA 0x00000101 -#define SATA_SIG_SEMB 0xC33C0101 -#define SATA_SIG_PM 0x96690101 - -#define HBA_PxCMD_CR 0x8000 -#define HBA_PxCMD_FRE 0x0010 -#define HBA_PxCMD_ST 0x0001 -#define HBA_PxCMD_FR 0x4000 - - enum PortType - { - None = 0, - SATA = 1, - SEMB = 2, - PM = 3, - SATAPI = 4, - }; - - enum FIS_TYPE - { - FIS_TYPE_REG_H2D = 0x27, - FIS_TYPE_REG_D2H = 0x34, - FIS_TYPE_DMA_ACT = 0x39, - FIS_TYPE_DMA_SETUP = 0x41, - FIS_TYPE_DATA = 0x46, - FIS_TYPE_BIST = 0x58, - FIS_TYPE_PIO_SETUP = 0x5F, - FIS_TYPE_DEV_BITS = 0xA1, - }; - - struct HBAPort - { - uint32_t CommandListBase; - uint32_t CommandListBaseUpper; - uint32_t FISBaseAddress; - uint32_t FISBaseAddressUpper; - uint32_t InterruptStatus; - uint32_t InterruptEnable; - uint32_t CommandStatus; - uint32_t Reserved0; - uint32_t TaskFileData; - uint32_t Signature; - uint32_t SataStatus; - uint32_t SataControl; - uint32_t SataError; - uint32_t SataActive; - uint32_t CommandIssue; - uint32_t SataNotification; - uint32_t FISSwitchControl; - uint32_t Reserved1[11]; - uint32_t Vendor[4]; - }; - - struct HBAMemory - { - uint32_t HostCapability; - uint32_t GlobalHostControl; - uint32_t InterruptStatus; - uint32_t PortsImplemented; - uint32_t Version; - uint32_t CCCControl; - uint32_t CCCPorts; - uint32_t EnclosureManagementLocation; - uint32_t EnclosureManagementControl; - uint32_t HostCapabilitiesExtended; - uint32_t BIOSHandoffControlStatus; - uint8_t Reserved0[0x74]; - uint8_t Vendor[0x60]; - HBAPort Ports[1]; - }; - - struct HBACommandHeader - { - uint8_t CommandFISLength : 5; - uint8_t ATAPI : 1; - uint8_t Write : 1; - uint8_t Preferable : 1; - uint8_t Reset : 1; - uint8_t BIST : 1; - uint8_t ClearBusy : 1; - uint8_t Reserved0 : 1; - uint8_t PortMultiplier : 4; - uint16_t PRDTLength; - uint32_t PRDBCount; - uint32_t CommandTableBaseAddress; - uint32_t CommandTableBaseAddressUpper; - uint32_t Reserved1[4]; - }; - - struct HBAPRDTEntry - { - uint32_t DataBaseAddress; - uint32_t DataBaseAddressUpper; - uint32_t Reserved0; - uint32_t ByteCount : 22; - uint32_t Reserved1 : 9; - uint32_t InterruptOnCompletion : 1; - }; - - struct HBACommandTable - { - uint8_t CommandFIS[64]; - uint8_t ATAPICommand[16]; - uint8_t Reserved[48]; - HBAPRDTEntry PRDTEntry[]; - }; - - struct FIS_REG_H2D - { - uint8_t FISType; - uint8_t PortMultiplier : 4; - uint8_t Reserved0 : 3; - uint8_t CommandControl : 1; - uint8_t Command; - uint8_t FeatureLow; - uint8_t LBA0; - uint8_t LBA1; - uint8_t LBA2; - uint8_t DeviceRegister; - uint8_t LBA3; - uint8_t LBA4; - uint8_t LBA5; - uint8_t FeatureHigh; - uint8_t CountLow; - uint8_t CountHigh; - uint8_t ISOCommandCompletion; - uint8_t Control; - uint8_t Reserved1[4]; - }; - - struct BARData - { - uint8_t Type; - uint16_t IOBase; - uint64_t MemoryBase; - }; - - class Port - { - public: - PortType AHCIPortType; - HBAPort *HBAPortPtr; - uint8_t *Buffer; - uint8_t PortNumber; - - Port(PortType Type, HBAPort *PortPtr, uint8_t PortNumber); - ~Port(); - void StartCMD(); - void StopCMD(); - void Configure(); - bool ReadWrite(uint64_t Sector, uint32_t SectorCount, uint8_t *Buffer, bool Write); - }; - - int DriverEntry(void *); - int CallbackHandler(KernelCallback *); - int InterruptCallback(CPURegisters *); -} - -#endif // !__FENNIX_KERNEL_AHCI_H__ diff --git a/modules/ATA/AdvancedTechnologyAttachment.cpp b/modules/ATA/AdvancedTechnologyAttachment.cpp deleted file mode 100644 index ae62521..0000000 --- a/modules/ATA/AdvancedTechnologyAttachment.cpp +++ /dev/null @@ -1,108 +0,0 @@ -/* - This file is part of Fennix Kernel. - - Fennix Kernel is free software: you can redistribute it and/or - modify it under the terms of the GNU General Public License as - published by the Free Software Foundation, either version 3 of - the License, or (at your option) any later version. - - Fennix Kernel is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Fennix Kernel. If not, see . -*/ - -#include "ata.hpp" - -#include -#include -#include - -#include "../../mapi.hpp" -#include "../mod.hpp" - -namespace AdvancedTechnologyAttachment -{ - KernelAPI KAPI; - - bool IsATAPresent() - { - outb(0x1F0 + 2, 0); - outb(0x1F0 + 3, 0); - outb(0x1F0 + 4, 0); - outb(0x1F0 + 5, 0); - outb(0x1F0 + 7, 0xEC); - if (inb(0x1F0 + 7) == 0 || inb(0x1F0 + 1) != 0) - return false; - return true; - } - - int DriverEntry(void *Data) - { - if (!Data) - return INVALID_KERNEL_API; - KAPI = *(KernelAPI *)Data; - if (KAPI.Version.Major < 0 || KAPI.Version.Minor < 0 || KAPI.Version.Patch < 0) - return KERNEL_API_VERSION_NOT_SUPPORTED; - - if (!IsATAPresent()) - return NOT_AVAILABLE; - trace("ATA device found."); - - return NOT_IMPLEMENTED; - } - - int CallbackHandler(KernelCallback *Data) - { - switch (Data->Reason) - { - case AcknowledgeReason: - { - debug("Kernel acknowledged the driver."); - break; - } - case ConfigurationReason: - { - debug("Module received configuration data."); - break; - } - case QueryReason: - { - break; - } - case SendReason: - case ReceiveReason: - { - break; - } - case StopReason: - { - // TODO: Stop the driver. - debug("Module stopped."); - break; - } - default: - { - warn("Unknown reason."); - break; - } - } - return OK; - } - - int InterruptCallback(CPURegisters *Registers) - { - if (Registers->InterruptNumber == 0xE) - { - fixme("IRQ14"); - } - else if (Registers->InterruptNumber == 0xF) - { - fixme("IRQ15"); - } - return OK; - } -} diff --git a/modules/AdvancedMicroDevices/PCNET.cpp b/modules/AdvancedMicroDevices/PCNET.cpp deleted file mode 100644 index 3b5330b..0000000 --- a/modules/AdvancedMicroDevices/PCNET.cpp +++ /dev/null @@ -1,131 +0,0 @@ -/* - This file is part of Fennix Kernel. - - Fennix Kernel is free software: you can redistribute it and/or - modify it under the terms of the GNU General Public License as - published by the Free Software Foundation, either version 3 of - the License, or (at your option) any later version. - - Fennix Kernel is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Fennix Kernel. If not, see . -*/ - -#include "pcnet.hpp" - -#include -#include -#include -#include - -#include "../../mapi.hpp" -#include "../mod.hpp" - -using namespace PCI; - -namespace PCNET -{ - KernelAPI KAPI; - - PCIDeviceHeader *PCIBaseAddress; - BARData BAR; - - MediaAccessControl MAC; - InternetProtocol::Version4 IP; - - void WriteRAP32(uint32_t Value) { outportl(BAR.IOBase + 0x14, Value); } - void WriteRAP16(uint16_t Value) { outportw(BAR.IOBase + 0x12, Value); } - - uint32_t ReadCSR32(uint32_t CSR) - { - WriteRAP32(CSR); - return inportl(BAR.IOBase + 0x10); - } - - uint16_t ReadCSR16(uint16_t CSR) - { - WriteRAP32(CSR); - return inportw(BAR.IOBase + 0x10); - } - - void WriteCSR32(uint32_t CSR, uint32_t Value) - { - WriteRAP32(CSR); - outportl(BAR.IOBase + 0x10, Value); - } - - void WriteCSR16(uint16_t CSR, uint16_t Value) - { - WriteRAP16(CSR); - outportw(BAR.IOBase + 0x10, Value); - } - - int DriverEntry(void *Data) - { - if (!Data) - return INVALID_KERNEL_API; - KAPI = *(KernelAPI *)Data; - if (KAPI.Version.Major < 0 || KAPI.Version.Minor < 0 || KAPI.Version.Patch < 0) - return KERNEL_API_VERSION_NOT_SUPPORTED; - return OK; - } - - int CallbackHandler(KernelCallback *Data) - { - switch (Data->Reason) - { - case AcknowledgeReason: - { - debug("Kernel acknowledged the driver."); - break; - } - case ConfigurationReason: - { - debug("Module received configuration data."); - PCIBaseAddress = reinterpret_cast(Data->RawPtr); - if (PCIBaseAddress->VendorID == 0x1022 && PCIBaseAddress->DeviceID == 0x2000) - { - trace("Found AMD PCNET."); - uint32_t PCIBAR = ((PCIHeader0 *)PCIBaseAddress)->BAR0; - BAR.Type = PCIBAR & 1; - BAR.IOBase = (uint16_t)(PCIBAR & (~3)); - BAR.MemoryBase = PCIBAR & (~15); - } - else - return DEVICE_NOT_SUPPORTED; - break; - } - case QueryReason: - { - memcpy(Data->NetworkCallback.Fetch.Name, (void *)"AMD PCNET", 10); - Data->NetworkCallback.Fetch.MAC = MAC.ToHex(); - break; - } - case SendReason: - { - break; - } - case StopReason: - { - // TODO: Stop the driver. - debug("Module stopped."); - break; - } - default: - { - warn("Unknown reason."); - break; - } - } - return OK; - } - - int InterruptCallback(CPURegisters *) - { - return OK; - } -} diff --git a/modules/AudioCodec97/AudioCodec97.cpp b/modules/AudioCodec97/AudioCodec97.cpp deleted file mode 100644 index bf7be3c..0000000 --- a/modules/AudioCodec97/AudioCodec97.cpp +++ /dev/null @@ -1,388 +0,0 @@ -/* - This file is part of Fennix Kernel. - - Fennix Kernel is free software: you can redistribute it and/or - modify it under the terms of the GNU General Public License as - published by the Free Software Foundation, either version 3 of - the License, or (at your option) any later version. - - Fennix Kernel is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Fennix Kernel. If not, see . -*/ - -#include "ac97.hpp" - -#include -#include -#include - -#include "../../mapi.hpp" -#include "../mod.hpp" - -using namespace PCI; - -namespace AudioCodec97 -{ - KernelAPI KAPI; - - /* https://wiki.osdev.org/AC97 */ - - PCIDeviceHeader *PCIBaseAddress; - BARData BAR; - BufferDescriptorList *DescriptorList = nullptr; - - AudioEncodingValues Encoding = AE_PCMs16le; - char Channels = 2; - uint8_t Volume = AV_Maximum; - bool Mute = false; - int SampleRate = 48000; - char SampleSize = 2; - - uint16_t MixerVolume(uint8_t Left, uint8_t Right, bool Mute) - { - return ((uint16_t)((Right & 0x3F) | - ((Left & 0x3F) << 0x8) | - (Mute & 1 << 0xF))); - } - - int DriverEntry(void *Data) - { - if (!Data) - return INVALID_KERNEL_API; - KAPI = *(KernelAPI *)Data; - if (KAPI.Version.Major < 0 || KAPI.Version.Minor < 0 || KAPI.Version.Patch < 0) - return KERNEL_API_VERSION_NOT_SUPPORTED; - - return OK; - } - - int CallbackHandler(KernelCallback *Data) - { - switch (Data->Reason) - { - case AcknowledgeReason: - { - debug("Kernel acknowledged the driver."); - break; - } - case ConfigurationReason: - { - debug("Module received configuration data."); - PCIBaseAddress = reinterpret_cast(Data->RawPtr); - PCIBaseAddress->Command |= PCI_COMMAND_MASTER | PCI_COMMAND_IO | PCI_COMMAND_MEMORY; - - /* Native Audio Mixer Base Address */ - uint32_t PCIBAR0 = ((PCIHeader0 *)PCIBaseAddress)->BAR0; - - /* Native Audio Bus Master Base Address */ - uint32_t PCIBAR1 = ((PCIHeader0 *)PCIBaseAddress)->BAR1; - - BAR.Type = PCIBAR0 & 1; - BAR.MixerAddress = (uint16_t)(PCIBAR0 & (~3)); - BAR.BusMasterAddress = PCIBAR1 & (~15); - - if (BAR.Type != 1) - { - error("BAR0 is not I/O."); - return INVALID_PCI_BAR; - } - uint16_t OutputPCMTransferControl = (uint16_t)(BAR.BusMasterAddress + PCMOUT_TransferControl); - - /* DescriptorList address MUST be physical. */ - DescriptorList = (BufferDescriptorList *)KAPI.Memory.RequestPage((sizeof(BufferDescriptorList) * DescriptorListLength) / KAPI.Memory.PageSize + 1); - memset(DescriptorList, 0, sizeof(BufferDescriptorList) * DescriptorListLength); - - uint16_t DLSampleCount = (uint16_t)(KAPI.Memory.PageSize / SampleSize); - for (int i = 0; i < DescriptorListLength; i++) - { - int DescriptorPages = (int)(sizeof(uint16_t *) / KAPI.Memory.PageSize + 1); - DescriptorList[i].Address = (uint32_t)(uint64_t)KAPI.Memory.RequestPage(DescriptorPages); - DescriptorList[i].SampleCount = DLSampleCount; - DescriptorList[i].Flags = 0; - debug("DescriptorList[%d] = { Address: 0x%x (%d %s), SampleCount: %d, Flags: 0x%x }", - i, - DescriptorList[i].Address, DescriptorPages, DescriptorPages == 1 ? "page" : "pages", - DescriptorList[i].SampleCount, - DescriptorList[i].Flags); - } - - outw(BAR.MixerAddress + NAM_MasterVolume, MixerVolume(Volume, Volume, Mute)); - outw(BAR.MixerAddress + NAM_PCMOutVolume, MixerVolume(Volume, Volume, Mute)); - - outb(OutputPCMTransferControl, inb(OutputPCMTransferControl) | TC_TransferReset); - while (inb(OutputPCMTransferControl) & TC_TransferReset) - ; - - uint32_t GlobalControl = inl((uint16_t)(BAR.BusMasterAddress + NABM_GlobalControl)); - GlobalControl = (GlobalControl & ~((0x3U) << 22)); /* PCM 16-bit mode */ - GlobalControl = (GlobalControl & ~((0x3U) << 20)); /* 2 channels */ - GlobalControl |= GC_GlobalInterruptEnable; - GlobalControl &= ~GC_ShutDown; - - outl((uint16_t)(BAR.BusMasterAddress + PCMOUT_BufferDescriptorList), (uint32_t)(uint64_t)DescriptorList); - outl((uint16_t)(BAR.BusMasterAddress + NABM_GlobalControl), GlobalControl); - - uint8_t TransferControl = inb(OutputPCMTransferControl); - TransferControl |= TC_LastBufferEntryInterruptEnable | TC_IOCInterruptEnable | TC_FifoERRORInterruptEnable; - outb(OutputPCMTransferControl, TransferControl); - - // Stop DMA - outb(OutputPCMTransferControl, inb(OutputPCMTransferControl) & ~TC_DMAControllerControl); - debug("AC'97 configured."); - break; - } - case AdjustReason: - { - if (Data->AudioCallback.Adjust._Volume) - { - Volume = (uint8_t)(0x3F - (0x3F * Data->AudioCallback.Adjust.Volume / 100)); - outw(BAR.MixerAddress + NAM_MasterVolume, MixerVolume(Volume, Volume, Mute)); - // outw(BAR.MixerAddress + NAM_PCMOutVolume, MixerVolume(Volume, Volume, Mute)); - } - else if (Data->AudioCallback.Adjust._Encoding) - { - fixme("Encoding changing not supported yet."); - } - else if (Data->AudioCallback.Adjust._SampleRate) - { - switch (Data->AudioCallback.Adjust.SampleRate) - { - case 0: - { - SampleRate = 8000; - break; - } - case 1: - { - SampleRate = 11025; - break; - } - case 2: - { - SampleRate = 16000; - break; - } - case 3: - { - SampleRate = 22050; - break; - } - case 4: - { - SampleRate = 32000; - break; - } - case 5: - { - SampleRate = 44100; - break; - } - case 6: - { - SampleRate = 48000; - break; - } - case 7: - { - SampleRate = 88200; - break; - } - case 8: - { - SampleRate = 96000; - break; - } - default: - { - SampleRate = 16000; - error("Invalid sample rate. Defaulting to 16000."); - break; - } - } - } - else if (Data->AudioCallback.Adjust._Channels) - { - switch (Data->AudioCallback.Adjust.Channels) - { - case 0: - { - Channels = 1; // Mono - break; - } - case 1: - { - Channels = 2; // Stereo - break; - } - default: - { - Channels = 2; - error("Invalid channel count. Defaulting to 2."); - break; - } - } - } - break; - } - case QueryReason: - { - Data->AudioCallback.Fetch.Volume = (unsigned char)((inw(BAR.MixerAddress + NAM_MasterVolume) & 0x3F) * 100 / 0x3F); - Data->AudioCallback.Fetch.Encoding = Encoding; /* FIXME */ - // Data->AudioCallback.Fetch.SampleRate = SampleRate; /* FIXME */ - Data->AudioCallback.Fetch.Channels = Channels; - break; - } - case SendReason: - { - unsigned char *Buffer = (unsigned char *)Data->AudioCallback.Send.Data; - unsigned int Length = (unsigned int)Data->AudioCallback.Send.Length; - - if (Buffer == nullptr) - { - error("Invalid buffer."); - return INVALID_DATA; - } - - if ((Length == 0) || (Length % (SampleSize * Channels))) - { - error("Invalid buffer length."); - return INVALID_DATA; - } - - int TotalBDLToFill = (int)((Length + KAPI.Memory.PageSize - 1) >> 12); - - while (Length > 0) - { - bool ActiveDMA = !(inw((uint16_t)(BAR.BusMasterAddress + PCMOUT_Status)) & TC_DMAControllerControl); - - if (ActiveDMA) - { - int RemainingBDL = 0; - - do - { - int CurrentBDL = inb((uint16_t)(BAR.BusMasterAddress + PCMOUT_BufferDescriptorEntry)); - int LastBDL = inb((uint16_t)(BAR.BusMasterAddress + PCMOUT_DescriptorEntries)); - - RemainingBDL = LastBDL - CurrentBDL; - if (RemainingBDL < 0) - RemainingBDL += DescriptorListLength; - - RemainingBDL += 1; - - if (RemainingBDL >= DescriptorListLength - 1) - { - long SampleCount = DescriptorList[(CurrentBDL + 1) % DescriptorListLength].SampleCount / Channels; - if (SampleCount > 0) - KAPI.Util.Sleep(SampleCount * 1000 / SampleRate); // milliseconds - } - - } while (RemainingBDL >= DescriptorListLength - 1 && !(inw((uint16_t)(BAR.BusMasterAddress + PCMOUT_Status)) & TC_DMAControllerControl)); - } - - { - uint8_t CurrentBDL = inb((uint16_t)(BAR.BusMasterAddress + PCMOUT_BufferDescriptorEntry)); - uint8_t LastBDL = inb((uint16_t)(BAR.BusMasterAddress + PCMOUT_DescriptorEntries)); - uint8_t NextBDL = LastBDL % DescriptorListLength; - - ActiveDMA = !(inw((uint16_t)(BAR.BusMasterAddress + PCMOUT_Status)) & TC_DMAControllerControl); - if (ActiveDMA) - { - NextBDL = (uint8_t)((LastBDL + 1) % DescriptorListLength); - if (NextBDL == CurrentBDL) - continue; - } - - do - { - size_t Wrote = (KAPI.Memory.PageSize > Length) ? size_t(Length) - : size_t(KAPI.Memory.PageSize); - - if (Wrote == 0) - break; - memcpy((void *)((uint64_t)DescriptorList[NextBDL].Address), Buffer, Wrote); - DescriptorList[NextBDL].Flags = 0; - - Buffer += Wrote; - Length -= (unsigned int)Wrote; - - DescriptorList[NextBDL].SampleCount = (uint16_t)(Wrote / SampleSize); - TotalBDLToFill--; - NextBDL = (uint8_t)((NextBDL + 1) % DescriptorListLength); - } while (TotalBDLToFill-- && NextBDL != CurrentBDL); - - outb((uint16_t)(BAR.BusMasterAddress + PCMOUT_DescriptorEntries), NextBDL - 1); - - ActiveDMA = !(inw((uint16_t)(BAR.BusMasterAddress + PCMOUT_Status)) & TC_DMAControllerControl); - if (!ActiveDMA) - { - // Start DMA - outb((uint16_t)(BAR.BusMasterAddress + PCMOUT_TransferControl), inb((uint16_t)(BAR.BusMasterAddress + PCMOUT_TransferControl) | TC_DMAControllerControl)); - } - } - } - break; - } - case StopReason: - { - outw(BAR.MixerAddress + NAM_MasterVolume, MixerVolume(AV_Maximum, AV_Maximum, true)); - outw(BAR.MixerAddress + NAM_PCMOutVolume, MixerVolume(AV_Maximum, AV_Maximum, true)); - - // Stop DMA - outb((uint16_t)(BAR.BusMasterAddress + PCMOUT_TransferControl), inb((uint16_t)(BAR.BusMasterAddress + PCMOUT_TransferControl)) & ~TC_DMAControllerControl); - - // Disable interrupts - uint8_t TransferControl = inb((uint16_t)(BAR.BusMasterAddress + PCMOUT_TransferControl)); - TransferControl &= ~(TC_LastBufferEntryInterruptEnable | TC_IOCInterruptEnable | TC_FifoERRORInterruptEnable); - outb((uint16_t)(BAR.BusMasterAddress + PCMOUT_TransferControl), TransferControl); - - // Disable global control - uint32_t GlobalControl = inl((uint16_t)(BAR.BusMasterAddress + NABM_GlobalControl)); - GlobalControl &= ~GC_GlobalInterruptEnable; - GlobalControl |= GC_ShutDown; - outl((uint16_t)(BAR.BusMasterAddress + NABM_GlobalControl), GlobalControl); - - debug("Module stopped."); - break; - } - default: - { - warn("Unknown reason."); - break; - } - } - return OK; - } - - int InterruptCallback(CPURegisters *) - { - uint16_t Status = inw(BAR.MixerAddress + PCMOUT_Status); - - if (Status & TC_IOCInterruptEnable) - { - debug("Interrupt on completion."); - } - else if (Status & TC_LastBufferEntryInterruptEnable) - { - debug("Last buffer entry."); - // Stop DMA - outb((uint16_t)(BAR.BusMasterAddress + PCMOUT_TransferControl), inb((uint16_t)(BAR.BusMasterAddress + PCMOUT_TransferControl)) & ~TC_DMAControllerControl); - } - else if (Status & TC_FifoERRORInterruptEnable) - { - debug("FIFO error."); - } - else if (Status != 0x0) - { - error("Unknown status: %#lx", Status); - } - - outw(BAR.MixerAddress + PCMOUT_Status, 0xFFFF); - return OK; - } -} diff --git a/modules/AudioCodec97/ac97.hpp b/modules/AudioCodec97/ac97.hpp deleted file mode 100644 index b6d1ad4..0000000 --- a/modules/AudioCodec97/ac97.hpp +++ /dev/null @@ -1,348 +0,0 @@ -/* - This file is part of Fennix Kernel. - - Fennix Kernel is free software: you can redistribute it and/or - modify it under the terms of the GNU General Public License as - published by the Free Software Foundation, either version 3 of - the License, or (at your option) any later version. - - Fennix Kernel is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Fennix Kernel. If not, see . -*/ - -#ifndef __FENNIX_KERNEL_AC97_H__ -#define __FENNIX_KERNEL_AC97_H__ - -#include -#include "../../mapi.hpp" - -namespace AudioCodec97 -{ -#define DescriptorListLength 0x20 - - enum AudioVolumeValues - { - AV_Maximum = 0x0, - AV_Minimum = 0x3F, - }; - - enum AudioEncodingValues - { - AE_PCMs8, - AE_PCMu8, - - AE_PCMs16le, - AE_PCMs20le, - AE_PCMs24le, - AE_PCMs32le, - - AE_PCMu16le, - AE_PCMu20le, - AE_PCMu24le, - AE_PCMu32le, - - AE_PCMs16be, - AE_PCMs20be, - AE_PCMs24be, - AE_PCMs32be, - - AE_PCMu16be, - AE_PCMu20be, - AE_PCMu24be, - AE_PCMu32be, - }; - - enum NativeAudioMixerRegisters - { - /** - * @brief Reset Register - * @note Length: word - */ - NAM_Reset = 0x00, - - /** - * @brief Master Volume Register - * @note Length: word - */ - NAM_MasterVolume = 0x02, - - /** - * @brief Microphone Volume Register - * @note Length: word - */ - NAM_MicrophoneVolume = 0x0E, - - /** - * @brief PCM Out Volume Register - * @note Length: word - */ - NAM_PCMOutVolume = 0x18, - - /** - * @brief Select Record Input Register - * @note Length: word - */ - NAM_SelectRecordInput = 0x1A, - - /** - * @brief Record Gain Register - * @note Length: word - */ - NAM_RecordGain = 0x1C, - - /** - * @brief Record Gain Microphone Register - * @note Length: word - */ - NAM_RecordGainMicrophone = 0x1E, - }; - - enum NativeAudioBusMasterRegisters - { - /** - * @brief Register box for PCM IN - * @note Length: below - */ - NABM_PCMInBox = 0x00, - - /** - * @brief Register box for PCM OUT - * @note Length: below - */ - NABM_PCMOutBox = 0x10, - - /** - * @brief Register box for Microphone - * @note Length: below - */ - NABM_MicrophoneBox = 0x20, - - /** - * @brief Global Control Register - * @note Length: dword - */ - NABM_GlobalControl = 0x2C, /* 0x30 */ - - /** - * @brief Global Status Register - * @note Length: dword - */ - NABM_GlobalStatus = 0x30, /* 0x34 */ - }; - - enum NativeAudioBusMasterBoxOffsets - { - /** - * @brief Physical Address of Buffer Descriptor List - * @note Length: dword - */ - NABMBOFF_BufferDescriptorList = 0x00, - - /** - * @brief Number of Actual Processed Buffer Descriptor Entry - * @note Length: byte - */ - NABMBOFF_BufferDescriptorEntry = 0x04, - - /** - * @brief Number of all Descriptor Entries - * @note Length: byte - */ - NABMBOFF_DescriptorEntries = 0x05, - - /** - * @brief Status of transferring Data - * @note Length: word - */ - NABMBOFF_Status = 0x06, - - /** - * @brief Number of transferred Samples in Actual Processed Entry - * @note Length: word - */ - NABMBOFF_TransferredSamples = 0x08, - - /** - * @brief Number of next processed Buffer Entry - * @note Length: byte - */ - NABMBOFF_NextProcessedBufferEntry = 0x0A, - - /** - * @brief Transfer Control - * @note Length: byte - */ - NABMBOFF_TransferControl = 0x0B, - }; - - enum OutputPulseCodeModulationRegisters - { - /** - * @brief Physical Address of Buffer Descriptor List - * @note Length: dword - */ - PCMOUT_BufferDescriptorList = (int)NABM_PCMOutBox + (int)NABMBOFF_BufferDescriptorList, - - /** - * @brief Number of Actual Processed Buffer Descriptor Entry - * @note Length: byte - */ - PCMOUT_BufferDescriptorEntry = (int)NABM_PCMOutBox + (int)NABMBOFF_BufferDescriptorEntry, - - /** - * @brief Number of all Descriptor Entries - * @note Length: byte - */ - PCMOUT_DescriptorEntries = (int)NABM_PCMOutBox + (int)NABMBOFF_DescriptorEntries, - - /** - * @brief Status of transferring Data - * @note Length: word - */ - PCMOUT_Status = (int)NABM_PCMOutBox + (int)NABMBOFF_Status, - - /** - * @brief Number of transferred Samples in Actual Processed Entry - * @note Length: word - */ - PCMOUT_TransferredSamples = (int)NABM_PCMOutBox + (int)NABMBOFF_TransferredSamples, - - /** - * @brief Number of next processed Buffer Entry - * @note Length: byte - */ - PCMOUT_NextProcessedBufferEntry = (int)NABM_PCMOutBox + (int)NABMBOFF_NextProcessedBufferEntry, - - /** - * @brief Transfer Control - * @note Length: byte - */ - PCMOUT_TransferControl = (int)NABM_PCMOutBox + (int)NABMBOFF_TransferControl, - }; - - enum TransferControlRegisters - { - /** - * @brief DMA controller control - * 0 = Pause transfer - * 1 = Transfer sound data - */ - TC_DMAControllerControl = 0x01, - - /** - * @brief Reset - * 0 = Remove reset condition - * 1 = Reset this NABM register box, this bit is cleared by card when is reset complete - */ - TC_TransferReset = 0x02, - - /** - * @brief Last Buffer Entry Interrupt enable - * 0 = Disable interrupt - * 1 = Enable interrupt - */ - TC_LastBufferEntryInterruptEnable = 0x04, - - /** - * @brief IOC Interrupt enable - * 0 = Disable interrupt - * 1 = Enable interrupt - */ - TC_IOCInterruptEnable = 0x08, - - /** - * @brief Fifo ERROR Interrupt enable - * 0 = Disable interrupt - * 1 = Enable interrupt - */ - TC_FifoERRORInterruptEnable = 0x10, - }; - - enum GlobalControlRegisters - { - /** - * @brief Global Interrupt Enable - * 0 = Disable Interrupts - * 1 = Enable Interrupts - */ - GC_GlobalInterruptEnable = 0x01, - - /** - * @brief Cold reset - * 0 = Device is in reset and can not be used - * 1 = Resume to operational state - */ - GC_ColdReset = 0x02, - - /** - * @brief Warm reset - */ - GC_WarmReset = 0x04, - - /** - * @brief Shut down - * 0 = Device is powered - * 1 = Shut down - */ - GC_ShutDown = 0x08, - - /** - * @brief Channels for PCM Output - * 00 = 2 channels - * 01 = 4 channels - * 10 = 6 channels - * 11 = Reserved - */ - GC_ChannelsForPCMOutput = 0x30, - - /** - * @brief PCM Output mode - * 00 = 16 bit samples - * 01 = 20 bit samples - */ - GC_PCMOutputMode = 0xC0, - }; - - struct BufferDescriptorList - { - /** - * @brief Physical Address to sound data in memory - * @note Length: dword - */ - uint32_t Address; - - /** - * @brief Number of samples in this buffer - * @note Length: word - */ - uint16_t SampleCount; - - /** - * @brief Flags - * @note Length: word - * - * Bit 15 = Interrupt fired when data from this entry is transferred - * Bit 14 = Last entry of buffer, stop playing - * Other bits = Reserved - */ - uint16_t Flags; - } __attribute__((packed)); - - struct BARData - { - uint8_t Type; - uint16_t MixerAddress; - uint64_t BusMasterAddress; - }; - - int DriverEntry(void *); - int CallbackHandler(KernelCallback *); - int InterruptCallback(CPURegisters *); -} - -#endif // !__FENNIX_KERNEL_AC97_H__ diff --git a/modules/Intel/Gigabit.cpp b/modules/Intel/Gigabit.cpp deleted file mode 100644 index ffb4c83..0000000 --- a/modules/Intel/Gigabit.cpp +++ /dev/null @@ -1,394 +0,0 @@ -/* - This file is part of Fennix Kernel. - - Fennix Kernel is free software: you can redistribute it and/or - modify it under the terms of the GNU General Public License as - published by the Free Software Foundation, either version 3 of - the License, or (at your option) any later version. - - Fennix Kernel is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Fennix Kernel. If not, see . -*/ - -#include "gigabit.hpp" - -#include -#include -#include -#include - -#include "../../mapi.hpp" -#include "../mod.hpp" - -using namespace PCI; - -namespace Gigabit -{ - KernelAPI KAPI; - - PCIDeviceHeader *PCIBaseAddress; - uint32_t CurrentPacket; - BARData BAR; - bool EEPROMAvailable; - - uint16_t RXCurrent; - uint16_t TXCurrent; - RXDescriptor *RX[E1000_NUM_RX_DESC]; - TXDescriptor *TX[E1000_NUM_TX_DESC]; - - MediaAccessControl MAC; - InternetProtocol::Version4 IP; - - void WriteCMD(uint16_t Address, uint32_t Value) - { - if (BAR.Type == 0) - mmioout32(BAR.MemoryBase + Address, Value); - else - { - outportl(BAR.IOBase, Address); - outportl(BAR.IOBase + 4, Value); - } - } - - uint32_t ReadCMD(uint16_t Address) - { - if (BAR.Type == 0) - return mmioin32(BAR.MemoryBase + Address); - else - { - outportl(BAR.IOBase, Address); - return inportl(BAR.IOBase + 0x4); - } - } - - uint32_t ReadEEPROM(uint8_t Address) - { - uint16_t Data = 0; - uint32_t temp = 0; - if (EEPROMAvailable) - { - WriteCMD(REG::EEPROM, (1) | ((uint32_t)(Address) << 8)); - while (!((temp = ReadCMD(REG::EEPROM)) & (1 << 4))) - ; - } - else - { - WriteCMD(REG::EEPROM, (1) | ((uint32_t)(Address) << 2)); - while (!((temp = ReadCMD(REG::EEPROM)) & (1 << 1))) - ; - } - Data = (uint16_t)((temp >> 16) & 0xFFFF); - return Data; - } - - MediaAccessControl GetMAC() - { - MediaAccessControl mac; - if (EEPROMAvailable) - { - uint32_t temp; - temp = ReadEEPROM(0); - mac.Address[0] = temp & 0xff; - mac.Address[1] = (uint8_t)(temp >> 8); - temp = ReadEEPROM(1); - mac.Address[2] = temp & 0xff; - mac.Address[3] = (uint8_t)(temp >> 8); - temp = ReadEEPROM(2); - mac.Address[4] = temp & 0xff; - mac.Address[5] = (uint8_t)(temp >> 8); - } - else - { - uint8_t *BaseMac8 = (uint8_t *)(BAR.MemoryBase + 0x5400); - uint32_t *BaseMac32 = (uint32_t *)(BAR.MemoryBase + 0x5400); - if (BaseMac32[0] != 0) - for (int i = 0; i < 6; i++) - mac.Address[i] = BaseMac8[i]; - else - { - error("No MAC address found."); - return MediaAccessControl(); - } - } - return mac; - } - - void InitializeRX() - { - debug("Initializing RX..."); - uintptr_t Ptr = (uintptr_t)KAPI.Memory.RequestPage((((sizeof(RXDescriptor) * E1000_NUM_RX_DESC + 16)) / KAPI.Memory.PageSize) + 1); - - for (int i = 0; i < E1000_NUM_RX_DESC; i++) - { - RX[i] = (RXDescriptor *)(Ptr + i * 16); - RX[i]->Address = (uint64_t)(uintptr_t)KAPI.Memory.RequestPage(((8192 + 16) / KAPI.Memory.PageSize) + 1); - RX[i]->Status = 0; - } - -#pragma GCC diagnostic ignored "-Wshift-count-overflow" - - WriteCMD(REG::TXDESCLO, (uint32_t)(Ptr >> 32)); - WriteCMD(REG::TXDESCHI, (uint32_t)(Ptr & 0xFFFFFFFF)); - - WriteCMD(REG::RXDESCLO, (uint32_t)Ptr); - WriteCMD(REG::RXDESCHI, 0); - - WriteCMD(REG::RXDESCLEN, E1000_NUM_RX_DESC * 16); - - WriteCMD(REG::RXDESCHEAD, 0); - WriteCMD(REG::RXDESCTAIL, E1000_NUM_RX_DESC - 1); - RXCurrent = 0; - WriteCMD(REG::RCTRL, RCTL::EN | RCTL::SBP | RCTL::UPE | RCTL::MPE | RCTL::LBM_NONE | RTCL::RDMTS_HALF | RCTL::BAM | RCTL::SECRC | RCTL::BSIZE_8192); - } - - void InitializeTX() - { - debug("Initializing TX..."); - uintptr_t Ptr = (uintptr_t)KAPI.Memory.RequestPage(((sizeof(TXDescriptor) * E1000_NUM_RX_DESC + 16) / KAPI.Memory.PageSize) + 1); - - for (short i = 0; i < E1000_NUM_TX_DESC; i++) - { - TX[i] = (TXDescriptor *)((uintptr_t)Ptr + i * 16); - TX[i]->Address = 0; - TX[i]->Command = 0; - TX[i]->Status = TSTA::DD; - } - - WriteCMD(REG::TXDESCHI, (uint32_t)((uint64_t)Ptr >> 32)); - WriteCMD(REG::TXDESCLO, (uint32_t)((uint64_t)Ptr & 0xFFFFFFFF)); - - WriteCMD(REG::TXDESCLEN, E1000_NUM_TX_DESC * 16); - - WriteCMD(REG::TXDESCHEAD, 0); - WriteCMD(REG::TXDESCTAIL, 0); - TXCurrent = 0; - WriteCMD(REG::TCTRL, TCTL::EN_ | TCTL::PSP | (15 << TCTL::CT_SHIFT) | (64 << TCTL::COLD_SHIFT) | TCTL::RTLC); - - WriteCMD(REG::TCTRL, 0b0110000000000111111000011111010); - WriteCMD(REG::TIPG, 0x0060200A); - } - - int DriverEntry(void *Data) - { - if (!Data) - return INVALID_KERNEL_API; - KAPI = *(KernelAPI *)Data; - if (KAPI.Version.Major < 0 || KAPI.Version.Minor < 0 || KAPI.Version.Patch < 0) - return KERNEL_API_VERSION_NOT_SUPPORTED; - return OK; - } - - int CallbackHandler(KernelCallback *Data) - { - switch (Data->Reason) - { - case AcknowledgeReason: - { - debug("Kernel acknowledged the driver."); - break; - } - case ConfigurationReason: - { - debug("Module received configuration data."); - PCIBaseAddress = reinterpret_cast(Data->RawPtr); - switch (PCIBaseAddress->DeviceID) - { - case 0x100E: - { - trace("Found Intel 82540EM Gigabit Ethernet Controller."); - - PCIBaseAddress->Command |= PCI_COMMAND_MASTER | PCI_COMMAND_IO | PCI_COMMAND_MEMORY; - uint32_t PCIBAR0 = ((PCIHeader0 *)PCIBaseAddress)->BAR0; - uint32_t PCIBAR1 = ((PCIHeader0 *)PCIBaseAddress)->BAR1; - - BAR.Type = PCIBAR0 & 1; - BAR.IOBase = (uint16_t)(PCIBAR1 & (~3)); - BAR.MemoryBase = PCIBAR0 & (~15); - - // Detect EEPROM - WriteCMD(REG::EEPROM, 0x1); - for (int i = 0; i < 1000 && !EEPROMAvailable; i++) - if (ReadCMD(REG::EEPROM) & 0x10) - EEPROMAvailable = true; - else - EEPROMAvailable = false; - - // Get MAC address - if (!GetMAC().Valid()) - return NOT_AVAILABLE; - else - { - debug("MAC address found."); - } - MAC = GetMAC(); - - // Start link - uint32_t cmdret = ReadCMD(REG::CTRL); - WriteCMD(REG::CTRL, cmdret | ECTRL::SLU); - - for (int i = 0; i < 0x80; i++) - WriteCMD((uint16_t)(0x5200 + i * 4), 0); - - WriteCMD(REG::IMASK, 0x1F6DC); - WriteCMD(REG::IMASK, 0xFF & ~4); - ReadCMD(0xC0); - - InitializeRX(); - InitializeTX(); - return OK; - } - case 0x100F: - { - trace("Found Intel 82545EM Gigabit Ethernet Controller."); - PCIBaseAddress->Command |= PCI_COMMAND_MASTER | PCI_COMMAND_IO | PCI_COMMAND_MEMORY; - uint32_t PCIBAR0 = ((PCIHeader0 *)PCIBaseAddress)->BAR0; - uint32_t PCIBAR1 = ((PCIHeader0 *)PCIBaseAddress)->BAR1; - - BAR.Type = PCIBAR0 & 1; - BAR.IOBase = (uint16_t)(PCIBAR1 & (~3)); - BAR.MemoryBase = PCIBAR0 & (~15); - - // Detect EEPROM - WriteCMD(REG::EEPROM, 0x1); - for (int i = 0; i < 1000 && !EEPROMAvailable; i++) - if (ReadCMD(REG::EEPROM) & 0x10) - EEPROMAvailable = true; - else - EEPROMAvailable = false; - - // Get MAC address - if (!GetMAC().Valid()) - return NOT_AVAILABLE; - else - { - debug("MAC address found."); - } - MAC = GetMAC(); - - return NOT_IMPLEMENTED; - } - case 0x10D3: - { - trace("Found Intel 82574L Gigabit Ethernet Controller."); - - PCIBaseAddress->Command |= PCI_COMMAND_MASTER | PCI_COMMAND_IO | PCI_COMMAND_MEMORY; - uint32_t PCIBAR0 = ((PCIHeader0 *)PCIBaseAddress)->BAR0; - uint32_t PCIBAR1 = ((PCIHeader0 *)PCIBaseAddress)->BAR1; - - BAR.Type = PCIBAR0 & 1; - BAR.IOBase = (uint16_t)(PCIBAR1 & (~3)); - BAR.MemoryBase = PCIBAR0 & (~15); - - // Detect EEPROM - WriteCMD(REG::EEPROM, 0x1); - for (int i = 0; i < 1000 && !EEPROMAvailable; i++) - if (ReadCMD(REG::EEPROM) & 0x10) - EEPROMAvailable = true; - else - EEPROMAvailable = false; - - // Get MAC address - if (!GetMAC().Valid()) - return NOT_AVAILABLE; - else - { - debug("MAC address found."); - } - MAC = GetMAC(); - - return NOT_IMPLEMENTED; - } - case 0x10EA: - { - fixme("Found Intel I217-LM Gigabit Ethernet Controller."); - return NOT_IMPLEMENTED; - } - case 0x153A: - { - fixme("Found Intel 82577LM Gigabit Ethernet Controller."); - return NOT_IMPLEMENTED; - } - default: - { - error("Unsupported Intel Ethernet Controller."); - return DEVICE_NOT_SUPPORTED; - } - } - return ERROR; - } - case QueryReason: - { - memcpy(Data->NetworkCallback.Fetch.Name, (void *)"Intel Gigabit Ethernet Controller", 34); - Data->NetworkCallback.Fetch.MAC = MAC.ToHex(); - break; - } - case SendReason: - { - TX[TXCurrent]->Address = (uint64_t)Data->NetworkCallback.Send.Data; - TX[TXCurrent]->Length = (uint16_t)Data->NetworkCallback.Send.Length; - TX[TXCurrent]->Command = CMD::EOP | CMD::IFCS | CMD::RS; - TX[TXCurrent]->Status = 0; - uint16_t OldTXCurrent = TXCurrent; - TXCurrent = (uint16_t)((TXCurrent + 1) % E1000_NUM_TX_DESC); - WriteCMD(REG::TXDESCTAIL, TXCurrent); - while (!(TX[OldTXCurrent]->Status & 0xFF)) - ; - break; - } - case StopReason: - { - // Clearing Enable bit in Receive Control Register - uint32_t cmdret = ReadCMD(REG::RCTRL); - WriteCMD(REG::RCTRL, cmdret & ~RCTL::EN); - - // Masking Interrupt Mask, Interrupt Throttling Rate & Interrupt Auto-Mask - WriteCMD(REG::IMASK, 0x00000000); - WriteCMD(REG::ITR, 0x00000000); - WriteCMD(REG::IAM, 0x00000000); - - // Clearing SLU bit in Device Control Register - cmdret = ReadCMD(REG::CTRL); - WriteCMD(REG::CTRL, cmdret & ~ECTRL::SLU); - - // Clear the Interrupt Cause Read register by reading it - ReadCMD(REG::ICR); - - // Powering down the device (?) - WriteCMD(REG::CTRL, PCTRL::POWER_DOWN); - /* TODO: Stop link; further testing required */ - debug("Module stopped."); - break; - } - default: - { - warn("Unknown reason."); - break; - } - } - return OK; - } - - int InterruptCallback(CPURegisters *) - { - WriteCMD(REG::IMASK, 0x1); - uint32_t status = ReadCMD(0xC0); - UNUSED(status); - - while ((RX[RXCurrent]->Status & 0x1)) - { - uint8_t *Data = (uint8_t *)RX[RXCurrent]->Address; - uint16_t DataLength = RX[RXCurrent]->Length; - KAPI.Command.Network.ReceivePacket(KAPI.Info.modUniqueID, Data, DataLength); - RX[RXCurrent]->Status = 0; - uint16_t OldRXCurrent = RXCurrent; - RXCurrent = (uint16_t)((RXCurrent + 1) % E1000_NUM_RX_DESC); - WriteCMD(REG::RXDESCTAIL, OldRXCurrent); - } - return OK; - } -} diff --git a/modules/Intel/gigabit.hpp b/modules/Intel/gigabit.hpp deleted file mode 100644 index 24d449e..0000000 --- a/modules/Intel/gigabit.hpp +++ /dev/null @@ -1,177 +0,0 @@ -/* - This file is part of Fennix Kernel. - - Fennix Kernel is free software: you can redistribute it and/or - modify it under the terms of the GNU General Public License as - published by the Free Software Foundation, either version 3 of - the License, or (at your option) any later version. - - Fennix Kernel is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Fennix Kernel. If not, see . -*/ - -#ifndef __FENNIX_KERNEL_INTEL_GIGABIT_H__ -#define __FENNIX_KERNEL_INTEL_GIGABIT_H__ - -#include -#include "../../mapi.hpp" - -namespace Gigabit -{ -#define E1000_NUM_RX_DESC 32 -#define E1000_NUM_TX_DESC 8 - - enum REG - { - CTRL = 0x0000, - STATUS = 0x0008, - ICR = 0x000C, - EEPROM = 0x0014, - CTRL_EXT = 0x0018, - ITR = 0x00C4, - IMASK = 0x00D0, - IAM = 0x00D8, - RCTRL = 0x0100, - RXDESCLO = 0x2800, - RXDESCHI = 0x2804, - RXDESCLEN = 0x2808, - RXDESCHEAD = 0x2810, - RXDESCTAIL = 0x2818, - TCTRL = 0x0400, - TXDESCLO = 0x3800, - TXDESCHI = 0x3804, - TXDESCLEN = 0x3808, - TXDESCHEAD = 0x3810, - TXDESCTAIL = 0x3818, - RDTR = 0x2820, - RXDCTL = 0x3828, - RADV = 0x282C, - RSRPD = 0x2C00, - TIPG = 0x0410 - }; - - enum PCTRL - { - RESERVED = 0b000000, // bits 5:0 - SPEED_SELECTION_MSB = 0b010000, // bit 6 - UPDATE_COLLISION_TEST = 0b001000, // bit 7 - DUPLEX_MODE = 0b000100, // bit 8 - RESTART_AUTO_NEGOTIATION = 0b000010, // bit 9 - ISOLATE = 0b000001, // bit 10 - POWER_DOWN = 0b100000, // bit 11 - SPEED_SELECTION_LSB = 0b100000, // bit 13 - }; - - enum ECTRL - { - SLU = 0x40 - }; - - enum RTCL - { - RDMTS_HALF = (0 << 8), - RDMTS_QUARTER = (1 << 8), - RDMTS_EIGHTH = (2 << 8) - }; - - enum RCTL - { - EN = (1 << 1), - SBP = (1 << 2), - UPE = (1 << 3), - MPE = (1 << 4), - LPE = (1 << 5), - LBM_NONE = (0 << 6), - LBM_PHY = (3 << 6), - MO_36 = (0 << 12), - MO_35 = (1 << 12), - MO_34 = (2 << 12), - MO_32 = (3 << 12), - BAM = (1 << 15), - VFE = (1 << 18), - CFIEN = (1 << 19), - CFI = (1 << 20), - DPF = (1 << 22), - PMCF = (1 << 23), - SECRC = (1 << 26), - BSIZE_256 = (3 << 16), - BSIZE_512 = (2 << 16), - BSIZE_1024 = (1 << 16), - BSIZE_2048 = (0 << 16), - BSIZE_4096 = ((3 << 16) | (1 << 25)), - BSIZE_8192 = ((2 << 16) | (1 << 25)), - BSIZE_16384 = ((1 << 16) | (1 << 25)) - }; - - enum CMD - { - EOP = (1 << 0), - IFCS = (1 << 1), - IC = (1 << 2), - RS = (1 << 3), - RPS = (1 << 4), - VLE = (1 << 6), - IDE = (1 << 7) - }; - - enum TCTL - { - EN_ = (1 << 1), - PSP = (1 << 3), - CT_SHIFT = 4, - COLD_SHIFT = 12, - SWXOFF = (1 << 22), - RTLC = (1 << 24) - }; - - enum TSTA - { - DD = (1 << 0), - EC = (1 << 1), - LC = (1 << 2) - }; - - enum LSTA - { - LSTA_TU = (1 << 3) - }; - - struct RXDescriptor - { - volatile uint64_t Address; - volatile uint16_t Length; - volatile uint16_t Checksum; - volatile uint8_t Status; - volatile uint8_t Errors; - volatile uint16_t Special; - } __attribute__((packed)); - - struct TXDescriptor - { - volatile uint64_t Address; - volatile uint16_t Length; - volatile uint8_t cso; - volatile uint8_t Command; - volatile uint8_t Status; - volatile uint8_t css; - volatile uint16_t Special; - } __attribute__((packed)); - - struct BARData - { - uint8_t Type; - uint16_t IOBase; - uint64_t MemoryBase; - }; - - int DriverEntry(void *); - int CallbackHandler(KernelCallback *); - int InterruptCallback(CPURegisters *); -} - -#endif // !__FENNIX_KERNEL_INTEL_GIGABIT_H__ diff --git a/modules/PersonalSystem2/Keyboard.cpp b/modules/PersonalSystem2/Keyboard.cpp deleted file mode 100644 index e41f40a..0000000 --- a/modules/PersonalSystem2/Keyboard.cpp +++ /dev/null @@ -1,227 +0,0 @@ -/* - This file is part of Fennix Kernel. - - Fennix Kernel is free software: you can redistribute it and/or - modify it under the terms of the GNU General Public License as - published by the Free Software Foundation, either version 3 of - the License, or (at your option) any later version. - - Fennix Kernel is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Fennix Kernel. If not, see . -*/ - -#include "keyboard.hpp" - -#include -#include -#include - -#include "../../mapi.hpp" -#include "../mod.hpp" -#include "../../kernel.h" - -namespace PS2Keyboard -{ - KernelAPI KAPI; - - uint8_t ScanCode = 0; - bool InputReceived = false; - - void PS2Wait(bool Read) - { - int Timeout = 100000; - uint8_t Status = 0; - while (Timeout--) - { - Status = inb(0x64); - if (Read) - { - if ((Status & 1) == 1) - return; - } - else - { - if ((Status & 2) == 0) - return; - } - } - } - - int DriverEntry(void *Data) - { - if (!Data) - return INVALID_KERNEL_API; - KAPI = *(KernelAPI *)Data; - if (KAPI.Version.Major < 0 || KAPI.Version.Minor < 0 || KAPI.Version.Patch < 0) - return KERNEL_API_VERSION_NOT_SUPPORTED; - - return OK; - } - - int CallbackHandler(KernelCallback *Data) - { - switch (Data->Reason) - { - case AcknowledgeReason: - { - debug("Kernel acknowledged the driver."); - break; - } - case ConfigurationReason: - { -#define WaitRead PS2Wait(true) -#define WaitWrite PS2Wait(false) - - WaitWrite; - outb(0x64, 0xAD); - WaitWrite; - outb(0x64, 0xA7); - - WaitRead; - inb(0x60); - - WaitWrite; - outb(0x64, 0x20); - WaitRead; - uint8_t cfg = inb(0x60); - bool DualChannel = cfg & 0b00100000; - if (DualChannel) - trace("Dual channel PS/2 controller detected."); - cfg |= 0b01000011; - WaitWrite; - outb(0x64, 0x60); - WaitWrite; - outb(0x60, cfg); - - WaitWrite; - outb(0x64, 0xAA); - WaitRead; - uint8_t test = inb(0x60); - if (test != 0x55) - { - error("PS/2 controller self test failed! (%#x)", test); - printf("PS/2 controller self test failed! (%#x)\n", test); - CPU::Stop(); - } - - WaitWrite; - outb(0x64, 0x60); - WaitWrite; - outb(0x60, cfg); - - bool DCExists = false; - if (DualChannel) - { - WaitWrite; - outb(0x64, 0xAE); - WaitWrite; - outb(0x64, 0x20); - WaitRead; - cfg = inb(0x60); - DCExists = !(cfg & 0b00100000); - WaitWrite; - outb(0x64, 0xAD); - debug("DCExists: %d", DCExists); - } - - WaitWrite; - outb(0x64, 0xAB); - WaitRead; - test = inb(0x60); - if (test != 0x00) - { - error("PS/2 keyboard self test failed! (%#x)", test); - printf("PS/2 keyboard self test failed! (%#x)\n", test); - CPU::Stop(); - } - - if (DCExists) - { - WaitWrite; - outb(0x64, 0xA9); - WaitRead; - test = inb(0x60); - if (test != 0x00) - { - error("PS/2 mouse self test failed! (%#x)", test); - printf("PS/2 mouse self test failed! (%#x)\n", test); - CPU::Stop(); - } - } - - WaitWrite; - outb(0x64, 0xAE); - - if (DCExists) - { - WaitWrite; - outb(0x64, 0xA8); - } - - WaitWrite; - outb(0x60, 0xFF); - WaitRead; - test = inb(0x60); - if (test == 0xFC) - { - error("PS/2 keyboard reset failed! (%#x)", test); - printf("PS/2 keyboard reset failed! (%#x)\n", test); - CPU::Stop(); - } - - WaitWrite; - outb(0x60, 0xD4); - WaitWrite; - outb(0x60, 0xFF); - WaitRead; - test = inb(0x60); - if (test == 0xFC) - { - error("PS/2 mouse reset failed! (%#x)", test); - printf("PS/2 mouse reset failed! (%#x)\n", test); - CPU::Stop(); - } - - trace("PS/2 keyboard configured."); - break; - } - case QueryReason: - { - Data->InputCallback.Keyboard.Key = ScanCode; - break; - } - case PollWaitReason: - { - while (!InputReceived) - TaskManager->Yield(); - InputReceived = false; - - Data->InputCallback.Keyboard.Key = ScanCode; - break; - } - case StopReason: - { - fixme("Module stopped."); - break; - } - default: - { - warn("Unknown reason."); - break; - } - } - return OK; - } - - int InterruptCallback(CPURegisters *) - { - ScanCode = inb(0x60); - InputReceived = true; - return OK; - } -} diff --git a/modules/PersonalSystem2/Mouse.cpp b/modules/PersonalSystem2/Mouse.cpp deleted file mode 100644 index d843057..0000000 --- a/modules/PersonalSystem2/Mouse.cpp +++ /dev/null @@ -1,265 +0,0 @@ -/* - This file is part of Fennix Kernel. - - Fennix Kernel is free software: you can redistribute it and/or - modify it under the terms of the GNU General Public License as - published by the Free Software Foundation, either version 3 of - the License, or (at your option) any later version. - - Fennix Kernel is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Fennix Kernel. If not, see . -*/ - -#include "mouse.hpp" - -#include -#include - -#include "../../mapi.hpp" -#include "../mod.hpp" -#include "../../kernel.h" - -namespace PS2Mouse -{ - KernelAPI KAPI; - - int MouseX = 0, MouseY = 0, MouseZ = 0; - int MouseLeft = 0, MouseMiddle = 0, MouseRight = 0; - - uint8_t Packet[4]; - bool PacketReady = false; - uint8_t Cycle = 0; - - void WaitRead() - { - uint64_t Timeout = 100000; - while (Timeout--) - if (inb(Ports::STATUS) & State::OUTPUT_FULL) - return; - } - - void WaitWrite() - { - uint64_t Timeout = 100000; - while (Timeout--) - if ((inb(Ports::STATUS) & State::INPUT_FULL) == 0) - return; - } - - uint8_t Read() - { - WaitRead(); - return inb(Ports::DATA); - } - - void Write(uint16_t Port, uint8_t Value) - { - WaitWrite(); - outb(Port, Value); - } - - int DriverEntry(void *Data) - { - if (!Data) - return INVALID_KERNEL_API; - KAPI = *(KernelAPI *)Data; - if (KAPI.Version.Major < 0 || KAPI.Version.Minor < 0 || KAPI.Version.Patch < 0) - return KERNEL_API_VERSION_NOT_SUPPORTED; - - return OK; - } - - int CallbackHandler(KernelCallback *Data) - { - switch (Data->Reason) - { - case AcknowledgeReason: - { - debug("Kernel acknowledged the driver."); - break; - } - case ConfigurationReason: - { - outb(COMMAND, 0xA8); - Write(COMMAND, READ_CONFIG); - uint8_t Status = Read(); - Status |= 0b10; - Write(COMMAND, WRITE_CONFIG); - Write(DATA, Status); - Write(COMMAND, 0xD4); - Write(DATA, 0xF6); - Read(); - Write(COMMAND, 0xD4); - Write(DATA, 0xF4); - Read(); - - trace("PS/2 mouse configured."); - break; - } - case QueryReason: - { - Data->InputCallback.Mouse.X = MouseX; - Data->InputCallback.Mouse.Y = MouseY; - Data->InputCallback.Mouse.Z = MouseZ; - Data->InputCallback.Mouse.Buttons.Left = MouseLeft; - Data->InputCallback.Mouse.Buttons.Right = MouseRight; - Data->InputCallback.Mouse.Buttons.Middle = MouseMiddle; - break; - } - case PollWaitReason: - { - while (!PacketReady) - TaskManager->Yield(); - - Data->InputCallback.Mouse.X = MouseX; - Data->InputCallback.Mouse.Y = MouseY; - Data->InputCallback.Mouse.Z = MouseZ; - Data->InputCallback.Mouse.Buttons.Left = MouseLeft; - Data->InputCallback.Mouse.Buttons.Right = MouseRight; - Data->InputCallback.Mouse.Buttons.Middle = MouseMiddle; - break; - } - case StopReason: - { - outb(COMMAND, 0xA8); - Write(COMMAND, READ_CONFIG); - uint8_t Status = Read(); - Status &= ~0b10; - Write(COMMAND, WRITE_CONFIG); - Write(DATA, Status); - Write(COMMAND, 0xD4); - Write(DATA, 0xF5); - Read(); - - debug("Module stopped."); - break; - } - default: - { - warn("Unknown reason."); - break; - } - } - return OK; - } - - int InterruptCallback(CPURegisters *) - { - uint8_t Data = inb(0x60); - - if (__builtin_expect(!!(PacketReady), 0)) - { - bool XNegative, YNegative, XOverflow, YOverflow; - - if (Packet[0] & PS2XSign) - XNegative = true; - else - XNegative = false; - - if (Packet[0] & PS2YSign) - YNegative = true; - else - YNegative = false; - - if (Packet[0] & PS2XOverflow) - XOverflow = true; - else - XOverflow = false; - - if (Packet[0] & PS2YOverflow) - YOverflow = true; - else - YOverflow = false; - - if (!XNegative) - { - MouseX += Packet[1]; - if (XOverflow) - MouseX += 255; - } - else - { - Packet[1] = (uint8_t)(256 - Packet[1]); - MouseX -= Packet[1]; - if (XOverflow) - MouseX -= 255; - } - - if (!YNegative) - { - MouseY -= Packet[2]; - if (YOverflow) - MouseY -= 255; - } - else - { - Packet[2] = (uint8_t)(256 - Packet[2]); - MouseY += Packet[2]; - if (YOverflow) - MouseY += 255; - } - - uint32_t Width = KAPI.Display.GetWidth(); - uint32_t Height = KAPI.Display.GetHeight(); - - if (MouseX < 0) - MouseX = 0; - - if ((uint32_t)MouseX > Width - 1) - MouseX = Width - 1; - - if (MouseY < 0) - MouseY = 0; - if ((uint32_t)MouseY > Height - 1) - MouseY = Height - 1; - - MouseLeft = 0; - MouseMiddle = 0; - MouseRight = 0; - - if (Packet[0] & PS2LeftButton) - MouseLeft = 1; - if (Packet[0] & PS2MiddleButton) - MouseMiddle = 1; - if (Packet[0] & PS2RightButton) - MouseRight = 1; - PacketReady = false; - } - - switch (Cycle) - { - case 0: - { - if ((Data & 0b00001000) == 0) - break; - Packet[0] = Data; - Cycle++; - break; - } - case 1: - { - Packet[1] = Data; - Cycle++; - break; - } - case 2: - { - Packet[2] = Data; - PacketReady = true; - Cycle = 0; - break; - } - default: - { - warn("Unknown cycle %d", Cycle); - break; - } - } - return OK; - } -} diff --git a/modules/PersonalSystem2/keyboard.hpp b/modules/PersonalSystem2/keyboard.hpp deleted file mode 100644 index 4c24cb3..0000000 --- a/modules/PersonalSystem2/keyboard.hpp +++ /dev/null @@ -1,237 +0,0 @@ -/* - This file is part of Fennix Kernel. - - Fennix Kernel is free software: you can redistribute it and/or - modify it under the terms of the GNU General Public License as - published by the Free Software Foundation, either version 3 of - the License, or (at your option) any later version. - - Fennix Kernel is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Fennix Kernel. If not, see . -*/ - -#ifndef __FENNIX_KERNEL_PS2_KEYBOARD_H__ -#define __FENNIX_KERNEL_PS2_KEYBOARD_H__ - -#include -#include "../../mapi.hpp" - -namespace PS2Keyboard -{ - enum DownKeys - { - 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, - }; - - enum UpKeys - { - 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, - }; - - int DriverEntry(void *); - int CallbackHandler(KernelCallback *); - int InterruptCallback(CPURegisters *); -} - -#endif // !__FENNIX_KERNEL_PS2_KEYBOARD_H__ diff --git a/modules/PersonalSystem2/mouse.hpp b/modules/PersonalSystem2/mouse.hpp deleted file mode 100644 index a7fedd2..0000000 --- a/modules/PersonalSystem2/mouse.hpp +++ /dev/null @@ -1,59 +0,0 @@ -/* - This file is part of Fennix Kernel. - - Fennix Kernel is free software: you can redistribute it and/or - modify it under the terms of the GNU General Public License as - published by the Free Software Foundation, either version 3 of - the License, or (at your option) any later version. - - Fennix Kernel is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Fennix Kernel. If not, see . -*/ - -#ifndef __FENNIX_KERNEL_PS2_MOUSE_H__ -#define __FENNIX_KERNEL_PS2_MOUSE_H__ - -#include -#include "../../mapi.hpp" - -namespace PS2Mouse -{ -#define PS2LeftButton 0b00000001 -#define PS2MiddleButton 0b00000100 -#define PS2RightButton 0b00000010 -#define PS2XSign 0b00010000 -#define PS2YSign 0b00100000 -#define PS2XOverflow 0b01000000 -#define PS2YOverflow 0b10000000 - - enum Config - { - READ_CONFIG = 0x20, - WRITE_CONFIG = 0x60 - }; - - enum Ports - { - DATA = 0x60, - STATUS = 0x64, - COMMAND = 0x64, - }; - - enum State - { - OUTPUT_FULL = (1 << 0), - INPUT_FULL = (1 << 1), - MOUSE_BYTE = (1 << 5) - }; - - int DriverEntry(void *); - int CallbackHandler(KernelCallback *); - int InterruptCallback(CPURegisters *); -} - -#endif // !__FENNIX_KERNEL_PS2_MOUSE_H__ diff --git a/modules/Realtek/RTL8139.cpp b/modules/Realtek/RTL8139.cpp deleted file mode 100644 index eee1933..0000000 --- a/modules/Realtek/RTL8139.cpp +++ /dev/null @@ -1,207 +0,0 @@ -/* - This file is part of Fennix Kernel. - - Fennix Kernel is free software: you can redistribute it and/or - modify it under the terms of the GNU General Public License as - published by the Free Software Foundation, either version 3 of - the License, or (at your option) any later version. - - Fennix Kernel is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Fennix Kernel. If not, see . -*/ - -#include "rtl8139.hpp" - -#include -#include -#include -#include - -#include "../../mapi.hpp" -#include "../mod.hpp" - -using namespace PCI; - -namespace RTL8139 -{ - KernelAPI KAPI; - - PCIDeviceHeader *PCIBaseAddress; - BARData BAR; - - uint8_t *RXBuffer; - int TXCurrent; - uint16_t CurrentPacket; - - MediaAccessControl MAC; - InternetProtocol::Version4 IP; - - uint8_t TSAD[4] = {0x20, 0x24, 0x28, 0x2C}; - uint8_t TSD[4] = {0x10, 0x14, 0x18, 0x1C}; - - void RTLOB(uint16_t Address, uint8_t Value) - { - if (BAR.Type == 0) - mmoutb(reinterpret_cast(BAR.MemoryBase + Address), Value); - else - outportb(BAR.IOBase + Address, Value); - } - - void RTLOW(uint16_t Address, uint16_t Value) - { - if (BAR.Type == 0) - mmoutw(reinterpret_cast(BAR.MemoryBase + Address), Value); - else - outportw(BAR.IOBase + Address, Value); - } - - void RTLOL(uint16_t Address, uint32_t Value) - { - if (BAR.Type == 0) - mmoutl(reinterpret_cast(BAR.MemoryBase + Address), Value); - else - outportl(BAR.IOBase + Address, Value); - } - - uint8_t RTLIB(uint16_t Address) - { - if (BAR.Type == 0) - return mminb(reinterpret_cast(BAR.MemoryBase + Address)); - else - return inportb(BAR.IOBase + Address); - } - - uint16_t RTLIW(uint16_t Address) - { - if (BAR.Type == 0) - return mminw(reinterpret_cast(BAR.MemoryBase + Address)); - else - return inportw(BAR.IOBase + Address); - } - - uint32_t RTLIL(uint16_t Address) - { - if (BAR.Type == 0) - return mminl(reinterpret_cast(BAR.MemoryBase + Address)); - else - return inportl(BAR.IOBase + Address); - } - - MediaAccessControl GetMAC() - { - uint32_t MAC1 = RTLIL(0x0); - uint16_t MAC2 = RTLIW(0x4); - MediaAccessControl mac = { - mac.Address[0] = (uint8_t)MAC1, - mac.Address[1] = (uint8_t)(MAC1 >> 8), - mac.Address[2] = (uint8_t)(MAC1 >> 16), - mac.Address[3] = (uint8_t)(MAC1 >> 24), - mac.Address[4] = (uint8_t)MAC2, - mac.Address[5] = (uint8_t)(MAC2 >> 8)}; - return mac; - } - - int DriverEntry(void *Data) - { - if (!Data) - return INVALID_KERNEL_API; - KAPI = *(KernelAPI *)Data; - if (KAPI.Version.Major < 0 || KAPI.Version.Minor < 0 || KAPI.Version.Patch < 0) - return KERNEL_API_VERSION_NOT_SUPPORTED; - return OK; - } - - int CallbackHandler(KernelCallback *Data) - { - switch (Data->Reason) - { - case AcknowledgeReason: - { - debug("Kernel acknowledged the driver."); - break; - } - case ConfigurationReason: - { - debug("Module received configuration data."); - PCIBaseAddress = reinterpret_cast(Data->RawPtr); - if (PCIBaseAddress->VendorID == 0x10EC && PCIBaseAddress->DeviceID == 0x8139) - { - trace("Found RTL-8139."); - - PCIBaseAddress->Command |= PCI_COMMAND_MASTER | PCI_COMMAND_IO | PCI_COMMAND_MEMORY; - uint32_t PCIBAR0 = ((PCIHeader0 *)PCIBaseAddress)->BAR0; - uint32_t PCIBAR1 = ((PCIHeader0 *)PCIBaseAddress)->BAR1; - - BAR.Type = PCIBAR1 & 1; - BAR.IOBase = (uint16_t)(PCIBAR0 & (~3)); - BAR.MemoryBase = PCIBAR1 & (~15); - - RXBuffer = (uint8_t *)KAPI.Memory.RequestPage(2); - RTLOB(0x52, 0x0); - RTLOB(0x37, (1 << 4)); - while ((RTLIB(0x37) & (1 << 4))) - ; - RTLOL(0x30, static_cast(reinterpret_cast(RXBuffer))); - RTLOW(0x3C, ((1 << 0) | (1 << 1) | (1 << 2) | (1 << 3) | - (1 << 4) | (1 << 5) | (1 << 6) | (1 << 13) | - (1 << 14) | (1 << 15))); - RTLOL(0x44, ((1 << 0) | (1 << 1) | (1 << 2) | (1 << 3) | (1 << 7))); - RTLOB(0x37, 0x0C); - MAC = GetMAC(); - } - else - return DEVICE_NOT_SUPPORTED; - break; - } - case QueryReason: - { - memcpy(Data->NetworkCallback.Fetch.Name, (void *)"RTL-8139", 9); - Data->NetworkCallback.Fetch.MAC = MAC.ToHex(); - break; - } - case SendReason: - { - RTLOL(TSAD[TXCurrent], static_cast(reinterpret_cast(Data->NetworkCallback.Send.Data))); - RTLOL(TSD[TXCurrent++], (uint32_t)Data->NetworkCallback.Send.Length); - if (TXCurrent > 3) - TXCurrent = 0; - break; - } - case StopReason: - { - // TODO: Stop the driver. - debug("Module stopped."); - break; - } - default: - { - warn("Unknown reason."); - break; - } - } - return OK; - } - - int InterruptCallback(CPURegisters *) - { - uint16_t Status = RTLIW(0x3E); - UNUSED(Status); - - uint16_t *Data = (uint16_t *)(RXBuffer + CurrentPacket); - uint16_t DataLength = *(Data + 1); - Data = Data + 2; - KAPI.Command.Network.ReceivePacket(KAPI.Info.modUniqueID, (uint8_t *)Data, DataLength); - CurrentPacket = (uint16_t)((CurrentPacket + DataLength + 4 + 3) & (~3)); - if (CurrentPacket > 8192) - CurrentPacket -= 8192; - RTLOW(0x38, CurrentPacket - 0x10); - - RTLOW(0x3E, (1 << 0) | (1 << 2)); - return OK; - } -} diff --git a/modules/VMware/Mouse.cpp b/modules/VMware/Mouse.cpp deleted file mode 100644 index 2e87045..0000000 --- a/modules/VMware/Mouse.cpp +++ /dev/null @@ -1,260 +0,0 @@ -/* - This file is part of Fennix Kernel. - - Fennix Kernel is free software: you can redistribute it and/or - modify it under the terms of the GNU General Public License as - published by the Free Software Foundation, either version 3 of - the License, or (at your option) any later version. - - Fennix Kernel is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Fennix Kernel. If not, see . -*/ - -#include "mouse.hpp" - -#include -#include - -#include "../../mapi.hpp" -#include "../mod.hpp" -#include "../../kernel.h" - -/* https://wiki.osdev.org/VMware_tools */ - -namespace VMwareMouse -{ - KernelAPI KAPI; - - void CommandSend(VMwareCommand *cmd) - { - cmd->magic = VMWARE_MAGIC; - cmd->port = VMWARE_PORT; - asm volatile("in %%dx, %0" - : "+a"(cmd->ax), "+b"(cmd->bx), "+c"(cmd->cx), "+d"(cmd->dx), "+S"(cmd->si), "+D"(cmd->di)); - } - - bool IsVMwareBackdoorAvailable(void) - { - VMwareCommand cmd; - cmd.bx = ~VMWARE_MAGIC; - cmd.command = CMD_GETVERSION; - CommandSend(&cmd); - if (cmd.bx != VMWARE_MAGIC || cmd.ax == 0xFFFFFFFF) - return false; - return true; - } - - int DriverEntry(void *Data) - { - if (!Data) - return INVALID_KERNEL_API; - KAPI = *(KernelAPI *)Data; - if (KAPI.Version.Major < 0 || KAPI.Version.Minor < 0 || KAPI.Version.Patch < 0) - return KERNEL_API_VERSION_NOT_SUPPORTED; - - if (!IsVMwareBackdoorAvailable()) - return SYSTEM_NOT_SUPPORTED; - - return OK; - } - - void Absolute(void) - { - VMwareCommand cmd; - - /* Enable */ - cmd.bx = ABSPOINTER_ENABLE; - cmd.command = CMD_ABSPOINTER_COMMAND; - CommandSend(&cmd); - - /* Status */ - cmd.bx = 0; - cmd.command = CMD_ABSPOINTER_STATUS; - CommandSend(&cmd); - - /* Read data (1) */ - cmd.bx = 1; - cmd.command = CMD_ABSPOINTER_DATA; - CommandSend(&cmd); - - /* Enable absolute */ - cmd.bx = ABSPOINTER_ABSOLUTE; - cmd.command = CMD_ABSPOINTER_COMMAND; - CommandSend(&cmd); - } - - void Relative(void) - { - VMwareCommand cmd; - cmd.bx = ABSPOINTER_RELATIVE; - cmd.command = CMD_ABSPOINTER_COMMAND; - CommandSend(&cmd); - } - - enum Config - { - READ_CONFIG = 0x20, - WRITE_CONFIG = 0x60 - }; - - enum Ports - { - DATA = 0x60, - STATUS = 0x64, - COMMAND = 0x64, - }; - - enum State - { - OUTPUT_FULL = (1 << 0), - INPUT_FULL = (1 << 1), - MOUSE_BYTE = (1 << 5) - }; - - void WaitRead() - { - uint64_t Timeout = 100000; - while (Timeout--) - if (inb(Ports::STATUS) & State::OUTPUT_FULL) - return; - } - - void WaitWrite() - { - uint64_t Timeout = 100000; - while (Timeout--) - if ((inb(Ports::STATUS) & State::INPUT_FULL) == 0) - return; - } - - void Write(uint16_t Port, uint8_t Value) - { - WaitWrite(); - outb(Port, Value); - } - - uint8_t Read() - { - WaitRead(); - return inb(Ports::DATA); - } - - int MouseX = 0, MouseY = 0, MouseZ = 0; - int MouseButton = 0; - - bool InputReceived = false; - - int CallbackHandler(KernelCallback *Data) - { - switch (Data->Reason) - { - case AcknowledgeReason: - { - debug("Kernel acknowledged the driver."); - break; - } - case ConfigurationReason: - { - outb(COMMAND, 0xA8); - Write(COMMAND, READ_CONFIG); - uint8_t Status = Read(); - Status |= 0b10; - Write(COMMAND, WRITE_CONFIG); - Write(DATA, Status); - Write(COMMAND, 0xD4); - Write(DATA, 0xF6); - Read(); - Write(COMMAND, 0xD4); - Write(DATA, 0xF4); - Read(); - Absolute(); - trace("VMware mouse configured."); - break; - } - case QueryReason: - { - Data->InputCallback.Mouse.X = (MouseX * KAPI.Display.GetWidth()) / 0xFFFF; - Data->InputCallback.Mouse.Y = (MouseY * KAPI.Display.GetHeight()) / 0xFFFF; - Data->InputCallback.Mouse.Z = MouseZ; - Data->InputCallback.Mouse.Buttons.Left = MouseButton & 0x20; - Data->InputCallback.Mouse.Buttons.Right = MouseButton & 0x10; - Data->InputCallback.Mouse.Buttons.Middle = MouseButton & 0x08; - break; - } - case PollWaitReason: - { - while (!InputReceived) - TaskManager->Yield(); - InputReceived = false; - - Data->InputCallback.Mouse.X = (MouseX * KAPI.Display.GetWidth()) / 0xFFFF; - Data->InputCallback.Mouse.Y = (MouseY * KAPI.Display.GetHeight()) / 0xFFFF; - Data->InputCallback.Mouse.Z = MouseZ; - Data->InputCallback.Mouse.Buttons.Left = MouseButton & 0x20; - Data->InputCallback.Mouse.Buttons.Right = MouseButton & 0x10; - Data->InputCallback.Mouse.Buttons.Middle = MouseButton & 0x08; - break; - } - case StopReason: - { - Relative(); - // TODO: UNTESTED!!! - outb(COMMAND, 0xA8); - Write(COMMAND, READ_CONFIG); - uint8_t Status = Read(); - Status &= ~0b10; - Write(COMMAND, WRITE_CONFIG); - Write(DATA, Status); - Write(COMMAND, 0xD4); - Write(DATA, 0xF5); - Read(); - debug("Module stopped."); - break; - } - default: - { - warn("Unknown reason."); - break; - } - } - return OK; - } - - int InterruptCallback(CPURegisters *) - { - uint8_t Data = inb(0x60); - (void)Data; - VMwareCommand cmd; - cmd.bx = 0; - cmd.command = CMD_ABSPOINTER_STATUS; - CommandSend(&cmd); - - if (cmd.ax == 0xFFFF0000) - { - warn("VMware mouse is not connected?"); - Relative(); - Absolute(); - return ERROR; - } - if ((cmd.ax & 0xFFFF) < 4) - return ERROR; - - cmd.bx = 4; - cmd.command = CMD_ABSPOINTER_DATA; - CommandSend(&cmd); - - int flags = (cmd.ax & 0xFFFF0000) >> 16; /* Not important */ - (void)flags; - MouseButton = (cmd.ax & 0xFFFF); /* 0x10 = Right, 0x20 = Left, 0x08 = Middle */ - MouseX = cmd.bx; /* Both X and Y are scaled from 0 to 0xFFFF */ - MouseY = cmd.cx; /* You should map these somewhere to the actual resolution. */ - MouseZ = (int8_t)cmd.dx; /* Z is a single signed byte indicating scroll direction. */ - InputReceived = true; - return OK; - } -} diff --git a/modules/VMware/mouse.hpp b/modules/VMware/mouse.hpp deleted file mode 100644 index 9ae895e..0000000 --- a/modules/VMware/mouse.hpp +++ /dev/null @@ -1,69 +0,0 @@ -/* - This file is part of Fennix Kernel. - - Fennix Kernel is free software: you can redistribute it and/or - modify it under the terms of the GNU General Public License as - published by the Free Software Foundation, either version 3 of - the License, or (at your option) any later version. - - Fennix Kernel is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Fennix Kernel. If not, see . -*/ - -#ifndef __FENNIX_KERNEL_VMWARE_MOUSE_H__ -#define __FENNIX_KERNEL_VMWARE_MOUSE_H__ - -#include -#include "../../mapi.hpp" - -namespace VMwareMouse -{ -#define VMWARE_MAGIC 0x564D5868 /* hXMV */ -#define VMWARE_PORT 0x5658 - -#define CMD_GETVERSION 0xA -#define CMD_ABSPOINTER_DATA 0x27 -#define CMD_ABSPOINTER_STATUS 0x28 -#define CMD_ABSPOINTER_COMMAND 0x29 - -#define ABSPOINTER_ENABLE 0x45414552 /* Q E A E */ -#define ABSPOINTER_RELATIVE 0xF5 -#define ABSPOINTER_ABSOLUTE 0x53424152 /* R A B S */ - - typedef struct - { - union - { - uint32_t ax; - uint32_t magic; - }; - union - { - uint32_t bx; - size_t size; - }; - union - { - uint32_t cx; - uint16_t command; - }; - union - { - uint32_t dx; - uint16_t port; - }; - uint32_t si; - uint32_t di; - } VMwareCommand; - - int DriverEntry(void *); - int CallbackHandler(KernelCallback *); - int InterruptCallback(CPURegisters *); -} - -#endif // !__FENNIX_KERNEL_VMWARE_MOUSE_H__ diff --git a/modules/mod_loader.cpp b/modules/mod_loader.cpp deleted file mode 100644 index 3f601da..0000000 --- a/modules/mod_loader.cpp +++ /dev/null @@ -1,317 +0,0 @@ -/* - This file is part of Fennix Kernel. - - Fennix Kernel is free software: you can redistribute it and/or - modify it under the terms of the GNU General Public License as - published by the Free Software Foundation, either version 3 of - the License, or (at your option) any later version. - - Fennix Kernel is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Fennix Kernel. If not, see . -*/ - -#include "mod.hpp" - -#include "AHCI/ahci.hpp" -#include "VMware/mouse.hpp" -#include "PersonalSystem2/mouse.hpp" -#include "PersonalSystem2/keyboard.hpp" -#include "ATA/ata.hpp" -#include "AudioCodec97/ac97.hpp" -#include "Realtek/rtl8139.hpp" -#include "AdvancedMicroDevices/pcnet.hpp" -#include "Intel/gigabit.hpp" - -#include -#include - -#include "../core/module/api.hpp" -#include "../kernel.h" -#include "../mapi.hpp" -#include "../Fex.hpp" - -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wmissing-field-initializers" - -FexExtended AHCIExtendedHeader = { - .Module = { - .Name = "Advanced Host Controller Interface", - .Type = FexModuleType_Storage, - .Callback = AdvancedHostControllerInterface::CallbackHandler, - .InterruptCallback = AdvancedHostControllerInterface::InterruptCallback, - .Bind = { - .Type = BIND_PCI, - .PCI = { - .VendorID = {0x8086, 0x15AD}, - .DeviceID = {0x2922, 0x2829, 0x07E0}, - .Class = 0x1, - .SubClass = 0x6, - .ProgIF = 0x1, - }}}}; - -FexExtended VMwareVirtualMouseExtendedHeader = { - .Module = { - .Name = "VMware Virtual Mouse", - .Type = FexModuleType_Input, - .TypeFlags = FexDriverInputTypes_Mouse, - .OverrideOnConflict = true, - .Callback = VMwareMouse::CallbackHandler, - .InterruptCallback = VMwareMouse::InterruptCallback, - .Bind = { - .Type = BIND_INTERRUPT, - .Interrupt = { - .Vector = {12}, // IRQ12 - }}}}; - -FexExtended PS2MouseExtendedHeader = { - .Module = { - .Name = "PS/2 Mouse", - .Type = FexModuleType_Input, - .TypeFlags = FexDriverInputTypes_Mouse, - .Callback = PS2Mouse::CallbackHandler, - .InterruptCallback = PS2Mouse::InterruptCallback, - .Bind = { - .Type = BIND_INTERRUPT, - .Interrupt = { - .Vector = {12}, // IRQ12 - }}}}; - -FexExtended PS2KeyboardExtendedHeader = { - .Module = { - .Name = "PS/2 Keyboard", - .Type = FexModuleType_Input, - .TypeFlags = FexDriverInputTypes_Keyboard, - .Callback = PS2Keyboard::CallbackHandler, - .InterruptCallback = PS2Keyboard::InterruptCallback, - .Bind = { - .Type = BIND_INTERRUPT, - .Interrupt = { - .Vector = {1}, // IRQ1 - }}}}; - -FexExtended ATAExtendedHeader = { - .Module = { - .Name = "Advanced Technology Attachment", - .Type = FexModuleType_Storage, - .Callback = AdvancedTechnologyAttachment::CallbackHandler, - .InterruptCallback = AdvancedTechnologyAttachment::InterruptCallback, - .Bind = { - .Type = BIND_INTERRUPT, - .Interrupt = { - .Vector = {14, 15}, // IRQ14, IRQ15 - }}}}; - -FexExtended AC97ExtendedHeader = { - .Module = { - .Name = "Audio Codec '97 Module", - .Type = FexModuleType_Audio, - .TypeFlags = FexDriverInputTypes_None, - .OverrideOnConflict = false, - .Callback = AudioCodec97::CallbackHandler, - .InterruptCallback = AudioCodec97::InterruptCallback, - .Bind = { - .Type = BIND_PCI, - .PCI = { - .VendorID = {0x8086}, - .DeviceID = {0x2415}, - .Class = 0x4, - .SubClass = 0x3, - .ProgIF = 0x0, - }}}}; - -FexExtended RTL8139ExtendedHeader = { - .Module = { - .Name = "Realtek RTL8139", - .Type = FexModuleType_Network, - .Callback = RTL8139::CallbackHandler, - .InterruptCallback = RTL8139::InterruptCallback, - .Bind = { - .Type = BIND_PCI, - .PCI = { - .VendorID = {0x10EC}, - .DeviceID = {0x8139}, - .Class = 0x2, - .SubClass = 0x0, - .ProgIF = 0x0, - }}}}; - -FexExtended AMDPCNETExtendedHeader = { - .Module = { - .Name = "Advanced Micro Devices PCNET", - .Type = FexModuleType_Network, - .Callback = PCNET::CallbackHandler, - .InterruptCallback = PCNET::InterruptCallback, - .Bind = { - .Type = BIND_PCI, - .PCI = { - .VendorID = {0x1022}, - .DeviceID = {0x2000}, - .Class = 0x2, - .SubClass = 0x0, - .ProgIF = 0x0, - }}}}; - -FexExtended IntelGigabitExtendedHeader = { - .Module = { - .Name = "Intel Gigabit Ethernet Controller", - .Type = FexModuleType_Network, - .Callback = Gigabit::CallbackHandler, - .InterruptCallback = Gigabit::InterruptCallback, - .Bind = { - .Type = BIND_PCI, - .PCI = { - .VendorID = {0x8086}, - .DeviceID = {0x100E, 0x100F, 0x10D3, 0x10EA, 0x153A}, - .Class = 0x2, - .SubClass = 0x0, - .ProgIF = 0x0, - }}}}; - -#pragma GCC diagnostic pop - -std::vector FindPCI(uint16_t VendorID[16], uint16_t DeviceID[16]) -{ - for (uint16_t Vidx = 0; Vidx < 16; Vidx++) - { - for (uint16_t Didx = 0; Didx < 16; Didx++) - { - if (VendorID[Vidx] == 0 || DeviceID[Didx] == 0) - break; - - std::vector devices = PCIManager->FindPCIDevice(VendorID[Vidx], DeviceID[Didx]); - if (devices.size() == 0) - continue; - - return devices; - } - } - - warn("No PCI device found"); - return std::vector(); -} - -bool StartAHCI() -{ - Module::BuiltInModuleInfo BIDI = { - .EntryPoint = AdvancedHostControllerInterface::DriverEntry, - .ExtendedHeader = &AHCIExtendedHeader}; - - if (ModuleManager->ModuleLoadBindPCI((uintptr_t)&BIDI, 0, true) == Module::ModuleCode::OK) - return true; - - return false; -} - -bool StartVMwareMouse() -{ - Module::BuiltInModuleInfo BIDI = { - .EntryPoint = VMwareMouse::DriverEntry, - .ExtendedHeader = &VMwareVirtualMouseExtendedHeader}; - - if (ModuleManager->ModuleLoadBindInterrupt((uintptr_t)&BIDI, 0, true) == Module::ModuleCode::OK) - return true; - - return false; -} - -bool StartPS2Mouse() -{ - Module::BuiltInModuleInfo BIDI = { - .EntryPoint = PS2Mouse::DriverEntry, - .ExtendedHeader = &PS2MouseExtendedHeader}; - - if (ModuleManager->ModuleLoadBindInterrupt((uintptr_t)&BIDI, 0, true) == Module::ModuleCode::OK) - return true; - - return false; -} - -bool StartPS2Keyboard() -{ - Module::BuiltInModuleInfo BIDI = { - .EntryPoint = PS2Keyboard::DriverEntry, - .ExtendedHeader = &PS2KeyboardExtendedHeader}; - - if (ModuleManager->ModuleLoadBindInterrupt((uintptr_t)&BIDI, 0, true) == Module::ModuleCode::OK) - return true; - - return false; -} - -bool StartATA() -{ - Module::BuiltInModuleInfo BIDI = { - .EntryPoint = AdvancedTechnologyAttachment::DriverEntry, - .ExtendedHeader = &ATAExtendedHeader}; - - if (ModuleManager->ModuleLoadBindInterrupt((uintptr_t)&BIDI, 0, true) == Module::ModuleCode::OK) - return true; - - return false; -} - -bool StartAC97() -{ - Module::BuiltInModuleInfo BIDI = { - .EntryPoint = AudioCodec97::DriverEntry, - .ExtendedHeader = &AC97ExtendedHeader}; - - if (ModuleManager->ModuleLoadBindPCI((uintptr_t)&BIDI, 0, true) == Module::ModuleCode::OK) - return true; - - return false; -} - -bool StartRTL8139() -{ - Module::BuiltInModuleInfo BIDI = { - .EntryPoint = RTL8139::DriverEntry, - .ExtendedHeader = &RTL8139ExtendedHeader}; - - if (ModuleManager->ModuleLoadBindPCI((uintptr_t)&BIDI, 0, true) == Module::ModuleCode::OK) - return true; - - return false; -} - -bool StartPCNET() -{ - Module::BuiltInModuleInfo BIDI = { - .EntryPoint = PCNET::DriverEntry, - .ExtendedHeader = &AMDPCNETExtendedHeader}; - - if (ModuleManager->ModuleLoadBindPCI((uintptr_t)&BIDI, 0, true) == Module::ModuleCode::OK) - return true; - - return false; -} - -bool StartGigabit() -{ - Module::BuiltInModuleInfo BIDI = { - .EntryPoint = Gigabit::DriverEntry, - .ExtendedHeader = &IntelGigabitExtendedHeader}; - - if (ModuleManager->ModuleLoadBindPCI((uintptr_t)&BIDI, 0, true) == Module::ModuleCode::OK) - return true; - - return false; -} - -void StartBuiltInModules() -{ - StartAHCI(); - StartVMwareMouse(); - StartPS2Mouse(); - StartPS2Keyboard(); - StartATA(); - StartAC97(); - StartRTL8139(); - StartPCNET(); - StartGigabit(); -} diff --git a/network/arp.cpp b/network/arp.cpp index 354d376..676e6f7 100644 --- a/network/arp.cpp +++ b/network/arp.cpp @@ -21,7 +21,7 @@ #include "../kernel.h" -/* conversion from ‘uint48_t’ {aka ‘long unsigned int’} to ‘long unsigned int:48’ may change value */ +/* conversion from 'uint48_t' {aka 'long unsigned int'} to 'long unsigned int:48' may change value */ #pragma GCC diagnostic ignored "-Wconversion" namespace NetworkARP diff --git a/network/checksum.cpp b/network/checksum.cpp index 2edac75..59fbea9 100644 --- a/network/checksum.cpp +++ b/network/checksum.cpp @@ -19,13 +19,13 @@ uint16_t CalculateChecksum(uint16_t *Data, size_t Length) { - uint16_t *Data16 = (uint16_t *)Data; - uint64_t Checksum = 0; - for (uint64_t i = 0; i < Length / 2; i++) - Checksum += ((Data16[i] & 0xFF00) >> 8) | ((Data16[i] & 0x00FF) << 8); - if (Length % 2) - Checksum += ((uint16_t)((char *)Data16)[Length - 1]) << 8; - while (Checksum & 0xFFFF0000) - Checksum = (Checksum & 0xFFFF) + (Checksum >> 16); - return (uint16_t)(((~Checksum & 0xFF00) >> 8) | ((~Checksum & 0x00FF) << 8)); + uint16_t *Data16 = (uint16_t *)Data; + uint64_t Checksum = 0; + for (uint64_t i = 0; i < Length / 2; i++) + Checksum += ((Data16[i] & 0xFF00) >> 8) | ((Data16[i] & 0x00FF) << 8); + if (Length % 2) + Checksum += ((uint16_t)((char *)Data16)[Length - 1]) << 8; + while (Checksum & 0xFFFF0000) + Checksum = (Checksum & 0xFFFF) + (Checksum >> 16); + return (uint16_t)(((~Checksum & 0xFF00) >> 8) | ((~Checksum & 0x00FF) << 8)); } diff --git a/network/dhcp.cpp b/network/dhcp.cpp index db93051..2e81c44 100644 --- a/network/dhcp.cpp +++ b/network/dhcp.cpp @@ -22,165 +22,165 @@ namespace NetworkDHCP { - DHCP::DHCP(NetworkUDP::Socket *Socket, NetworkInterfaceManager::DeviceInterface *Interface) - { - debug("DHCP interface %#lx created.", this); - this->UDPSocket = Socket; - this->Interface = Interface; - Socket->LocalPort = b16(68); + DHCP::DHCP(NetworkUDP::Socket *Socket, NetworkInterfaceManager::DeviceInterface *Interface) + { + debug("DHCP interface %#lx created.", this); + this->UDPSocket = Socket; + this->Interface = Interface; + Socket->LocalPort = b16(68); - InternetProtocol::Version4 DefaultIPv4 = {.Address = {0x0, 0x0, 0x0, 0x0}}; - InternetProtocol::Version6 DefaultIPv6 = {.Address = {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}}; + InternetProtocol::Version4 DefaultIPv4 = {.Address = {0x0, 0x0, 0x0, 0x0}}; + InternetProtocol::Version6 DefaultIPv6 = {.Address = {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}}; - this->IP.v4 = DefaultIPv4; - this->IP.v6 = DefaultIPv6; + this->IP.v4 = DefaultIPv4; + this->IP.v6 = DefaultIPv6; - this->Gateway.v4 = DefaultIPv4; - this->Gateway.v6 = DefaultIPv6; + this->Gateway.v4 = DefaultIPv4; + this->Gateway.v6 = DefaultIPv6; - this->SubNetworkMask.v4 = DefaultIPv4; - this->SubNetworkMask.v6 = DefaultIPv6; + this->SubNetworkMask.v4 = DefaultIPv4; + this->SubNetworkMask.v6 = DefaultIPv6; - this->DomainNameSystem.v4 = DefaultIPv4; - this->DomainNameSystem.v6 = DefaultIPv6; - } + this->DomainNameSystem.v4 = DefaultIPv4; + this->DomainNameSystem.v6 = DefaultIPv6; + } - DHCP::~DHCP() - { - debug("DHCP interface %#lx destroyed.", this); - } + DHCP::~DHCP() + { + debug("DHCP interface %#lx destroyed.", this); + } - __no_sanitize("alignment") void DHCP::CreatePacket(DHCPHeader *Packet, uint8_t MessageType, uint32_t RequestIP) - { - Packet->Opcode = b8(DHCP_OP_BOOTREQUEST); - Packet->HardwareType = b8(1); - Packet->HardwareAddressLength = b8(6); - Packet->Hops = b8(0); - Packet->TransactionID = b32(DHCP_TRANSACTION_ID); - Packet->Flags = b16(0x40); - uint48_t InterfaceMAC = b48(Interface->MAC.ToHex()); - memcpy(Packet->ClientHardwareAddress, &InterfaceMAC, sizeof(InterfaceMAC)); + __no_sanitize("alignment") void DHCP::CreatePacket(DHCPHeader *Packet, uint8_t MessageType, uint32_t RequestIP) + { + Packet->Opcode = b8(DHCP_OP_BOOTREQUEST); + Packet->HardwareType = b8(1); + Packet->HardwareAddressLength = b8(6); + Packet->Hops = b8(0); + Packet->TransactionID = b32(DHCP_TRANSACTION_ID); + Packet->Flags = b16(0x40); + uint48_t InterfaceMAC = b48(Interface->MAC.ToHex()); + memcpy(Packet->ClientHardwareAddress, &InterfaceMAC, sizeof(InterfaceMAC)); - uint8_t *Ptr = Packet->Options; - *((uint32_t *)(Ptr)) = b32(0x63825363); // Magic Cookie - Ptr += 4; + uint8_t *Ptr = Packet->Options; + *((uint32_t *)(Ptr)) = b32(0x63825363); // Magic Cookie + Ptr += 4; - *(Ptr++) = DHCP_OPTION_MESSAGE_TYPE; - *(Ptr++) = DHCP_MESSAGE_TYPE_DISCOVER; - *(Ptr++) = MessageType; + *(Ptr++) = DHCP_OPTION_MESSAGE_TYPE; + *(Ptr++) = DHCP_MESSAGE_TYPE_DISCOVER; + *(Ptr++) = MessageType; - *(Ptr++) = DHCP_OPTION_CLIENT_IDENTIFIER; - *(Ptr++) = 0x07; - *(Ptr++) = 0x01; - memcpy(Ptr, &InterfaceMAC, sizeof(InterfaceMAC)); - Ptr += 6; + *(Ptr++) = DHCP_OPTION_CLIENT_IDENTIFIER; + *(Ptr++) = 0x07; + *(Ptr++) = 0x01; + memcpy(Ptr, &InterfaceMAC, sizeof(InterfaceMAC)); + Ptr += 6; - *(Ptr++) = DHCP_OPTION_REQUESTED_IP; - *(Ptr++) = 0x04; - *((uint32_t *)(Ptr)) = b32(0x0a00020e); - memcpy((uint32_t *)(Ptr), &RequestIP, 4); - Ptr += 4; + *(Ptr++) = DHCP_OPTION_REQUESTED_IP; + *(Ptr++) = 0x04; + *((uint32_t *)(Ptr)) = b32(0x0a00020e); + memcpy((uint32_t *)(Ptr), &RequestIP, 4); + Ptr += 4; - *(Ptr++) = DHCP_OPTION_HOST_NAME; - char *HostName = (char *)KERNEL_NAME; - *(Ptr++) = s_cst(uint8_t, 1 + strlen(HostName)); - memcpy(Ptr, HostName, strlen(HostName)); - Ptr += strlen(HostName); + *(Ptr++) = DHCP_OPTION_HOST_NAME; + char *HostName = (char *)KERNEL_NAME; + *(Ptr++) = s_cst(uint8_t, 1 + strlen(HostName)); + memcpy(Ptr, HostName, strlen(HostName)); + Ptr += strlen(HostName); - *(Ptr++) = DHCP_OPTION_PAD; + *(Ptr++) = DHCP_OPTION_PAD; - *(Ptr++) = DHCP_OPTION_PARAMETER_REQUEST_LIST; - *(Ptr++) = DHCP_OPTION_COOKIE_SERVER; - *(Ptr++) = DHCP_OPTION_SUBNETMASK; - *(Ptr++) = DHCP_OPTION_ROUTER; - *(Ptr++) = DHCP_OPTION_DOMAIN_NAME_SERVER; - *(Ptr++) = DHCP_OPTION_DOMAIN_NAME; - *(Ptr++) = DHCP_OPTION_NETBIOS_NAME_SERVERS; - *(Ptr++) = DHCP_OPTION_NETBIOS_NODE_TYPE; - *(Ptr++) = DHCP_OPTION_NETBIOS_SCOPE; - *(Ptr++) = DHCP_OPTION_MAX_MESSAGE_SIZE; + *(Ptr++) = DHCP_OPTION_PARAMETER_REQUEST_LIST; + *(Ptr++) = DHCP_OPTION_COOKIE_SERVER; + *(Ptr++) = DHCP_OPTION_SUBNETMASK; + *(Ptr++) = DHCP_OPTION_ROUTER; + *(Ptr++) = DHCP_OPTION_DOMAIN_NAME_SERVER; + *(Ptr++) = DHCP_OPTION_DOMAIN_NAME; + *(Ptr++) = DHCP_OPTION_NETBIOS_NAME_SERVERS; + *(Ptr++) = DHCP_OPTION_NETBIOS_NODE_TYPE; + *(Ptr++) = DHCP_OPTION_NETBIOS_SCOPE; + *(Ptr++) = DHCP_OPTION_MAX_MESSAGE_SIZE; - *(Ptr++) = DHCP_OPTION_END; - } + *(Ptr++) = DHCP_OPTION_END; + } - void DHCP::Request() - { - netdbg("Requesting IP address"); - DHCPHeader packet; - memset(&packet, 0, sizeof(DHCPHeader)); + void DHCP::Request() + { + netdbg("Requesting IP address"); + DHCPHeader packet; + memset(&packet, 0, sizeof(DHCPHeader)); - CreatePacket(&packet, DHCP_MESSAGE_TYPE_DISCOVER, 0x00000000); - this->UDPSocket->SocketUDP->Send(this->UDPSocket, (uint8_t *)&packet, sizeof(DHCPHeader)); + CreatePacket(&packet, DHCP_MESSAGE_TYPE_DISCOVER, 0x00000000); + this->UDPSocket->SocketUDP->Send(this->UDPSocket, (uint8_t *)&packet, sizeof(DHCPHeader)); - debug("Waiting for response..."); - int RequestTimeout = 20; - while (!Received) - { - if (--RequestTimeout == 0) - { - warn("Request timeout."); - break; - } - netdbg("Still waiting..."); - TaskManager->Sleep(1000); - } - } + debug("Waiting for response..."); + int RequestTimeout = 20; + while (!Received) + { + if (--RequestTimeout == 0) + { + warn("Request timeout."); + break; + } + netdbg("Still waiting..."); + TaskManager->Sleep(1000); + } + } - void DHCP::Request(InternetProtocol IP) - { - netdbg("Requesting IP address %s", IP.v4.ToStringLittleEndian()); - DHCPHeader packet; - memset(&packet, 0, sizeof(DHCPHeader)); + void DHCP::Request(InternetProtocol IP) + { + netdbg("Requesting IP address %s", IP.v4.ToStringLittleEndian()); + DHCPHeader packet; + memset(&packet, 0, sizeof(DHCPHeader)); - /* CreatePacket() accepts IP as MSB */ - CreatePacket(&packet, DHCP_MESSAGE_TYPE_REQUEST, b32(IP.v4.ToHex())); - UDPSocket->SocketUDP->Send(UDPSocket, (uint8_t *)&packet, sizeof(DHCPHeader)); - } + /* CreatePacket() accepts IP as MSB */ + CreatePacket(&packet, DHCP_MESSAGE_TYPE_REQUEST, b32(IP.v4.ToHex())); + UDPSocket->SocketUDP->Send(UDPSocket, (uint8_t *)&packet, sizeof(DHCPHeader)); + } - void *DHCP::GetOption(DHCPHeader *Packet, uint8_t Type) - { - uint8_t *Option = Packet->Options + 4; - uint8_t Current = *Option; - while (Current != 0xFF) - { - uint8_t OptionLength = *(Option + 1); - if (Current == Type) - return Option + 2; - Option += (2 + OptionLength); - Current = *Option; - } - warn("Option %#x not found", Type); - return nullptr; - } + void *DHCP::GetOption(DHCPHeader *Packet, uint8_t Type) + { + uint8_t *Option = Packet->Options + 4; + uint8_t Current = *Option; + while (Current != 0xFF) + { + uint8_t OptionLength = *(Option + 1); + if (Current == Type) + return Option + 2; + Option += (2 + OptionLength); + Current = *Option; + } + warn("Option %#x not found", Type); + return nullptr; + } - __no_sanitize("alignment") void DHCP::OnUDPPacketReceived(NetworkUDP::Socket *Socket, uint8_t *Data, size_t Length) - { - UNUSED(Socket); - UNUSED(Length); - DHCPHeader *Packet = (DHCPHeader *)Data; - uint8_t *MessageType = (uint8_t *)GetOption(Packet, DHCP_OPTION_MESSAGE_TYPE); + __no_sanitize("alignment") void DHCP::OnUDPPacketReceived(NetworkUDP::Socket *Socket, uint8_t *Data, size_t Length) + { + UNUSED(Socket); + UNUSED(Length); + DHCPHeader *Packet = (DHCPHeader *)Data; + uint8_t *MessageType = (uint8_t *)GetOption(Packet, DHCP_OPTION_MESSAGE_TYPE); - switch (*MessageType) - { - case DHCP_OPTION_TIME_OFFSET: - { - InternetProtocol ReqIP; - ReqIP.v4.FromHex(b32(Packet->YourIP)); - netdbg("Received DHCP offer for IP %s", ReqIP.v4.ToStringLittleEndian()); - this->Request(ReqIP); - break; - } - case DHCP_OPTION_NAME_SERVER: - this->IP.v4.FromHex(b32(Packet->YourIP)); - this->Gateway.v4.FromHex(b32((uint32_t)(*(uintptr_t *)GetOption(Packet, DHCP_OPTION_ROUTER)))); - this->DomainNameSystem.v4.FromHex(b32((uint32_t)(*(uintptr_t *)GetOption(Packet, DHCP_OPTION_DOMAIN_NAME_SERVER)))); - this->SubNetworkMask.v4.FromHex(b32((uint32_t)(*(uintptr_t *)GetOption(Packet, DHCP_OPTION_SUBNETMASK)))); - this->Received = true; - netdbg("Received DHCP ACK for IP %s", this->IP.v4.ToStringLittleEndian()); - break; - default: - warn("Received unknown message type %#x", *MessageType); - break; - } - } + switch (*MessageType) + { + case DHCP_OPTION_TIME_OFFSET: + { + InternetProtocol ReqIP; + ReqIP.v4.FromHex(b32(Packet->YourIP)); + netdbg("Received DHCP offer for IP %s", ReqIP.v4.ToStringLittleEndian()); + this->Request(ReqIP); + break; + } + case DHCP_OPTION_NAME_SERVER: + this->IP.v4.FromHex(b32(Packet->YourIP)); + this->Gateway.v4.FromHex(b32((uint32_t)(*(uintptr_t *)GetOption(Packet, DHCP_OPTION_ROUTER)))); + this->DomainNameSystem.v4.FromHex(b32((uint32_t)(*(uintptr_t *)GetOption(Packet, DHCP_OPTION_DOMAIN_NAME_SERVER)))); + this->SubNetworkMask.v4.FromHex(b32((uint32_t)(*(uintptr_t *)GetOption(Packet, DHCP_OPTION_SUBNETMASK)))); + this->Received = true; + netdbg("Received DHCP ACK for IP %s", this->IP.v4.ToStringLittleEndian()); + break; + default: + warn("Received unknown message type %#x", *MessageType); + break; + } + } } diff --git a/network/dns.cpp b/network/dns.cpp index 98c46ad..3180afe 100644 --- a/network/dns.cpp +++ b/network/dns.cpp @@ -22,14 +22,14 @@ namespace NetworkDNS { - DNS::DNS(NetworkUDP::Socket *Socket) : NetworkUDP::UDPEvents() - { - debug("DNS interface %#lx created.", this); - this->UDPSocket = Socket; - } + DNS::DNS(NetworkUDP::Socket *Socket) : NetworkUDP::UDPEvents() + { + debug("DNS interface %#lx created.", this); + this->UDPSocket = Socket; + } - DNS::~DNS() - { - debug("DNS interface %#lx destroyed.", this); - } + DNS::~DNS() + { + debug("DNS interface %#lx destroyed.", this); + } } diff --git a/network/eth.cpp b/network/eth.cpp index 265012f..d042461 100644 --- a/network/eth.cpp +++ b/network/eth.cpp @@ -20,7 +20,7 @@ #include "../kernel.h" -/* conversion from ‘uint48_t’ {aka ‘long unsigned int’} to ‘long unsigned int:48’ may change value */ +/* conversion from 'uint48_t' {aka 'long unsigned int'} to 'long unsigned int:48' may change value */ #pragma GCC diagnostic ignored "-Wconversion" namespace NetworkEthernet @@ -77,7 +77,7 @@ namespace NetworkEthernet /* Byte-swapped little-endian */ if (b48(Packet->Header.DestinationMAC) == 0xFFFFFFFFFFFF || - /* Byte-swapped Module interface has little-endian order */ + /* Byte-swapped Driver interface has little-endian order */ b48(Packet->Header.DestinationMAC) == this->Interface->MAC.ToHex()) /* This is true only if the packet is for us (Interface MAC or broadcast) */ { diff --git a/network/icmp.cpp b/network/icmp.cpp index 1bc3788..3ff792a 100644 --- a/network/icmp.cpp +++ b/network/icmp.cpp @@ -23,55 +23,55 @@ namespace NetworkICMPv4 { - ICMPv4::ICMPv4(NetworkInterfaceManager::DeviceInterface *Interface) - { - debug("ICMPv4 interface %#lx created.", this); - this->Interface = Interface; - } + ICMPv4::ICMPv4(NetworkInterfaceManager::DeviceInterface *Interface) + { + debug("ICMPv4 interface %#lx created.", this); + this->Interface = Interface; + } - ICMPv4::~ICMPv4() - { - debug("ICMPv4 interface %#lx destroyed.", this); - } + ICMPv4::~ICMPv4() + { + debug("ICMPv4 interface %#lx destroyed.", this); + } - void ICMPv4::Send(/* ???? */) - { - fixme("Unimplemented"); - } + void ICMPv4::Send(/* ???? */) + { + fixme("Unimplemented"); + } - void ICMPv4::Receive(ICMPPacket *Packet) - { - if (Packet->Header.Type == ICMPv4Type::TYPE_ECHO) - { - // TODO: This probably doesn't work - netdbg("Echo Request"); - Packet->Header.Type = ICMPv4Type::TYPE_ECHO_REPLY; - Packet->Header.Code = 0x0; - Packet->Header.Checksum = CalculateChecksum((uint16_t *)Packet, sizeof(ICMPHeader)); - NIManager->Send(this->Interface, (uint8_t *)Packet, sizeof(ICMPHeader) + 0); - } - else - { - netdbg("Unknown type %d", Packet->Header.Type); - } - } + void ICMPv4::Receive(ICMPPacket *Packet) + { + if (Packet->Header.Type == ICMPv4Type::TYPE_ECHO) + { + // TODO: This probably doesn't work + netdbg("Echo Request"); + Packet->Header.Type = ICMPv4Type::TYPE_ECHO_REPLY; + Packet->Header.Code = 0x0; + Packet->Header.Checksum = CalculateChecksum((uint16_t *)Packet, sizeof(ICMPHeader)); + NIManager->Send(this->Interface, (uint8_t *)Packet, sizeof(ICMPHeader) + 0); + } + else + { + netdbg("Unknown type %d", Packet->Header.Type); + } + } } namespace NetworkICMPv6 { - ICMPv6::ICMPv6(NetworkInterfaceManager::DeviceInterface *Interface) { this->Interface = Interface; } - ICMPv6::~ICMPv6() {} + ICMPv6::ICMPv6(NetworkInterfaceManager::DeviceInterface *Interface) { this->Interface = Interface; } + ICMPv6::~ICMPv6() {} - void ICMPv6::Send(uint8_t *Data, size_t Length) - { - UNUSED(Data); - UNUSED(Length); - fixme("Unimplemented"); - } + void ICMPv6::Send(uint8_t *Data, size_t Length) + { + UNUSED(Data); + UNUSED(Length); + fixme("Unimplemented"); + } - void ICMPv6::Receive(uint8_t *Data) - { - UNUSED(Data); - fixme("Unimplemented"); - } + void ICMPv6::Receive(uint8_t *Data) + { + UNUSED(Data); + fixme("Unimplemented"); + } } diff --git a/network/ip.cpp b/network/ip.cpp index c6075fc..f714b25 100644 --- a/network/ip.cpp +++ b/network/ip.cpp @@ -22,120 +22,120 @@ namespace NetworkIPv4 { - IPv4::IPv4(NetworkARP::ARP *ARP, NetworkEthernet::Ethernet *Ethernet) : NetworkEthernet::EthernetEvents(NetworkEthernet::TYPE_IPV4) - { - debug("IPv4 interface %#lx created.", this); - this->ARP = ARP; - this->Ethernet = Ethernet; - } + IPv4::IPv4(NetworkARP::ARP *ARP, NetworkEthernet::Ethernet *Ethernet) : NetworkEthernet::EthernetEvents(NetworkEthernet::TYPE_IPV4) + { + debug("IPv4 interface %#lx created.", this); + this->ARP = ARP; + this->Ethernet = Ethernet; + } - IPv4::~IPv4() - { - debug("IPv4 interface %#lx destroyed.", this); - } + IPv4::~IPv4() + { + debug("IPv4 interface %#lx destroyed.", this); + } - void IPv4::Send(uint8_t *Data, size_t Length, uint8_t Protocol, InternetProtocol DestinationIP) - { - netdbg("Sending %ld bytes to %s", Length, DestinationIP.v4.ToStringLittleEndian()); - IPv4Packet *Packet = (IPv4Packet *)kmalloc(Length + sizeof(IPv4Header)); + void IPv4::Send(uint8_t *Data, size_t Length, uint8_t Protocol, InternetProtocol DestinationIP) + { + netdbg("Sending %ld bytes to %s", Length, DestinationIP.v4.ToStringLittleEndian()); + IPv4Packet *Packet = (IPv4Packet *)kmalloc(Length + sizeof(IPv4Header)); - /* This part is the most confusing one for me. */ - Packet->Header.Version = b8(4); - Packet->Header.IHL = b8(sizeof(IPv4Header) / 4); - Packet->Header.TypeOfService = b8(0); - /* We don't byteswap. */ - Packet->Header.TotalLength = s_cst(uint16_t, Length + sizeof(IPv4Header)); - Packet->Header.TotalLength = s_cst(uint16_t, ((Packet->Header.TotalLength & 0xFF00) >> 8) | ((Packet->Header.TotalLength & 0x00FF) << 8)); + /* This part is the most confusing one for me. */ + Packet->Header.Version = b8(4); + Packet->Header.IHL = b8(sizeof(IPv4Header) / 4); + Packet->Header.TypeOfService = b8(0); + /* We don't byteswap. */ + Packet->Header.TotalLength = s_cst(uint16_t, Length + sizeof(IPv4Header)); + Packet->Header.TotalLength = s_cst(uint16_t, ((Packet->Header.TotalLength & 0xFF00) >> 8) | ((Packet->Header.TotalLength & 0x00FF) << 8)); - Packet->Header.Identification = b16(0x0000); - Packet->Header.Flags = b8(0x0); - Packet->Header.FragmentOffset = b8(0x0); - Packet->Header.TimeToLive = b8(64); - Packet->Header.Protocol = b8(Protocol); - Packet->Header.DestinationIP = b32(DestinationIP.v4.ToHex()); - Packet->Header.SourceIP = b32(Ethernet->GetInterface()->IP.v4.ToHex()); - Packet->Header.HeaderChecksum = b16(0x0); - Packet->Header.HeaderChecksum = CalculateChecksum((uint16_t *)Packet, sizeof(IPv4Header)); + Packet->Header.Identification = b16(0x0000); + Packet->Header.Flags = b8(0x0); + Packet->Header.FragmentOffset = b8(0x0); + Packet->Header.TimeToLive = b8(64); + Packet->Header.Protocol = b8(Protocol); + Packet->Header.DestinationIP = b32(DestinationIP.v4.ToHex()); + Packet->Header.SourceIP = b32(Ethernet->GetInterface()->IP.v4.ToHex()); + Packet->Header.HeaderChecksum = b16(0x0); + Packet->Header.HeaderChecksum = CalculateChecksum((uint16_t *)Packet, sizeof(IPv4Header)); - memcpy(Packet->Data, Data, Length); - InternetProtocol DestinationRoute = DestinationIP; - if ((DestinationIP.v4.ToHex() & SubNetworkMaskIP.v4.ToHex()) != (b32(Packet->Header.SourceIP) & SubNetworkMaskIP.v4.ToHex())) - DestinationRoute = SubNetworkMaskIP; + memcpy(Packet->Data, Data, Length); + InternetProtocol DestinationRoute = DestinationIP; + if ((DestinationIP.v4.ToHex() & SubNetworkMaskIP.v4.ToHex()) != (b32(Packet->Header.SourceIP) & SubNetworkMaskIP.v4.ToHex())) + DestinationRoute = SubNetworkMaskIP; - Ethernet->Send(MediaAccessControl().FromHex(ARP->Resolve(DestinationRoute)), this->GetFrameType(), (uint8_t *)Packet, Length + sizeof(IPv4Header)); - kfree(Packet); - } + Ethernet->Send(MediaAccessControl().FromHex(ARP->Resolve(DestinationRoute)), this->GetFrameType(), (uint8_t *)Packet, Length + sizeof(IPv4Header)); + kfree(Packet); + } - std::vector RegisteredEvents; + std::vector RegisteredEvents; - __no_sanitize("alignment") bool IPv4::OnEthernetPacketReceived(uint8_t *Data, size_t Length) - { - IPv4Packet *Packet = (IPv4Packet *)Data; - netdbg("Received %d bytes [Protocol %ld]", Length, Packet->Header.Protocol); - if (Length < sizeof(IPv4Header)) - { - warn("Packet too short"); - return false; - } + __no_sanitize("alignment") bool IPv4::OnEthernetPacketReceived(uint8_t *Data, size_t Length) + { + IPv4Packet *Packet = (IPv4Packet *)Data; + netdbg("Received %d bytes [Protocol %ld]", Length, Packet->Header.Protocol); + if (Length < sizeof(IPv4Header)) + { + warn("Packet too short"); + return false; + } - bool Reply = false; + bool Reply = false; - if (b32(Packet->Header.DestinationIP) == Ethernet->GetInterface()->IP.v4.ToHex() || b32(Packet->Header.DestinationIP) == 0xFFFFFFFF || Ethernet->GetInterface()->IP.v4.ToHex() == 0) - { - size_t TotalLength = Packet->Header.TotalLength; - if (TotalLength > Length) - TotalLength = Length; + if (b32(Packet->Header.DestinationIP) == Ethernet->GetInterface()->IP.v4.ToHex() || b32(Packet->Header.DestinationIP) == 0xFFFFFFFF || Ethernet->GetInterface()->IP.v4.ToHex() == 0) + { + size_t TotalLength = Packet->Header.TotalLength; + if (TotalLength > Length) + TotalLength = Length; - foreach (auto Event in RegisteredEvents) - if (Packet->Header.Protocol == Event->GetProtocol()) - { - InternetProtocol SourceIP; - InternetProtocol DestinationIP; + foreach (auto Event in RegisteredEvents) + if (Packet->Header.Protocol == Event->GetProtocol()) + { + InternetProtocol SourceIP; + InternetProtocol DestinationIP; - SourceIP.v4 = SourceIP.v4.FromHex(b32(Packet->Header.SourceIP)); - DestinationIP.v4 = DestinationIP.v4.FromHex(b32(Packet->Header.DestinationIP)); + SourceIP.v4 = SourceIP.v4.FromHex(b32(Packet->Header.SourceIP)); + DestinationIP.v4 = DestinationIP.v4.FromHex(b32(Packet->Header.DestinationIP)); - if (Event->OnIPv4PacketReceived(SourceIP, DestinationIP, (uint8_t *)((uint64_t)Data + 4 * Packet->Header.IHL), TotalLength - 4 * Packet->Header.IHL)) - Reply = true; - } - } - else - { - netdbg("Not for us. We are %s but this is for %s", - Ethernet->GetInterface()->IP.v4.ToHex(), - Packet->Header.DestinationIP); - } + if (Event->OnIPv4PacketReceived(SourceIP, DestinationIP, (uint8_t *)((uint64_t)Data + 4 * Packet->Header.IHL), TotalLength - 4 * Packet->Header.IHL)) + Reply = true; + } + } + else + { + netdbg("Not for us. We are %s but this is for %s", + Ethernet->GetInterface()->IP.v4.ToHex(), + Packet->Header.DestinationIP); + } - if (Reply) - { - uint32_t SwapIP = Packet->Header.DestinationIP; - Packet->Header.DestinationIP = Packet->Header.SourceIP; - Packet->Header.SourceIP = SwapIP; - Packet->Header.TimeToLive = 0x40; - Packet->Header.HeaderChecksum = 0x0; - Packet->Header.HeaderChecksum = CalculateChecksum((uint16_t *)Data, 4 * Packet->Header.TotalLength); - NIManager->Send(Ethernet->GetInterface(), (uint8_t *)Data, Length); - } - return Reply; - } + if (Reply) + { + uint32_t SwapIP = Packet->Header.DestinationIP; + Packet->Header.DestinationIP = Packet->Header.SourceIP; + Packet->Header.SourceIP = SwapIP; + Packet->Header.TimeToLive = 0x40; + Packet->Header.HeaderChecksum = 0x0; + Packet->Header.HeaderChecksum = CalculateChecksum((uint16_t *)Data, 4 * Packet->Header.TotalLength); + NIManager->Send(Ethernet->GetInterface(), (uint8_t *)Data, Length); + } + return Reply; + } - IPv4Events::IPv4Events(IPv4Protocols Protocol) - { - this->Protocol = (uint8_t)Protocol; - RegisteredEvents.push_back(this); - } + IPv4Events::IPv4Events(IPv4Protocols Protocol) + { + this->Protocol = (uint8_t)Protocol; + RegisteredEvents.push_back(this); + } - IPv4Events::~IPv4Events() - { - forItr(itr, RegisteredEvents) - { - if (*itr == this) - { - RegisteredEvents.erase(itr); - break; - } - } - } + IPv4Events::~IPv4Events() + { + forItr(itr, RegisteredEvents) + { + if (*itr == this) + { + RegisteredEvents.erase(itr); + break; + } + } + } } namespace NetworkIPv6 diff --git a/network/net_dbg.cpp b/network/net_dbg.cpp index 65d9b06..da6b7b1 100644 --- a/network/net_dbg.cpp +++ b/network/net_dbg.cpp @@ -33,64 +33,64 @@ NewLock(netdbg_lock); namespace NetDbg { - class NETWORK_DEBUG : public NetworkInterfaceManager::Events - { - public: - static inline void print_wrapper(char c, void *unused) { UART(COM1).Write(c); } - int vprintf(const char *format, va_list list) { return vfctprintf(print_wrapper, NULL, format, list); } - void WriteRaw(const char *format, ...) - { - va_list args; - va_start(args, format); - vprintf(format, args); - va_end(args); - } + class NETWORK_DEBUG : public NetworkInterfaceManager::Events + { + public: + static inline void print_wrapper(char c, void *unused) { UART(COM1).Write(c); } + int vprintf(const char *format, va_list list) { return vfctprintf(print_wrapper, NULL, format, list); } + void WriteRaw(const char *format, ...) + { + va_list args; + va_start(args, format); + vprintf(format, args); + va_end(args); + } - void DumpData(const char *Description, void *Address, unsigned long Length) - { - SmartLock(netdbg_lock); - WriteRaw("-------------------------------------------------------------------------\n"); - unsigned char *AddressChar = (unsigned char *)Address; - unsigned char Buffer[17]; - unsigned long Iterate; + void DumpData(const char *Description, void *Address, unsigned long Length) + { + SmartLock(netdbg_lock); + WriteRaw("-------------------------------------------------------------------------\n"); + unsigned char *AddressChar = (unsigned char *)Address; + unsigned char Buffer[17]; + unsigned long Iterate; - if (Description != nullptr) - WriteRaw("%s:\n", Description); + if (Description != nullptr) + WriteRaw("%s:\n", Description); - for (Iterate = 0; Iterate < Length; Iterate++) - { - if ((Iterate % 16) == 0) - { - if (Iterate != 0) - WriteRaw(" %s\n", Buffer); - WriteRaw(" %04x ", Iterate); - } + for (Iterate = 0; Iterate < Length; Iterate++) + { + if ((Iterate % 16) == 0) + { + if (Iterate != 0) + WriteRaw(" %s\n", Buffer); + WriteRaw(" %04x ", Iterate); + } - WriteRaw(" %02x", AddressChar[Iterate]); + WriteRaw(" %02x", AddressChar[Iterate]); - if ((AddressChar[Iterate] < 0x20) || (AddressChar[Iterate] > 0x7e)) - Buffer[Iterate % 16] = '.'; - else - Buffer[Iterate % 16] = AddressChar[Iterate]; + if ((AddressChar[Iterate] < 0x20) || (AddressChar[Iterate] > 0x7e)) + Buffer[Iterate % 16] = '.'; + else + Buffer[Iterate % 16] = AddressChar[Iterate]; - Buffer[(Iterate % 16) + 1] = '\0'; - } + Buffer[(Iterate % 16) + 1] = '\0'; + } - while ((Iterate % 16) != 0) - { - WriteRaw(" "); - Iterate++; - } + while ((Iterate % 16) != 0) + { + WriteRaw(" "); + Iterate++; + } - WriteRaw(" %s\n", Buffer); - WriteRaw("-------------------------------------------------------------------------\n"); - } + WriteRaw(" %s\n", Buffer); + WriteRaw("-------------------------------------------------------------------------\n"); + } - NETWORK_DEBUG() : NetworkInterfaceManager::Events(nullptr) { netdbg("NetworkDebugger initialized."); } - ~NETWORK_DEBUG() { netdbg("NetworkDebugger destroyed."); } - void OnInterfaceReceived(NetworkInterfaceManager::DeviceInterface *Interface, uint8_t *Data, size_t Length) { DumpData("Received", Data, Length); } - void OnInterfaceSent(NetworkInterfaceManager::DeviceInterface *Interface, uint8_t *Data, size_t Length) { DumpData("Sent", Data, Length); } - }; + NETWORK_DEBUG() : NetworkInterfaceManager::Events(nullptr) { netdbg("NetworkDebugger initialized."); } + ~NETWORK_DEBUG() { netdbg("NetworkDebugger destroyed."); } + void OnInterfaceReceived(NetworkInterfaceManager::DeviceInterface *Interface, uint8_t *Data, size_t Length) { DumpData("Received", Data, Length); } + void OnInterfaceSent(NetworkInterfaceManager::DeviceInterface *Interface, uint8_t *Data, size_t Length) { DumpData("Sent", Data, Length); } + }; } NetDbg::NETWORK_DEBUG *N; diff --git a/network/network_controller.cpp b/network/network_controller.cpp index 229bee4..caf465e 100644 --- a/network/network_controller.cpp +++ b/network/network_controller.cpp @@ -27,8 +27,6 @@ #include #include "../kernel.h" -#include "../mapi.hpp" -#include "../Fex.hpp" /* FIXME: The functions MUST have little endian parameters and return values. */ @@ -39,14 +37,15 @@ namespace NetworkInterfaceManager NetworkInterface::NetworkInterface() { this->vma = new Memory::VirtualMemoryArea(nullptr); - if (ModuleManager->GetModules().size() > 0) - { - foreach (auto Module in ModuleManager->GetModules()) - if (((FexExtended *)Module.ExtendedHeaderAddress)->Module.Type == FexModuleType::FexModuleType_Network) - this->FetchNetworkCards(Module.modUniqueID); - } - else - KPrint("\eE85230No network drivers found! Cannot fetch network cards!"); + /* KernelCallback */ + // if (DriverManager->GetModules().size() > 0) + // { + // foreach (auto Driver in DriverManager->GetModules()) + // if (((FexExtended *)Driver.ExtendedHeaderAddress)->Driver.Type == FexDriverType::FexDriverType_Network) + // this->FetchNetworkCards(Driver.modUniqueID); + // } + // else + // KPrint("\eE85230No network drivers found! Cannot fetch network cards!"); DbgNetwork(); } @@ -70,14 +69,15 @@ namespace NetworkInterfaceManager void NetworkInterface::FetchNetworkCards(unsigned long modUniqueID) { - KernelCallback cb{}; - cb.Reason = QueryReason; - ModuleManager->IOCB(modUniqueID, &cb); + // KernelCallback cb{}; + // cb.Reason = QueryReason; + // DriverManager->IOCB(modUniqueID, &cb); + /* KernelCallback */ DeviceInterface *Iface = (DeviceInterface *)vma->RequestPages(TO_PAGES(sizeof(DeviceInterface) + 1)); - strcpy(Iface->Name, cb.NetworkCallback.Fetch.Name); + // strcpy(Iface->Name, cb.NetworkCallback.Fetch.Name); Iface->ID = this->CardIDs++; - Iface->MAC.FromHex(cb.NetworkCallback.Fetch.MAC); + // Iface->MAC.FromHex(cb.NetworkCallback.Fetch.MAC); Iface->DriverID = modUniqueID; Interfaces.push_back(Iface); @@ -98,62 +98,68 @@ namespace NetworkInterfaceManager thisThread->SetPriority(Tasking::TaskPriority::Critical); DeviceInterface *DefaultDevice = nullptr; foreach (auto inf in Interfaces) + { if (inf) { DefaultDevice = inf; break; } + } if (!DefaultDevice) - error("No network device found!"); - else { - DbgWriteScreen("Using %s (%s) as the default network device", DefaultDevice->Name, DefaultDevice->MAC.ToString()); - NetworkEthernet::Ethernet *eth = new NetworkEthernet::Ethernet(DefaultDevice); // Use the first device found as the ethernet device - NetworkARP::ARP *arp = new NetworkARP::ARP(eth); - NetworkIPv4::IPv4 *ipv4 = new NetworkIPv4::IPv4(arp, eth); - NetworkUDP::UDP *udp = new NetworkUDP::UDP(ipv4, DefaultDevice); - NetworkUDP::Socket *DHCP_Socket = udp->Connect(InternetProtocol() /* Default value is 255.255.255.255 */, 67); - NetworkDHCP::DHCP *dhcp = new NetworkDHCP::DHCP(DHCP_Socket, DefaultDevice); - debug("eth: %p; arp: %p; ipv4: %p; udp: %p; dhcp: %p", - eth, arp, ipv4, udp, dhcp); - udp->Bind(DHCP_Socket, dhcp); - dhcp->Request(); - - DefaultDevice->IP.v4.FromHex(dhcp->IP.v4.ToHex()); - ipv4->SubNetworkMaskIP = dhcp->SubNetworkMask; - ipv4->GatewayIP = dhcp->Gateway; - arp->Broadcast(dhcp->Gateway); - TaskManager->Sleep(200); - DbgWriteScreen("IP: %s", dhcp->IP.v4.ToStringLittleEndian()); - DbgWriteScreen("SubNetwork Mask: %s", dhcp->SubNetworkMask.v4.ToStringLittleEndian()); - DbgWriteScreen("Gateway: %s", dhcp->Gateway.v4.ToStringLittleEndian()); - DbgWriteScreen("DNS: %s", dhcp->DomainNameSystem.v4.ToStringLittleEndian()); - TaskManager->Sleep(200); - - /* TODO: This is a quick workaround we need DNS resolver asap. - - https://tf.nist.gov/tf-cgi/servers.cgi - https://www.ntppool.org - - - 0.ro.pool.ntp.org ( {86, 127, 71, 168} ) - - time-a-g.nist.gov ( {129, 6, 15, 28} ) - */ - // InternetProtocol ip = {.v4 = {.Address = {129, 6, 15, 28}}, - // .v6 = {.Address = {}}}; - // NetworkUDP::Socket *NTP_Socket = udp->Connect(ip, 123); - // NetworkNTP::NTP *ntp = new NetworkNTP::NTP(NTP_Socket); - // udp->Bind(NTP_Socket, ntp); - // int UnixTimestamp = ntp->ReadTime(); - // Time::Clock time = Time::ConvertFromUnix(UnixTimestamp); - // DbgWriteScreen("NTP: %d - %d.%d.%d %d:%d:%d", time.Counter, - // time.Day, time.Month, time.Year, - // time.Hour, time.Minute, time.Second); - TaskManager->Sleep(200); - - /* TODO: Store everything in an vector and initialize all network cards */ + error("No network device found!"); + KPrint("\eE85230No network device found!"); + thisThread->SetPriority(Tasking::TaskPriority::Idle); + CPU::Halt(true); } + KPrint("Using %s (%s) as the default network device", + DefaultDevice->Name, DefaultDevice->MAC.ToString()); + NetworkEthernet::Ethernet *eth = new NetworkEthernet::Ethernet(DefaultDevice); // Use the first device found as the ethernet device + NetworkARP::ARP *arp = new NetworkARP::ARP(eth); + NetworkIPv4::IPv4 *ipv4 = new NetworkIPv4::IPv4(arp, eth); + NetworkUDP::UDP *udp = new NetworkUDP::UDP(ipv4, DefaultDevice); + NetworkUDP::Socket *DHCP_Socket = udp->Connect(InternetProtocol() /* Default value is 255.255.255.255 */, 67); + NetworkDHCP::DHCP *dhcp = new NetworkDHCP::DHCP(DHCP_Socket, DefaultDevice); + debug("eth: %p; arp: %p; ipv4: %p; udp: %p; dhcp: %p", + eth, arp, ipv4, udp, dhcp); + udp->Bind(DHCP_Socket, dhcp); + dhcp->Request(); + + DefaultDevice->IP.v4.FromHex(dhcp->IP.v4.ToHex()); + ipv4->SubNetworkMaskIP = dhcp->SubNetworkMask; + ipv4->GatewayIP = dhcp->Gateway; + arp->Broadcast(dhcp->Gateway); + TaskManager->Sleep(200); + DbgWriteScreen("IP: %s", dhcp->IP.v4.ToStringLittleEndian()); + DbgWriteScreen("SubNetwork Mask: %s", dhcp->SubNetworkMask.v4.ToStringLittleEndian()); + DbgWriteScreen("Gateway: %s", dhcp->Gateway.v4.ToStringLittleEndian()); + DbgWriteScreen("DNS: %s", dhcp->DomainNameSystem.v4.ToStringLittleEndian()); + TaskManager->Sleep(200); + + /* TODO: This is a quick workaround we need DNS resolver asap. + + https://tf.nist.gov/tf-cgi/servers.cgi + https://www.ntppool.org + + - 0.ro.pool.ntp.org ( {86, 127, 71, 168} ) + - time-a-g.nist.gov ( {129, 6, 15, 28} ) + */ + // InternetProtocol ip = {.v4 = {.Address = {129, 6, 15, 28}}, + // .v6 = {.Address = {}}}; + // NetworkUDP::Socket *NTP_Socket = udp->Connect(ip, 123); + // NetworkNTP::NTP *ntp = new NetworkNTP::NTP(NTP_Socket); + // udp->Bind(NTP_Socket, ntp); + // int UnixTimestamp = ntp->ReadTime(); + // Time::Clock time = Time::ConvertFromUnix(UnixTimestamp); + // DbgWriteScreen("NTP: %d - %d.%d.%d %d:%d:%d", time.Counter, + // time.Day, time.Month, time.Year, + // time.Hour, time.Minute, time.Second); + TaskManager->Sleep(200); + + /* TODO: Store everything in an vector and initialize all network cards */ + thisThread->SetPriority(Tasking::TaskPriority::Idle); CPU::Halt(true); } @@ -190,11 +196,12 @@ namespace NetworkInterfaceManager void *DataToBeSent = vma->RequestPages(TO_PAGES(Length + 1)); memcpy(DataToBeSent, Data, Length); - KernelCallback cb{}; - cb.Reason = SendReason; - cb.NetworkCallback.Send.Data = (uint8_t *)DataToBeSent; - cb.NetworkCallback.Send.Length = Length; - ModuleManager->IOCB(Interface->DriverID, &cb); + /* KernelCallback */ + // KernelCallback cb{}; + // cb.Reason = SendReason; + // cb.NetworkCallback.Send.Data = (uint8_t *)DataToBeSent; + // cb.NetworkCallback.Send.Length = Length; + // DriverManager->IOCB(Interface->DriverID, &cb); vma->FreePages(DataToBeSent, TO_PAGES(Length + 1)); foreach (auto ev in RegisteredEvents) diff --git a/network/ntp.cpp b/network/ntp.cpp index 9fe7717..15ebc36 100644 --- a/network/ntp.cpp +++ b/network/ntp.cpp @@ -22,54 +22,54 @@ namespace NetworkNTP { - void NTP::OnUDPPacketReceived(NetworkUDP::Socket *Socket, uint8_t *Data, size_t Length) - { - UNUSED(Socket); - UNUSED(Length); - this->NTPPacket = *(NTPHeader *)Data; - this->TimeReceived = true; - netdbg("Received UDP packet for NTP."); - } + void NTP::OnUDPPacketReceived(NetworkUDP::Socket *Socket, uint8_t *Data, size_t Length) + { + UNUSED(Socket); + UNUSED(Length); + this->NTPPacket = *(NTPHeader *)Data; + this->TimeReceived = true; + netdbg("Received UDP packet for NTP."); + } - NTP::NTP(NetworkUDP::Socket *Socket) : NetworkUDP::UDPEvents() - { - debug("NTP interface %#lx created.", this); - this->UDPSocket = Socket; - } + NTP::NTP(NetworkUDP::Socket *Socket) : NetworkUDP::UDPEvents() + { + debug("NTP interface %#lx created.", this); + this->UDPSocket = Socket; + } - NTP::~NTP() - { - debug("NTP interface %#lx destroyed.", this); - } + NTP::~NTP() + { + debug("NTP interface %#lx destroyed.", this); + } - int NTP::ReadTime() - { - netdbg("Requesting time"); - this->TimeReceived = false; + int NTP::ReadTime() + { + netdbg("Requesting time"); + this->TimeReceived = false; - NTPHeader ReqPacket; // This may require physical memory allocation but Ethernet already has this job. - memset(&ReqPacket, 0, sizeof(NTPHeader)); // Zero out the packet - *((char *)&ReqPacket) = 0x1b; // byteswap nightmare, this is the code below but in little endian - // ReqPacket.LeapIndicator = 0; - // ReqPacket.VersionNumber = 3; - // ReqPacket.Mode = 3; - UDPSocket->SocketUDP->Send(UDPSocket, (uint8_t *)&ReqPacket, sizeof(NTPHeader)); + NTPHeader ReqPacket; // This may require physical memory allocation but Ethernet already has this job. + memset(&ReqPacket, 0, sizeof(NTPHeader)); // Zero out the packet + *((char *)&ReqPacket) = 0x1b; // byteswap nightmare, this is the code below but in little endian + // ReqPacket.LeapIndicator = 0; + // ReqPacket.VersionNumber = 3; + // ReqPacket.Mode = 3; + UDPSocket->SocketUDP->Send(UDPSocket, (uint8_t *)&ReqPacket, sizeof(NTPHeader)); - debug("Waiting for response..."); - int RequestTimeout = 20; - while (!this->TimeReceived) - { - if (--RequestTimeout == 0) - { - warn("Request timeout."); - return 0; - } - netdbg("Still waiting..."); - TaskManager->Sleep(1000); - } + debug("Waiting for response..."); + int RequestTimeout = 20; + while (!this->TimeReceived) + { + if (--RequestTimeout == 0) + { + warn("Request timeout."); + return 0; + } + netdbg("Still waiting..."); + TaskManager->Sleep(1000); + } - uint64_t UnixTimestamp = (b32(this->NTPPacket.TransmitTimestamp[0])) - 2208988800; - debug("Unix time: %d", UnixTimestamp); - return s_cst(int, UnixTimestamp); - } + uint64_t UnixTimestamp = (b32(this->NTPPacket.TransmitTimestamp[0])) - 2208988800; + debug("Unix time: %d", UnixTimestamp); + return s_cst(int, UnixTimestamp); + } } diff --git a/network/udp.cpp b/network/udp.cpp index 3791b08..cb2f1c2 100644 --- a/network/udp.cpp +++ b/network/udp.cpp @@ -22,124 +22,124 @@ namespace NetworkUDP { - struct EventInfo - { - Socket *UDPSocket; - uint16_t Port; - }; - std::vector RegisteredEvents; + struct EventInfo + { + Socket *UDPSocket; + uint16_t Port; + }; + std::vector RegisteredEvents; - UDPEvents::UDPEvents() {} + UDPEvents::UDPEvents() {} - UDPEvents::~UDPEvents() {} + UDPEvents::~UDPEvents() {} - /* -------------------------------------------------------------------------------------------------------------------------------- */ + /* -------------------------------------------------------------------------------------------------------------------------------- */ - UDP::UDP(NetworkIPv4::IPv4 *ipv4, NetworkInterfaceManager::DeviceInterface *Interface) : NetworkIPv4::IPv4Events(NetworkIPv4::PROTOCOL_UDP) - { - debug("UDP interface %#lx created.", this); - this->ipv4 = ipv4; - this->Interface = Interface; - } + UDP::UDP(NetworkIPv4::IPv4 *ipv4, NetworkInterfaceManager::DeviceInterface *Interface) : NetworkIPv4::IPv4Events(NetworkIPv4::PROTOCOL_UDP) + { + debug("UDP interface %#lx created.", this); + this->ipv4 = ipv4; + this->Interface = Interface; + } - UDP::~UDP() - { - debug("UDP interface %#lx destroyed.", this); - } + UDP::~UDP() + { + debug("UDP interface %#lx destroyed.", this); + } - uint16_t UsablePort = 0x200; + uint16_t UsablePort = 0x200; - Socket *UDP::Connect(InternetProtocol IP, uint16_t Port) - { - netdbg("Connecting to %s", IP.v4.ToStringLittleEndian(), Port); - Socket *socket = new Socket(this); - socket->RemoteIP = IP; - socket->RemotePort = Port; - socket->LocalPort = UsablePort++; // TODO: track ports - socket->LocalIP = Interface->IP; - socket->LocalPort = b16(socket->LocalPort); - socket->RemotePort = b16(socket->RemotePort); - RegisteredEvents.push_back({.UDPSocket = socket, .Port = socket->LocalPort}); - return socket; - } + Socket *UDP::Connect(InternetProtocol IP, uint16_t Port) + { + netdbg("Connecting to %s", IP.v4.ToStringLittleEndian(), Port); + Socket *socket = new Socket(this); + socket->RemoteIP = IP; + socket->RemotePort = Port; + socket->LocalPort = UsablePort++; // TODO: track ports + socket->LocalIP = Interface->IP; + socket->LocalPort = b16(socket->LocalPort); + socket->RemotePort = b16(socket->RemotePort); + RegisteredEvents.push_back({.UDPSocket = socket, .Port = socket->LocalPort}); + return socket; + } - Socket *UDP::Listen(uint16_t Port) - { - UNUSED(Port); - fixme("Not implemented."); - return nullptr; - } + Socket *UDP::Listen(uint16_t Port) + { + UNUSED(Port); + fixme("Not implemented."); + return nullptr; + } - void UDP::Disconnect(Socket *Socket) - { - UNUSED(Socket); - fixme("Not implemented."); - } + void UDP::Disconnect(Socket *Socket) + { + UNUSED(Socket); + fixme("Not implemented."); + } - void UDP::Send(Socket *Socket, uint8_t *Data, size_t Length) - { - netdbg("Sending %d bytes to %s", Length, Socket->RemoteIP.v4.ToStringLittleEndian(), Socket->RemotePort); - uint16_t TotalLength = s_cst(uint16_t, Length + sizeof(UDPHeader)); - UDPPacket *packet = (UDPPacket *)kmalloc(TotalLength); - packet->Header.SourcePort = Socket->LocalPort; - packet->Header.DestinationPort = Socket->RemotePort; - packet->Header.Length = b16(TotalLength); - memcpy(packet->Data, Data, Length); - packet->Header.Checksum = 0; // I totally should do this. Some devices may require it. - // packet->Header.Checksum = CalculateChecksum((uint16_t *)packet, TotalLength); - this->ipv4->Send((uint8_t *)packet, TotalLength, 0x11, Socket->RemoteIP); - kfree(packet); - } + void UDP::Send(Socket *Socket, uint8_t *Data, size_t Length) + { + netdbg("Sending %d bytes to %s", Length, Socket->RemoteIP.v4.ToStringLittleEndian(), Socket->RemotePort); + uint16_t TotalLength = s_cst(uint16_t, Length + sizeof(UDPHeader)); + UDPPacket *packet = (UDPPacket *)kmalloc(TotalLength); + packet->Header.SourcePort = Socket->LocalPort; + packet->Header.DestinationPort = Socket->RemotePort; + packet->Header.Length = b16(TotalLength); + memcpy(packet->Data, Data, Length); + packet->Header.Checksum = 0; // I totally should do this. Some devices may require it. + // packet->Header.Checksum = CalculateChecksum((uint16_t *)packet, TotalLength); + this->ipv4->Send((uint8_t *)packet, TotalLength, 0x11, Socket->RemoteIP); + kfree(packet); + } - void UDP::Bind(Socket *Socket, UDPEvents *EventHandler) - { - netdbg("Binding socket to %s", Socket->LocalIP.v4.ToStringLittleEndian(), Socket->LocalPort); - Socket->EventHandler = EventHandler; - } + void UDP::Bind(Socket *Socket, UDPEvents *EventHandler) + { + netdbg("Binding socket to %s", Socket->LocalIP.v4.ToStringLittleEndian(), Socket->LocalPort); + Socket->EventHandler = EventHandler; + } - bool UDP::OnIPv4PacketReceived(InternetProtocol SourceIP, InternetProtocol DestinationIP, uint8_t *Data, size_t Length) - { - netdbg("Received %d bytes from %s", Length, SourceIP.v4.ToStringLittleEndian()); - if (Length < sizeof(UDPHeader)) - return false; + bool UDP::OnIPv4PacketReceived(InternetProtocol SourceIP, InternetProtocol DestinationIP, uint8_t *Data, size_t Length) + { + netdbg("Received %d bytes from %s", Length, SourceIP.v4.ToStringLittleEndian()); + if (Length < sizeof(UDPHeader)) + return false; - UDPHeader *udp = (UDPHeader *)Data; + UDPHeader *udp = (UDPHeader *)Data; - netdbg("SP:%d | DP:%d | L:%d | CHK:%#x", b16(udp->SourcePort), b16(udp->DestinationPort), b16(udp->Length), b16(udp->Checksum)); + netdbg("SP:%d | DP:%d | L:%d | CHK:%#x", b16(udp->SourcePort), b16(udp->DestinationPort), b16(udp->Length), b16(udp->Checksum)); - Socket *GoodSocket = nullptr; + Socket *GoodSocket = nullptr; - foreach (auto &var in RegisteredEvents) - { - netdbg("UDP->SKT[]: LP:%d | LIP:%s | RP:%d | RIP:%s | LST:%d", - b16(var.UDPSocket->LocalPort), - var.UDPSocket->LocalIP.v4.ToStringLittleEndian(), - b16(var.UDPSocket->RemotePort), - var.UDPSocket->RemoteIP.v4.ToStringLittleEndian(), - b16(var.UDPSocket->Listening)); - if (var.UDPSocket->LocalPort == udp->DestinationPort && - var.UDPSocket->LocalIP.v4 == DestinationIP.v4 && - var.UDPSocket->Listening == true) - { - var.UDPSocket->Listening = false; - var.UDPSocket->RemotePort = b16(udp->SourcePort); - var.UDPSocket->RemoteIP = SourceIP; - netdbg("E1"); - return true; - } + foreach (auto &var in RegisteredEvents) + { + netdbg("UDP->SKT[]: LP:%d | LIP:%s | RP:%d | RIP:%s | LST:%d", + b16(var.UDPSocket->LocalPort), + var.UDPSocket->LocalIP.v4.ToStringLittleEndian(), + b16(var.UDPSocket->RemotePort), + var.UDPSocket->RemoteIP.v4.ToStringLittleEndian(), + b16(var.UDPSocket->Listening)); + if (var.UDPSocket->LocalPort == udp->DestinationPort && + var.UDPSocket->LocalIP.v4 == DestinationIP.v4 && + var.UDPSocket->Listening == true) + { + var.UDPSocket->Listening = false; + var.UDPSocket->RemotePort = b16(udp->SourcePort); + var.UDPSocket->RemoteIP = SourceIP; + netdbg("E1"); + return true; + } - GoodSocket = var.UDPSocket; - } - if (GoodSocket) - GoodSocket->EventHandler->OnUDPPacketReceived(GoodSocket, ((UDPPacket *)Data)->Data, Length); + GoodSocket = var.UDPSocket; + } + if (GoodSocket) + GoodSocket->EventHandler->OnUDPPacketReceived(GoodSocket, ((UDPPacket *)Data)->Data, Length); - netdbg("E0 (Success)"); - return false; - } + netdbg("E0 (Success)"); + return false; + } - /* -------------------------------------------------------------------------------------------------------------------------------- */ + /* -------------------------------------------------------------------------------------------------------------------------------- */ - Socket::Socket(UDP *_UDP) { this->SocketUDP = _UDP; } + Socket::Socket(UDP *_UDP) { this->SocketUDP = _UDP; } - Socket::~Socket() {} + Socket::~Socket() {} } diff --git a/profiling/cyg.cpp b/profiling/cyg.cpp index a12f83e..841d7e0 100644 --- a/profiling/cyg.cpp +++ b/profiling/cyg.cpp @@ -30,84 +30,84 @@ UART com2(COM2); static inline SafeFunction NIF void profiler_uart_wrapper(char c, void *unused) { - bool renable = EnableProfiler; - EnableProfiler = false; - com2.Write(c); - UNUSED(unused); - if (renable) - EnableProfiler = true; + bool renable = EnableProfiler; + EnableProfiler = false; + com2.Write(c); + UNUSED(unused); + if (renable) + EnableProfiler = true; } EXTERNC SafeFunction NIF void __cyg_profile_func_enter(void *Function, void *CallSite) { - if (!EnableProfiler) - return; + if (!EnableProfiler) + return; - while (Wait) + while (Wait) #if defined(a86) - asmv("pause"); + asmv("pause"); #elif defined(aa64) - asmv("yield"); + asmv("yield"); #endif - Wait = true; + Wait = true; - if (Level > 40) - Level--; + if (Level > 40) + Level--; - Level++; + Level++; - if (!KernelSymbolTable) - fctprintf(profiler_uart_wrapper, nullptr, "%lld [%02d]: \033[42m->\033[0m%*c \033[33m%p\033[0m - \033[33m%p\033[0m\n", - LogDepth++, - Level - 1, - Level, - ' ', - Function, - CallSite); - else - fctprintf(profiler_uart_wrapper, nullptr, "%lld [%02d]: \033[42m->\033[0m%*c \033[33m%s\033[0m - \033[33m%s\033[0m\n", - LogDepth++, - Level - 1, - Level, - ' ', - KernelSymbolTable->GetSymbolFromAddress((uintptr_t)Function), - KernelSymbolTable->GetSymbolFromAddress((uintptr_t)CallSite)); - Wait = false; + if (!KernelSymbolTable) + fctprintf(profiler_uart_wrapper, nullptr, "%lld [%02d]: \033[42m->\033[0m%*c \033[33m%p\033[0m - \033[33m%p\033[0m\n", + LogDepth++, + Level - 1, + Level, + ' ', + Function, + CallSite); + else + fctprintf(profiler_uart_wrapper, nullptr, "%lld [%02d]: \033[42m->\033[0m%*c \033[33m%s\033[0m - \033[33m%s\033[0m\n", + LogDepth++, + Level - 1, + Level, + ' ', + KernelSymbolTable->GetSymbol((uintptr_t)Function), + KernelSymbolTable->GetSymbol((uintptr_t)CallSite)); + Wait = false; } EXTERNC SafeFunction NIF void __cyg_profile_func_exit(void *Function, void *CallSite) { - if (!EnableProfiler) - return; + if (!EnableProfiler) + return; - while (Wait) + while (Wait) #if defined(a86) - asmv("pause"); + asmv("pause"); #elif defined(aa64) - asmv("yield"); + asmv("yield"); #endif - Wait = true; + Wait = true; - if (Level > 40) - Level--; + if (Level > 40) + Level--; - Level--; + Level--; - if (!KernelSymbolTable) - fctprintf(profiler_uart_wrapper, nullptr, "%lld [%02d]: \033[41m<-\033[0m%*c \033[33m%p\033[0m - \033[33m%p\033[0m\n", - LogDepth++, - Level - 1, - Level, - ' ', - Function, - CallSite); - else - fctprintf(profiler_uart_wrapper, nullptr, "%lld [%02d]: \033[41m<-\033[0m%*c \033[33m%s\033[0m - \033[33m%s\033[0m\n", - LogDepth++, - Level - 1, - Level, - ' ', - KernelSymbolTable->GetSymbolFromAddress((uintptr_t)Function), - KernelSymbolTable->GetSymbolFromAddress((uintptr_t)CallSite)); - Wait = false; + if (!KernelSymbolTable) + fctprintf(profiler_uart_wrapper, nullptr, "%lld [%02d]: \033[41m<-\033[0m%*c \033[33m%p\033[0m - \033[33m%p\033[0m\n", + LogDepth++, + Level - 1, + Level, + ' ', + Function, + CallSite); + else + fctprintf(profiler_uart_wrapper, nullptr, "%lld [%02d]: \033[41m<-\033[0m%*c \033[33m%s\033[0m - \033[33m%s\033[0m\n", + LogDepth++, + Level - 1, + Level, + ' ', + KernelSymbolTable->GetSymbol((uintptr_t)Function), + KernelSymbolTable->GetSymbol((uintptr_t)CallSite)); + Wait = false; } diff --git a/profiling/gcov.cpp b/profiling/gcov.cpp index c3d4866..8a47261 100644 --- a/profiling/gcov.cpp +++ b/profiling/gcov.cpp @@ -31,34 +31,34 @@ typedef long long gcov_type; struct gcov_fn_info { - unsigned int ident; - unsigned int checksum; - unsigned int n_ctrs[0]; + unsigned int ident; + unsigned int checksum; + unsigned int n_ctrs[0]; }; struct gcov_ctr_info { - unsigned int num; - gcov_type *values; - void (*merge)(gcov_type *, unsigned int); + unsigned int num; + gcov_type *values; + void (*merge)(gcov_type *, unsigned int); }; struct gcov_info { - unsigned int version; - struct gcov_info *next; - unsigned int stamp; - const char *filename; - unsigned int n_functions; - const struct gcov_fn_info *functions; - unsigned int ctr_mask; - struct gcov_ctr_info counts[0]; + unsigned int version; + struct gcov_info *next; + unsigned int stamp; + const char *filename; + unsigned int n_functions; + const struct gcov_fn_info *functions; + unsigned int ctr_mask; + struct gcov_ctr_info counts[0]; }; static inline SafeFunction NIF void gcov_uart_wrapper(char c, void *unused) { - UART(COM2).Write(c); - UNUSED(unused); + UART(COM2).Write(c); + UNUSED(unused); } // TODO: Implement @@ -77,12 +77,12 @@ EXTERNC SafeFunction NIF void __gcov_flush(void) EXTERNC SafeFunction NIF void __gcov_merge_add(gcov_type *counters, unsigned int n_counters) { - UNUSED(counters); - UNUSED(n_counters); + UNUSED(counters); + UNUSED(n_counters); } EXTERNC SafeFunction NIF void __gcov_merge_single(gcov_type *counters, unsigned int n_counters) { - UNUSED(counters); - UNUSED(n_counters); + UNUSED(counters); + UNUSED(n_counters); } diff --git a/profiling/gprof.cpp b/profiling/gprof.cpp index afd3d4b..da5a3ba 100644 --- a/profiling/gprof.cpp +++ b/profiling/gprof.cpp @@ -25,14 +25,14 @@ using namespace UniversalAsynchronousReceiverTransmitter; static inline SafeFunction NIF void gprof_uart_wrapper(char c, void *unused) { - UART(COM2).Write(c); - UNUSED(unused); + UART(COM2).Write(c); + UNUSED(unused); } EXTERNC SafeFunction NIF void mcount(unsigned long frompc, unsigned long selfpc) { - // TODO: Implement - /* https://docs.kernel.org/trace/ftrace-design.html */ - UNUSED(frompc); - UNUSED(selfpc); + // TODO: Implement + /* https://docs.kernel.org/trace/ftrace-design.html */ + UNUSED(frompc); + UNUSED(selfpc); } diff --git a/storage/README.md b/storage/README.md new file mode 100644 index 0000000..aebd7bc --- /dev/null +++ b/storage/README.md @@ -0,0 +1,37 @@ +# File System Implementation + +--- + +## Nodes + +### /storage + +- `node.cpp` + - **ref_node <=> device** + - Handles open/close/read/write operations for the device + +
+ +- `ref_node.cpp` + - **kernel/user <=> node.cpp** + - Maintains the count of references to a node and the seek position + +
+ +- `file_descriptor.cpp` + - **user <=> ref_node.cpp** + - Manages the file descriptor table for user processes + +
+ +- `kernel_io.cpp` + - **kernel <=> file_descriptor.cpp** + - Performs a similar role as `file_descriptor.cpp` but for kernel processes + +### /storage/fs + +This directory contains the implementations of various file systems, such as `fat32.cpp` and `ustar.cpp`. + +### /storage/devices + +This directory houses implementations of various devices, including /dev/null, /dev/zero, /dev/random, and more. diff --git a/storage/fs/null.cpp b/storage/devices/null.cpp similarity index 100% rename from storage/fs/null.cpp rename to storage/devices/null.cpp diff --git a/storage/fs/random.cpp b/storage/devices/random.cpp similarity index 100% rename from storage/fs/random.cpp rename to storage/devices/random.cpp diff --git a/storage/fs/root.cpp b/storage/devices/root.cpp similarity index 100% rename from storage/fs/root.cpp rename to storage/devices/root.cpp diff --git a/storage/devices/tty/kcon.cpp b/storage/devices/tty/kcon.cpp new file mode 100644 index 0000000..abc8562 --- /dev/null +++ b/storage/devices/tty/kcon.cpp @@ -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 . +*/ + +#include +#include +#include +#include + +#include "../../../kernel.h" + +namespace vfs +{ + size_t KConDevice::read(uint8_t *Buffer, size_t Size, off_t Offset) + { + return DriverManager->InputKeyboardDev->read(Buffer, Size, Offset); + } + + size_t KConDevice::write(uint8_t *Buffer, size_t Size, off_t Offset) + { + if (Offset != 0) + fixme("Offset is %d", Offset); + + for (size_t i = 0; i < Size; i++) + putchar(((char *)Buffer)[i]); + + if (!Config.Quiet) + Display->SetBuffer(0); + return Size; + } + + int KConDevice::ioctl(unsigned long Request, void *Argp) + { + static_assert(sizeof(struct termios) < PAGE_SIZE); + + void *pArgp = thisProcess->PageTable->Get(Argp); + switch (Request) + { + case TCGETS: + { + struct termios *t = (struct termios *)pArgp; + memcpy(t, &this->term, sizeof(struct termios)); + break; + } + case TCSETS: + { + struct termios *t = (struct termios *)pArgp; + memcpy(&this->term, t, sizeof(struct termios)); + break; + } + case TCSETSW: + case TCSETSF: + case TCGETA: + case TCSETA: + case TCSETAW: + case TCSETAF: + case TCSBRK: + case TCXONC: + case TCFLSH: + case TIOCEXCL: + case TIOCNXCL: + case TIOCSCTTY: + case TIOCGPGRP: + case TIOCSPGRP: + case TIOCOUTQ: + case TIOCSTI: + { + fixme("ioctl %#lx not implemented", Request); + return -ENOSYS; + } + case TIOCGWINSZ: + { + struct winsize *ws = (struct winsize *)pArgp; + memcpy(ws, &this->termSize, sizeof(struct winsize)); + break; + } + case TIOCSWINSZ: + { + struct winsize *ws = (struct winsize *)pArgp; + memcpy(&this->termSize, ws, sizeof(struct winsize)); + break; + } + case TIOCMGET: + case TIOCMBIS: + case TIOCMBIC: + case TIOCMSET: + { + fixme("ioctl %#lx not implemented", Request); + return -ENOSYS; + } + case TIOCGPTN: + case 0xffffffff80045430: /* FIXME: ???? */ + { + int *n = (int *)pArgp; + *n = -1; + break; + } + case TIOCSPTLCK: + { + int *n = (int *)pArgp; + *n = 0; + break; + } + default: + { + debug("Unknown ioctl %#lx", Request); + return -EINVAL; + } + } + + return 0; + } + + KConDevice::KConDevice() : Node(DevFS, "kcon", CHARDEVICE) + { + /* + - ICRNL - Map Carriage Return to New Line + - IXON - Enable XON/XOFF flow control + + - OPOST - Enable output processing + - ONLCR - Map New Line to Carriage Return - New Line + + - CS8 - 8-bit characters + - CREAD - Enable receiver + - HUPCL - Hang up on last close + + - ECHO - Echo input characters + - ICANON - Enable canonical input (enable line editing) + */ + this->term.c_iflag = /*ICRNL |*/ IXON; + this->term.c_oflag = OPOST | ONLCR; + this->term.c_cflag = CS8 | CREAD | HUPCL; + this->term.c_lflag = ECHO | ICANON; + this->term.c_cc[VEOF] = 0x04; /* ^D */ + this->term.c_cc[VEOL] = 0x00; /* NUL */ + this->term.c_cc[VERASE] = 0x7f; /* DEL */ + this->term.c_cc[VINTR] = 0x03; /* ^C */ + this->term.c_cc[VKILL] = 0x15; /* ^U */ + this->term.c_cc[VMIN] = 1; /* Minimum number of characters for non-canonical read */ + this->term.c_cc[VQUIT] = 0x1c; /* ^\ */ + this->term.c_cc[VSTART] = 0x11; /* ^Q */ + this->term.c_cc[VSTOP] = 0x13; /* ^S */ + this->term.c_cc[VSUSP] = 0x1a; /* ^Z */ + this->term.c_cc[VTIME] = 0; /* Timeout for non-canonical read */ + this->term.c_cc[VWERASE] = 0x17; /* ^W */ + } + + KConDevice::~KConDevice() + { + } +} diff --git a/storage/devices/tty/ptmx.cpp b/storage/devices/tty/ptmx.cpp new file mode 100644 index 0000000..aec02c7 --- /dev/null +++ b/storage/devices/tty/ptmx.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 +#include + +#include "../../../kernel.h" + +namespace vfs +{ + int PTMXDevice::open(int Flags, mode_t Mode) + { + SmartLock(PTMXLock); + int id = -1; + for (size_t i = 0; i < ptysId.Size; i++) + { + if (unlikely(ptysId.Buffer[i] == false)) + { + id = int(i); + ptysId.Buffer[i] = true; + break; + } + } + + if (id == -1) + return -ENFILE; + + PTYDevice *pty = new PTYDevice(pts, id); + ptysList.push_back(pty); + return pty->OpenMaster(Flags, Mode); + } + + void PTMXDevice::RemovePTY(int fd, Tasking::PCB *pcb) + { + SmartLock(PTMXLock); + if (!pcb) + pcb = thisProcess; + assert(pcb != nullptr); + + FileDescriptorTable *fdt = pcb->FileDescriptors; + RefNode *node = fdt->GetRefNode(fd); + + assert(node->SpecialData != nullptr); + PTYDevice *pty = (PTYDevice *)node->SpecialData; + int id = pty->ptyId; + + forItr(itr, ptysList) + { + if (*itr != pty) + continue; + + ptysList.erase(itr); + delete *itr; + break; + } + ptysId.Buffer[id] = false; + } + + PTMXDevice::PTMXDevice() : Node(DevFS, "ptmx", CHARDEVICE) + { + this->Mode = 0644; + this->UserIdentifier = 0; + this->GroupIdentifier = 0; + pts = new Node(DevFS, "pts", DIRECTORY); + + ptysId.Buffer = new uint8_t[0x1000]; + ptysId.Size = 0x1000; + } + + PTMXDevice::~PTMXDevice() + { + SmartLock(PTMXLock); + delete pts; + delete[] ptysId.Buffer; + } +} diff --git a/storage/devices/tty/pty.cpp b/storage/devices/tty/pty.cpp new file mode 100644 index 0000000..4ca0d85 --- /dev/null +++ b/storage/devices/tty/pty.cpp @@ -0,0 +1,213 @@ +/* + 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" + +namespace vfs +{ + int PTYDevice::open(int Flags, mode_t Mode) + { + stub; + return -ENOSYS; + } + + int PTYDevice::close() + { + stub; + return -ENOSYS; + } + + size_t PTYDevice::read(uint8_t *Buffer, + size_t Size, + off_t Offset) + { + if (this->isMaster) + { + if (MasterDev != nullptr) + return MasterDev->read(Buffer, Size, Offset); + else + fixme("MasterDev is nullptr"); + } + + if (this->SlaveDev == nullptr) + { + fixme("SlaveDev is nullptr"); + return 0; + } + + return SlaveDev->read(Buffer, Size, Offset); + } + + size_t PTYDevice::write(uint8_t *Buffer, + size_t Size, + off_t Offset) + { + if (this->isMaster) + { + if (MasterDev != nullptr) + return MasterDev->write(Buffer, Size, Offset); + else + fixme("MasterDev is nullptr"); + } + + if (this->SlaveDev == nullptr) + { + fixme("SlaveDev is nullptr"); + return 0; + } + + return SlaveDev->write(Buffer, Size, Offset); + } + + int PTYDevice::ioctl(unsigned long Request, + void *Argp) + { + static_assert(sizeof(struct termios) < PAGE_SIZE); + void *pArgp = thisProcess->PageTable->Get(Argp); + + switch (Request) + { + case TCGETS: + { + struct termios *t = (struct termios *)pArgp; + memcpy(t, &this->term, sizeof(struct termios)); + break; + } + case TCSETS: + { + struct termios *t = (struct termios *)pArgp; + memcpy(&this->term, t, sizeof(struct termios)); + break; + } + case TCSETSW: + case TCSETSF: + case TCGETA: + case TCSETA: + case TCSETAW: + case TCSETAF: + case TCSBRK: + case TCXONC: + case TCFLSH: + case TIOCEXCL: + case TIOCNXCL: + case TIOCSCTTY: + case TIOCGPGRP: + case TIOCSPGRP: + case TIOCOUTQ: + case TIOCSTI: + { + fixme("ioctl %#lx not implemented", Request); + return -ENOSYS; + } + case TIOCGWINSZ: + { + struct winsize *ws = (struct winsize *)pArgp; + memcpy(ws, &this->termSize, sizeof(struct winsize)); + break; + } + case TIOCSWINSZ: + { + struct winsize *ws = (struct winsize *)pArgp; + memcpy(&this->termSize, ws, sizeof(struct winsize)); + break; + } + case TIOCMGET: + case TIOCMBIS: + case TIOCMBIC: + case TIOCMSET: + { + fixme("ioctl %#lx not implemented", Request); + return -ENOSYS; + } + case TIOCGPTN: + case 0xffffffff80045430: /* FIXME: ???? */ + { + int *n = (int *)pArgp; + *n = this->id; + break; + } + case TIOCSPTLCK: + { + int *n = (int *)pArgp; + *n = 0; + break; + } + default: + { + debug("Unknown ioctl %#lx", Request); + return -EINVAL; + } + } + + return 0; + } + + int PTYDevice::OpenMaster(int Flags, mode_t Mode) + { + debug("Opening master PTY device %s", this->FullPath); + FileDescriptorTable *fdt = thisProcess->FileDescriptors; + int rfd = fdt->_open(this->FullPath, Flags, Mode); + debug("Opened master PTY device %s with fd %d", + this->FullPath, rfd); + return rfd; + } + + PTYDevice::PTYDevice(Node *pts, int id) : Node(pts, + std::to_string(id), + CHARDEVICE) + { + /* + - ICRNL - Map Carriage Return to New Line + - IXON - Enable XON/XOFF flow control + + - OPOST - Enable output processing + - ONLCR - Map New Line to Carriage Return - New Line + + - CS8 - 8-bit characters + - CREAD - Enable receiver + - HUPCL - Hang up on last close + + - ECHO - Echo input characters + - ICANON - Enable canonical input (enable line editing) + */ + this->term.c_iflag = /*ICRNL |*/ IXON; + this->term.c_oflag = OPOST | ONLCR; + this->term.c_cflag = CS8 | CREAD | HUPCL; + this->term.c_lflag = ECHO | ICANON; + this->term.c_cc[VEOF] = 0x04; /* ^D */ + this->term.c_cc[VEOL] = 0x00; /* NUL */ + this->term.c_cc[VERASE] = 0x7f; /* DEL */ + this->term.c_cc[VINTR] = 0x03; /* ^C */ + this->term.c_cc[VKILL] = 0x15; /* ^U */ + this->term.c_cc[VMIN] = 1; /* Minimum number of characters for non-canonical read */ + this->term.c_cc[VQUIT] = 0x1c; /* ^\ */ + this->term.c_cc[VSTART] = 0x11; /* ^Q */ + this->term.c_cc[VSTOP] = 0x13; /* ^S */ + this->term.c_cc[VSUSP] = 0x1a; /* ^Z */ + this->term.c_cc[VTIME] = 0; /* Timeout for non-canonical read */ + this->term.c_cc[VWERASE] = 0x17; /* ^W */ + + debug("Created PTY device %s", FullPath); + } + + PTYDevice::~PTYDevice() {} +} diff --git a/storage/fs/ptmx.cpp b/storage/devices/tty/ptym.cpp similarity index 66% rename from storage/fs/ptmx.cpp rename to storage/devices/tty/ptym.cpp index 8f7fc4b..45f7a25 100644 --- a/storage/fs/ptmx.cpp +++ b/storage/devices/tty/ptym.cpp @@ -17,33 +17,34 @@ #include #include +#include #include -#include "../../kernel.h" +#include "../../../kernel.h" namespace vfs { - size_t PTMXDevice::read(uint8_t *Buffer, size_t Size, off_t Offset) + size_t MasterPTY::read(uint8_t *Buffer, + size_t Size, + off_t Offset) { - if (Size <= 0) - return 0; - - memset(Buffer, 0, Size); - return Size; + fixme("%.*s", Size, Buffer); + return -ENOSYS; } - size_t PTMXDevice::write(uint8_t *Buffer, size_t Size, off_t Offset) + size_t MasterPTY::write(uint8_t *Buffer, + size_t Size, + off_t Offset) { - return Size; + fixme("%.*s", Size, Buffer); + return -ENOSYS; } - PTMXDevice::PTMXDevice() : Node(DevFS, "null", CHARDEVICE) + MasterPTY::MasterPTY() { - pts = new Node(DevFS, "pts", DIRECTORY); } - PTMXDevice::~PTMXDevice() + MasterPTY::~MasterPTY() { - delete pts; } } diff --git a/core/module/module_binding/bind_input.cpp b/storage/devices/tty/ptys.cpp similarity index 61% rename from core/module/module_binding/bind_input.cpp rename to storage/devices/tty/ptys.cpp index f5bac93..1a7ed4b 100644 --- a/core/module/module_binding/bind_input.cpp +++ b/storage/devices/tty/ptys.cpp @@ -15,28 +15,36 @@ along with Fennix Kernel. If not, see . */ -#include "../api.hpp" - -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include #include "../../../kernel.h" -#include "../../../mapi.hpp" -#include "../../../Fex.hpp" -namespace Module +namespace vfs { - ModuleCode Module::ModuleLoadBindInput(uintptr_t ModuleAddress, size_t Size, bool IsBuiltIn) + size_t SlavePTY::read(uint8_t *Buffer, + size_t Size, + off_t Offset) + { + fixme("%.*s", Size, Buffer); + return -ENOSYS; + } + + size_t SlavePTY::write(uint8_t *Buffer, + size_t Size, + off_t Offset) + { + fixme("%.*s", Size, Buffer); + return -ENOSYS; + } + + SlavePTY::SlavePTY() + { + } + + SlavePTY::~SlavePTY() { - stub; - UNUSED(ModuleAddress); - UNUSED(Size); - UNUSED(IsBuiltIn); - return ModuleCode::NOT_IMPLEMENTED; } } diff --git a/storage/fs/tty.cpp b/storage/devices/tty/tty.cpp similarity index 98% rename from storage/fs/tty.cpp rename to storage/devices/tty/tty.cpp index c1eac3c..57236b9 100644 --- a/storage/fs/tty.cpp +++ b/storage/devices/tty/tty.cpp @@ -19,7 +19,7 @@ #include #include -#include "../../kernel.h" +#include "../../../kernel.h" namespace vfs { @@ -57,5 +57,6 @@ namespace vfs } TTYDevice::TTYDevice() : Node(DevFS, "tty", CHARDEVICE) {} + TTYDevice::~TTYDevice() {} } diff --git a/storage/fs/zero.cpp b/storage/devices/zero.cpp similarity index 100% rename from storage/fs/zero.cpp rename to storage/devices/zero.cpp diff --git a/storage/file_descriptor.cpp b/storage/file_descriptor.cpp index d6279ec..ff1db64 100644 --- a/storage/file_descriptor.cpp +++ b/storage/file_descriptor.cpp @@ -68,10 +68,10 @@ namespace vfs // // .Write = fd_Write, // }; - FileDescriptorTable::Fildes + FileDescriptorTable::Fildes & FileDescriptorTable::GetFileDescriptor(int FileDescriptor) { - foreach (auto fd in FileDescriptors) + foreach (auto &fd in FileDescriptors) { if (fd.Descriptor == FileDescriptor) { @@ -79,13 +79,13 @@ namespace vfs return fd; } } - return {}; + return nullfd; } - FileDescriptorTable::DupFildes + FileDescriptorTable::Fildes & FileDescriptorTable::GetDupFildes(int FileDescriptor) { - foreach (auto fd in FildesDuplicates) + foreach (auto &fd in FildesDuplicates) { if (fd.Descriptor == FileDescriptor) { @@ -93,7 +93,48 @@ namespace vfs return fd; } } - return {}; + return nullfd; + } + + FileDescriptorTable::Fildes & + FileDescriptorTable::GetDescriptor(int FileDescriptor) + { + Fildes &fd = this->GetFileDescriptor(FileDescriptor); + Fildes &dfd = this->GetDupFildes(FileDescriptor); + + if (fd.Descriptor == -1 && + dfd.Descriptor == -1) + return nullfd; + + if (fd.Descriptor != -1) + return fd; + else + return dfd; + } + + int FileDescriptorTable::GetFlags(int FileDescriptor) + { + Fildes &fd = this->GetDescriptor(FileDescriptor); + if (fd == nullfd) + { + debug("invalid fd %d", FileDescriptor); + return -EBADF; + } + + return fd.Flags; + } + + int FileDescriptorTable::SetFlags(int FileDescriptor, int Flags) + { + Fildes &fd = this->GetDescriptor(FileDescriptor); + if (fd == nullfd) + { + debug("invalid fd %d", FileDescriptor); + return -EBADF; + } + + fd.Flags = Flags; + return 0; } int FileDescriptorTable::ProbeMode(mode_t Mode, int Flags) @@ -143,12 +184,12 @@ namespace vfs if (Flags & O_CREAT) { int ret; - Node *n = new Node(pcb->CurrentWorkingDirectory, - AbsolutePath, - NodeType::FILE, - cwk_path_is_absolute(AbsolutePath), - fs, - &ret); + new Node(pcb->CurrentWorkingDirectory, + AbsolutePath, + NodeType::FILE, + cwk_path_is_absolute(AbsolutePath), + fs, + &ret); if (ret == -EEXIST) { @@ -159,7 +200,7 @@ namespace vfs { error("Failed to create file %s: %d", AbsolutePath, ret); - assert(false); + assert(ret < 0); } } @@ -174,6 +215,7 @@ namespace vfs AbsolutePath); return -EIO; } + delete File; } if (Flags & O_TRUNC) @@ -213,15 +255,14 @@ namespace vfs FileDescriptors.push_back(fd); char FileName[64]; - sprintf(FileName, "%d", fd.Descriptor); - vfs::Node *n = fs->Create(FileName, vfs::NodeType::FILE, this->fdDir); - if (n) - { - /* FIXME: Implement proper file descriptors */ - n->Size = File->FileSize; - } + itoa(fd.Descriptor, FileName, 10); + assert(fs->CreateLink(FileName, AbsolutePath, this->fdDir) != nullptr); - return fd.Descriptor; + int rfd = File->node->open(Flags, Mode); + if (rfd <= 0) + return fd.Descriptor; + else + return rfd; } int FileDescriptorTable::RemoveFileDescriptor(int FileDescriptor) @@ -233,7 +274,7 @@ namespace vfs FileDescriptors.erase(itr); char FileName[64]; - sprintf(FileName, "%d", FileDescriptor); + itoa(FileDescriptor, FileName, 10); fs->Delete(FileName, false, this->fdDir); return 0; } @@ -246,7 +287,7 @@ namespace vfs FildesDuplicates.erase(itr); char FileName[64]; - sprintf(FileName, "%d", FileDescriptor); + itoa(FileDescriptor, FileName, 10); fs->Delete(FileName, false, this->fdDir); return 0; } @@ -292,25 +333,58 @@ namespace vfs const char *FileDescriptorTable::GetAbsolutePath(int FileDescriptor) { - Fildes fd = this->GetFileDescriptor(FileDescriptor); - DupFildes dfd = this->GetDupFildes(FileDescriptor); - - if (fd.Descriptor == -1 && - dfd.Descriptor == -1) + Fildes &fd = this->GetDescriptor(FileDescriptor); + if (fd == nullfd) return ""; - RefNode *hnd = nullptr; - if (fd.Descriptor != -1) - hnd = fd.Handle; - else - hnd = dfd.Handle; - - Node *node = hnd->node; + Node *node = fd.Handle->node; const char *path = new char[strlen(node->FullPath) + 1]; strcpy((char *)path, node->FullPath); return path; } + RefNode *FileDescriptorTable::GetRefNode(int FileDescriptor) + { + Fildes &fd = this->GetDescriptor(FileDescriptor); + if (fd == nullfd) + return nullptr; + + return fd.Handle; + } + + void FileDescriptorTable::Fork(FileDescriptorTable *Parent) + { + foreach (auto &fd in Parent->FileDescriptors) + { + debug("Forking fd: %d", fd.Descriptor); + RefNode *node = fs->Open(fd.Handle->node->FullPath, + thisProcess->CurrentWorkingDirectory); + assert(node != nullptr); + + Fildes new_fd; + new_fd.Descriptor = fd.Descriptor; + new_fd.Flags = fd.Flags; + new_fd.Mode = fd.Mode; + new_fd.Handle = node; + this->FileDescriptors.push_back(new_fd); + } + + foreach (auto &fd in Parent->FildesDuplicates) + { + debug("Forking duplicated fd: %d", fd.Descriptor); + RefNode *node = fs->Open(fd.Handle->node->FullPath, + thisProcess->CurrentWorkingDirectory); + assert(node != nullptr); + + Fildes new_fd; + new_fd.Descriptor = fd.Descriptor; + new_fd.Flags = fd.Flags; + new_fd.Mode = fd.Mode; + new_fd.Handle = node; + this->FildesDuplicates.push_back(new_fd); + } + } + int FileDescriptorTable::_open(const char *pathname, int flags, mode_t mode) { @@ -325,84 +399,50 @@ namespace vfs return _open(pathname, O_WRONLY | O_CREAT | O_TRUNC, mode); } - ssize_t FileDescriptorTable::_read(int fd, void *buf, size_t count) + ssize_t FileDescriptorTable::_read(int _fd, void *buf, size_t count) { - Fildes fdesc = this->GetFileDescriptor(fd); - DupFildes dfdesc = this->GetDupFildes(fd); - if (fdesc.Descriptor < 0 && - dfdesc.Descriptor < 0) + Fildes &fd = this->GetDescriptor(_fd); + if (fd == nullfd) { + debug("invalid fd %d", _fd); return -EBADF; } - RefNode *hnd = nullptr; - if (fdesc.Descriptor != -1) - hnd = fdesc.Handle; - else - hnd = dfdesc.Handle; - - return hnd->read((uint8_t *)buf, count); + return fd.Handle->read((uint8_t *)buf, count); } - ssize_t FileDescriptorTable::_write(int fd, const void *buf, + ssize_t FileDescriptorTable::_write(int _fd, const void *buf, size_t count) { - Fildes fdesc = this->GetFileDescriptor(fd); - DupFildes dfdesc = this->GetDupFildes(fd); - if (fdesc.Descriptor < 0 && - dfdesc.Descriptor < 0) + Fildes &fd = this->GetDescriptor(_fd); + if (fd == nullfd) { + debug("invalid fd %d", _fd); return -EBADF; } - RefNode *hnd = nullptr; - if (fdesc.Descriptor != -1) - hnd = fdesc.Handle; - else - hnd = dfdesc.Handle; - - return hnd->write((uint8_t *)buf, count); + return fd.Handle->write((uint8_t *)buf, count); } - int FileDescriptorTable::_close(int fd) + int FileDescriptorTable::_close(int _fd) { - Fildes fdesc = this->GetFileDescriptor(fd); - DupFildes dfdesc = this->GetDupFildes(fd); - - if (fdesc.Descriptor < 0 && - dfdesc.Descriptor < 0) + Fildes &fd = this->GetDescriptor(_fd); + if (fd == nullfd) { + debug("invalid fd %d", _fd); return -EBADF; } - if (RemoveFileDescriptor(fd) < 0) + if (RemoveFileDescriptor(_fd) < 0) + { + debug("invalid fd %d", _fd); return -EBADF; - - /* If the file descriptor is a duplicate, - we don't need to close the handle, - because it's a duplicate of another - file descriptor. */ + } bool Found = false; - RefNode *hnd = nullptr; - - if (fdesc.Descriptor != -1) - hnd = fdesc.Handle; - else - hnd = dfdesc.Handle; - foreach (auto dfd in FileDescriptors) { - if (dfd.Handle == hnd) - { - Found = true; - break; - } - } - - foreach (auto dfd in FildesDuplicates) - { - if (dfd.Handle == hnd) + if (dfd.Handle == fd.Handle) { Found = true; break; @@ -410,28 +450,34 @@ namespace vfs } if (!Found) - delete hnd; + foreach (auto dfd in FildesDuplicates) + { + if (dfd.Handle == fd.Handle) + { + Found = true; + break; + } + } + + /* If the file descriptor is a duplicate, + we don't need to close the handle, + because it's a duplicate of another + file descriptor. */ + if (!Found) + delete fd.Handle; return 0; } - off_t FileDescriptorTable::_lseek(int fd, off_t offset, int whence) + off_t FileDescriptorTable::_lseek(int _fd, off_t offset, int whence) { - Fildes fdesc = this->GetFileDescriptor(fd); - DupFildes dfdesc = this->GetDupFildes(fd); - - if (fdesc.Descriptor < 0 && - dfdesc.Descriptor < 0) + Fildes &fd = this->GetDescriptor(_fd); + if (fd == nullfd) { + debug("invalid fd %d", _fd); return -EBADF; } - RefNode *hnd = nullptr; - if (fdesc.Descriptor != -1) - hnd = fdesc.Handle; - else - hnd = dfdesc.Handle; - - return hnd->seek(offset, whence); + return fd.Handle->seek(offset, whence); } int FileDescriptorTable::_stat(const char *pathname, @@ -465,24 +511,16 @@ namespace vfs return 0; } - int FileDescriptorTable::_fstat(int fd, struct stat *statbuf) + int FileDescriptorTable::_fstat(int _fd, struct stat *statbuf) { - Fildes fdesc = this->GetFileDescriptor(fd); - DupFildes dfdesc = this->GetDupFildes(fd); - - if (fdesc.Descriptor < 0 && - dfdesc.Descriptor < 0) + Fildes &fd = this->GetDescriptor(_fd); + if (fd == nullfd) { + debug("invalid fd %d", _fd); return -EBADF; } - RefNode *hnd = nullptr; - if (fdesc.Descriptor != -1) - hnd = fdesc.Handle; - else - hnd = dfdesc.Handle; - - Node *node = hnd->node; + Node *node = fd.Handle->node; statbuf->st_dev = 0; /* FIXME: stub */ statbuf->st_ino = node->IndexNode; statbuf->st_mode = node->Type | node->Mode; @@ -530,12 +568,10 @@ namespace vfs int FileDescriptorTable::_dup(int oldfd) { - Fildes fdesc = this->GetFileDescriptor(oldfd); - DupFildes dfdesc = this->GetDupFildes(oldfd); - - if (fdesc.Descriptor < 0 && - dfdesc.Descriptor < 0) + Fildes &fd = this->GetDescriptor(oldfd); + if (fd == nullfd) { + debug("invalid fd %d", oldfd); return -EBADF; } @@ -543,17 +579,9 @@ namespace vfs if (newfd < 0) return -EMFILE; - DupFildes new_dfd{}; - if (fdesc.Descriptor != -1) - { - new_dfd.Handle = fdesc.Handle; - new_dfd.Mode = fdesc.Mode; - } - else - { - new_dfd.Handle = dfdesc.Handle; - new_dfd.Mode = dfdesc.Mode; - } + Fildes new_dfd{}; + new_dfd.Handle = fd.Handle; + new_dfd.Mode = fd.Mode; new_dfd.Descriptor = newfd; this->FildesDuplicates.push_back(new_dfd); @@ -564,17 +592,18 @@ namespace vfs int FileDescriptorTable::_dup2(int oldfd, int newfd) { - Fildes fdesc = this->GetFileDescriptor(oldfd); - DupFildes dfdesc = this->GetDupFildes(oldfd); - - if (fdesc.Descriptor < 0 && - dfdesc.Descriptor < 0) + Fildes &fd = this->GetDescriptor(oldfd); + if (fd == nullfd) { + debug("invalid fd %d", oldfd); return -EBADF; } if (newfd < 0) + { + debug("invalid fd %d", newfd); return -EBADF; + } if (newfd == oldfd) return newfd; @@ -583,17 +612,9 @@ namespace vfs we ignore it. */ this->_close(newfd); - DupFildes new_dfd{}; - if (fdesc.Descriptor != -1) - { - new_dfd.Handle = fdesc.Handle; - new_dfd.Mode = fdesc.Mode; - } - else - { - new_dfd.Handle = dfdesc.Handle; - new_dfd.Mode = dfdesc.Mode; - } + Fildes new_dfd{}; + new_dfd.Handle = fd.Handle; + new_dfd.Mode = fd.Mode; new_dfd.Descriptor = newfd; this->FildesDuplicates.push_back(new_dfd); @@ -602,39 +623,31 @@ namespace vfs return newfd; } - int FileDescriptorTable::_ioctl(int fd, unsigned long request, void *argp) + int FileDescriptorTable::_ioctl(int _fd, unsigned long request, void *argp) { - Fildes fdesc = this->GetFileDescriptor(fd); - DupFildes dfdesc = this->GetDupFildes(fd); - if (fdesc.Descriptor < 0 && - dfdesc.Descriptor < 0) + Fildes &fd = this->GetDescriptor(_fd); + if (fd == nullfd) { + debug("invalid fd %d", _fd); return -EBADF; } - RefNode *hnd = nullptr; - if (fdesc.Descriptor != -1) - hnd = fdesc.Handle; - else - hnd = dfdesc.Handle; - - return hnd->ioctl(request, argp); + return fd.Handle->ioctl(request, argp); } FileDescriptorTable::FileDescriptorTable(void *Owner) { debug("+ %#lx", this); this->fdDir = fs->Create("fd", vfs::NodeType::DIRECTORY, - ((Tasking::PCB *)Owner)->ProcessDirectory); + ((Tasking::PCB *)Owner)); } FileDescriptorTable::~FileDescriptorTable() { debug("- %#lx", this); - foreach (auto fd in FileDescriptors) + foreach (auto &fd in FileDescriptors) { - debug("Removing fd: %d(%#lx)", - fd.Descriptor, fd); + debug("Removing fd: %d", fd.Descriptor); this->RemoveFileDescriptor(fd.Descriptor); delete fd.Handle; } diff --git a/storage/filesystem.cpp b/storage/filesystem.cpp index fc67980..a4371d4 100644 --- a/storage/filesystem.cpp +++ b/storage/filesystem.cpp @@ -282,24 +282,21 @@ namespace vfs } } - if (GetChild(SegmentName, CurrentParent) == nullptr) - { - Node *NewNode = new Node(CurrentParent, - SegmentName, - NodeType::DIRECTORY); - - CurrentParent = NewNode; - CurrentParent->Type = Type; - CurrentParent->FullPath = CleanPath; - } + if (GetChild(SegmentName, CurrentParent) != nullptr) + CurrentParent = GetChild(SegmentName, CurrentParent); else { - CurrentParent = GetChild(SegmentName, CurrentParent); + CurrentParent = new Node(CurrentParent, + SegmentName, + NodeType::DIRECTORY); } delete[] SegmentName; } while (cwk_path_get_next_segment(&segment)); + CurrentParent->Type = Type; + // CurrentParent->FullPath = CleanPath; + vfsdbg("Virtual::Create()->\"%s\"", CurrentParent->Name); #ifdef DEBUG VirtualLock.Unlock(); @@ -315,6 +312,25 @@ namespace vfs return nullptr; } + Node *Virtual::CreateLink(const char *Path, const char *Target, Node *Parent) + { + Node *node = this->Create(Path, NodeType::SYMLINK, Parent); + if (node) + { + node->Symlink = new char[strlen(Target) + 1]; + strncpy((char *)node->Symlink, + Target, + strlen(Target)); + + node->SymlinkTarget = node->vFS->GetNodeFromPath(node->Symlink); + return node; + } + + error("Failed to create link \"%s\" -> \"%s\"", + Path, Target); + return nullptr; + } + int Virtual::Delete(const char *Path, bool Recursive, Node *Parent) { vfsdbg("Virtual::Delete( Path: \"%s\" Parent: \"%s\" )", @@ -337,8 +353,14 @@ namespace vfs } Node *NodeToDelete = GetNodeFromPath(CleanPath, Parent); + + if (!NodeToDelete->References.empty()) + fixme("Path \"%s\" is referenced by %d objects.", + CleanPath, NodeToDelete->References.size()); + delete[] CleanPath; - return NodeToDelete->Delete(Recursive); + delete NodeToDelete; + return 0; } int Virtual::Delete(Node *Path, bool Recursive, Node *Parent) @@ -385,6 +407,14 @@ namespace vfs return nullptr; } + Node *Virtual::CreateIfNotExists(const char *Path, NodeType Type, Node *Parent) + { + Node *node = GetNodeFromPath(Path, Parent); + if (node) + return node; + return Create(Path, Type, Parent); + } + Virtual::Virtual() { SmartLock(VirtualLock); diff --git a/storage/kernel_io.cpp b/storage/kernel_io.cpp index c9bf0ce..d1fa96a 100644 --- a/storage/kernel_io.cpp +++ b/storage/kernel_io.cpp @@ -59,8 +59,8 @@ ssize_t fread(int fd, void *buf, size_t count) PCB *pcb = thisProcess; FileDescriptorTable *fdt = pcb->FileDescriptors; - ssize_t r = fdt->_read(fd, buf, count); - return r; + ssize_t ret = fdt->_read(fd, buf, count); + return ret; } ssize_t fwrite(int fd, const void *buf, size_t count) @@ -70,8 +70,8 @@ ssize_t fwrite(int fd, const void *buf, size_t count) PCB *pcb = thisProcess; FileDescriptorTable *fdt = pcb->FileDescriptors; - ssize_t r = fdt->_write(fd, buf, count); - return r; + ssize_t ret = fdt->_write(fd, buf, count); + return ret; } int fclose(int fd) @@ -81,8 +81,8 @@ int fclose(int fd) PCB *pcb = thisProcess; FileDescriptorTable *fdt = pcb->FileDescriptors; - int r = fdt->_close(fd); - return r; + int ret = fdt->_close(fd); + return ret; } off_t lseek(int fd, off_t offset, int whence) @@ -92,8 +92,8 @@ off_t lseek(int fd, off_t offset, int whence) PCB *pcb = thisProcess; FileDescriptorTable *fdt = pcb->FileDescriptors; - off_t r = fdt->_lseek(fd, offset, whence); - return r; + off_t ret = fdt->_lseek(fd, offset, whence); + return ret; } int stat(const char *pathname, struct stat *statbuf) @@ -103,8 +103,8 @@ int stat(const char *pathname, struct stat *statbuf) PCB *pcb = thisProcess; FileDescriptorTable *fdt = pcb->FileDescriptors; - int r = fdt->_stat(pathname, statbuf); - return r; + int ret = fdt->_stat(pathname, statbuf); + return ret; } int fstat(int fd, struct stat *statbuf) @@ -114,8 +114,8 @@ int fstat(int fd, struct stat *statbuf) PCB *pcb = thisProcess; FileDescriptorTable *fdt = pcb->FileDescriptors; - int r = fdt->_fstat(fd, statbuf); - return r; + int ret = fdt->_fstat(fd, statbuf); + return ret; } int lstat(const char *pathname, struct stat *statbuf) @@ -125,6 +125,6 @@ int lstat(const char *pathname, struct stat *statbuf) PCB *pcb = thisProcess; FileDescriptorTable *fdt = pcb->FileDescriptors; - int r = fdt->_lstat(pathname, statbuf); - return r; + int ret = fdt->_lstat(pathname, statbuf); + return ret; } diff --git a/storage/node.cpp b/storage/node.cpp index 5e5e888..d8acd42 100644 --- a/storage/node.cpp +++ b/storage/node.cpp @@ -22,31 +22,51 @@ namespace vfs { int Node::open(int Flags, mode_t Mode) { - debug("Operation not handled"); - return -ENXIO; + if (likely(open_ptr)) + return open_ptr(Flags, Mode); + + debug("Operation not handled for %s(%#lx)", + this->FullPath, this); + return -ENODEV; } int Node::close() { - debug("Operation not handled"); - return -ENXIO; + if (likely(close_ptr)) + return close_ptr(); + + debug("Operation not handled for %s(%#lx)", + this->FullPath, this); + return -ENODEV; } size_t Node::read(uint8_t *Buffer, size_t Size, off_t Offset) { - debug("Operation not handled"); - return -ENXIO; + if (likely(read_ptr)) + return read_ptr(Buffer, Size, Offset); + + debug("Operation not handled for %s(%#lx)", + this->FullPath, this); + return -ENODEV; } size_t Node::write(uint8_t *Buffer, size_t Size, off_t Offset) { - debug("Operation not handled"); - return -ENXIO; + if (likely(write_ptr)) + return write_ptr(Buffer, Size, Offset); + + debug("Operation not handled for %s(%#lx)", + this->FullPath, this); + return -ENODEV; } int Node::ioctl(unsigned long Request, void *Argp) { - debug("Operation not handled"); + if (likely(ioctl_ptr)) + return ioctl_ptr(Request, Argp); + + debug("Operation not handled for %s(%#lx)", + this->FullPath, this); return -ENODEV; } @@ -55,7 +75,8 @@ namespace vfs SmartLock(NodeLock); RefNode *ref = new RefNode(this); References.push_back(ref); - debug("Created reference %#lx for node %#lx", ref, this); + debug("Created reference %#lx for node %#lx(%s)", + ref, this, this->Name); return ref; } @@ -199,56 +220,24 @@ namespace vfs trace("Node %s(%#lx) has no parent", this->Name, this); } - } - int Node::Delete(bool Recursive) - { - if (this->References.size() != 0) - { - debug("Node %s(%#lx) has %ld references", - this->FullPath, this, - this->References.size()); - return -EBUSY; - } - - if (this->Type == MOUNTPOINT || - this->Type == DIRECTORY) - { - if (this->Children.size() != 0) - { - if (!Recursive) - { - debug("Node %s(%#lx) has %ld children", - this->FullPath, this, - this->Children.size()); - return -ENOTEMPTY; - } - - for (auto Child : this->Children) - { - int ret = Child->Delete(Recursive); - - if (ret < 0) - { - debug("Failed to delete child %s(%#lx)", - Child->FullPath, Child); - return ret; - } - } - } - } - - delete this; - return 0; + debug("Created node %s(%#lx)", this->FullPath, this); } Node::~Node() { - debug("Destroyed node %#lx", this); - assert(this->Children.size() == 0); + debug("Destroyed node %s(%#lx)", this->FullPath, this); + // assert(this->Children.size() == 0); + + foreach (auto Child in this->Children) + delete Child; if (this->Parent) { + debug("Removing node %s(%#lx) from parent %s(%#lx)", + this->FullPath, this, + this->Parent->FullPath, this->Parent); + this->Parent->Children.erase(std::find(this->Parent->Children.begin(), this->Parent->Children.end(), this)); diff --git a/storage/ref_node.cpp b/storage/ref_node.cpp index 7580dd3..c418d35 100644 --- a/storage/ref_node.cpp +++ b/storage/ref_node.cpp @@ -150,6 +150,7 @@ namespace vfs { if (this->SymlinkTo) this->node->SymlinkTarget->RemoveReference(this); + this->node->RemoveReference(this); debug("Destroyed reference node for %s [%#lx]", diff --git a/syscalls/linux.cpp b/syscalls/linux.cpp index 803bd81..9e33ab8 100644 --- a/syscalls/linux.cpp +++ b/syscalls/linux.cpp @@ -15,13 +15,29 @@ along with Fennix Kernel. If not, see . */ +#include +#include +#include +#include #include +#include +#include +#include +#include +#include #include #include +#include + +#include +#define INI_IMPLEMENTATION +#include #include "../kernel.h" -#include "linux_syscalls.hpp" + +using Tasking::PCB; +using Tasking::TCB; struct SyscallData { @@ -29,185 +45,96 @@ struct SyscallData void *Handler; }; -using InterProcessCommunication::IPC; -using InterProcessCommunication::IPCID; -using Tasking::TaskState::Ready; -using Tasking::TaskState::Terminated; - -#define ARCH_SET_GS 0x1001 -#define ARCH_SET_FS 0x1002 -#define ARCH_GET_FS 0x1003 -#define ARCH_GET_GS 0x1004 - -#define ARCH_GET_CPUID 0x1011 -#define ARCH_SET_CPUID 0x1012 - -#define ARCH_GET_XCOMP_SUPP 0x1021 -#define ARCH_GET_XCOMP_PERM 0x1022 -#define ARCH_REQ_XCOMP_PERM 0x1023 -#define ARCH_GET_XCOMP_GUEST_PERM 0x1024 -#define ARCH_REQ_XCOMP_GUEST_PERM 0x1025 - -#define ARCH_XCOMP_TILECFG 17 -#define ARCH_XCOMP_TILEDATA 18 - -#define ARCH_MAP_VDSO_X32 0x2001 -#define ARCH_MAP_VDSO_32 0x2002 -#define ARCH_MAP_VDSO_64 0x2003 - -#define ARCH_GET_UNTAG_MASK 0x4001 -#define ARCH_ENABLE_TAGGED_ADDR 0x4002 -#define ARCH_GET_MAX_TAG_BITS 0x4003 -#define ARCH_FORCE_TAGGED_SVA 0x4004 - -#define PROT_NONE 0 -#define PROT_READ 1 -#define PROT_WRITE 2 -#define PROT_EXEC 4 -#define PROT_GROWSDOWN 0x01000000 -#define PROT_GROWSUP 0x02000000 - -#define MAP_TYPE 0x0f - -#define MAP_FILE 0 -#define MAP_SHARED 0x01 -#define MAP_PRIVATE 0x02 -#define MAP_SHARED_VALIDATE 0x03 -#define MAP_FIXED 0x10 -#define MAP_ANONYMOUS 0x20 -#define MAP_NORESERVE 0x4000 -#define MAP_GROWSDOWN 0x0100 -#define MAP_DENYWRITE 0x0800 -#define MAP_EXECUTABLE 0x1000 -#define MAP_LOCKED 0x2000 -#define MAP_POPULATE 0x8000 -#define MAP_NONBLOCK 0x10000 -#define MAP_STACK 0x20000 -#define MAP_HUGETLB 0x40000 -#define MAP_SYNC 0x80000 -#define MAP_FIXED_NOREPLACE 0x100000 - -#define linux_SIGHUP 1 -#define linux_SIGINT 2 -#define linux_SIGQUIT 3 -#define linux_SIGILL 4 -#define linux_SIGTRAP 5 -#define linux_SIGABRT 6 -#define linux_SIGIOT linux_SIGABRT -#define linux_SIGBUS 7 -#define linux_SIGFPE 8 -#define linux_SIGKILL 9 -#define linux_SIGUSR1 10 -#define linux_SIGSEGV 11 -#define linux_SIGUSR2 12 -#define linux_SIGPIPE 13 -#define linux_SIGALRM 14 -#define linux_SIGTERM 15 -#define linux_SIGSTKFLT 16 -#define linux_SIGCHLD 17 -#define linux_SIGCONT 18 -#define linux_SIGSTOP 19 -#define linux_SIGTSTP 20 -#define linux_SIGTTIN 21 -#define linux_SIGTTOU 22 -#define linux_SIGURG 23 -#define linux_SIGXCPU 24 -#define linux_SIGXFSZ 25 -#define linux_SIGVTALRM 26 -#define linux_SIGPROF 27 -#define linux_SIGWINCH 28 -#define linux_SIGIO 29 -#define linux_SIGPOLL 29 -#define linux_SIGPWR 30 -#define linux_SIGSYS 31 -#define linux_SIGUNUSED linux_SIGSYS - -typedef int pid_t; - -struct iovec +void linux_fork_return(void *tableAddr) { - void *iov_base; - size_t iov_len; -}; - -typedef long __kernel_old_time_t; -typedef long __kernel_suseconds_t; - -struct timeval -{ - __kernel_old_time_t tv_sec; - __kernel_suseconds_t tv_usec; -}; - -struct rusage -{ - struct timeval ru_utime; - struct timeval ru_stime; - long ru_maxrss; - long ru_ixrss; - long ru_idrss; - long ru_isrss; - long ru_minflt; - long ru_majflt; - long ru_nswap; - long ru_inblock; - long ru_oublock; - long ru_msgsnd; - long ru_msgrcv; - long ru_nsignals; - long ru_nvcsw; - long ru_nivcsw; -}; - -/* From native functions */ -#define SysFrm SyscallsFrame -SysFrm *thisFrame; -ssize_t sys_read(SysFrm *, int, void *, size_t); -ssize_t sys_write(SysFrm *, int, const void *, size_t); -int sys_open(SysFrm *, const char *, int, mode_t); -int sys_close(SysFrm *, int); -off_t sys_lseek(SysFrm *, int, off_t, int); -void *sys_mmap(SysFrm *, void *, size_t, int, int, int, off_t); -int sys_mprotect(SysFrm *, void *, size_t, int); -int sys_munmap(SysFrm *, void *, size_t); -int sys_fork(SysFrm *); -int sys_execve(SysFrm *, const char *, char *const[], char *const[]); -__noreturn void sys_exit(SysFrm *, int); +#if defined(a64) + asmv("movq %0, %%cr3" ::"r"(tableAddr)); /* Load process page table */ + asmv("movq $0, %rax\n"); /* Return 0 */ + asmv("movq %r8, %rsp\n"); /* Restore stack pointer */ + asmv("movq %r8, %rbp\n"); /* Restore base pointer */ + asmv("swapgs\n"); /* Swap GS back to the user GS */ + asmv("sti\n"); /* Enable interrupts */ + asmv("sysretq\n"); /* Return to rcx address in user mode */ +#elif defined(a32) +#warning "linux_fork_return not implemented for i386" +#endif + __builtin_unreachable(); +} /* https://man7.org/linux/man-pages/man2/read.2.html */ -static ssize_t linux_read(int fd, void *buf, size_t count) +static ssize_t linux_read(SysFrm *, int fd, void *buf, size_t count) { - return sys_read(thisFrame, fd, buf, count); + PCB *pcb = thisProcess; + void *pBuf = pcb->PageTable->Get(buf); + + function("%d, %p, %d", fd, buf, count); + vfs::FileDescriptorTable *fdt = pcb->FileDescriptors; + ssize_t ret = fdt->_read(fd, pBuf, count); + if (ret >= 0) + fdt->_lseek(fd, ret, SEEK_CUR); + return ret; } /* https://man7.org/linux/man-pages/man2/write.2.html */ -static ssize_t linux_write(int fd, const void *buf, size_t count) +static ssize_t linux_write(SysFrm *, int fd, const void *buf, size_t count) { - return sys_write(thisFrame, fd, buf, count); + PCB *pcb = thisProcess; + const void *pBuf = pcb->PageTable->Get((void *)buf); + + function("%d, %p, %d", fd, buf, count); + vfs::FileDescriptorTable *fdt = pcb->FileDescriptors; + ssize_t ret = fdt->_write(fd, pBuf, count); + if (ret) + fdt->_lseek(fd, ret, SEEK_CUR); + return ret; } /* https://man7.org/linux/man-pages/man2/open.2.html */ -static int linux_open(const char *pathname, int flags, mode_t mode) +static int linux_open(SysFrm *sf, const char *pathname, int flags, mode_t mode) { - return sys_open(thisFrame, pathname, flags, mode); + PCB *pcb = thisProcess; + const char *pPathname = pcb->PageTable->Get(pathname); + + function("%s, %d, %d", pPathname, flags, mode); + + if (flags & 0200000 /* O_DIRECTORY */) + { + vfs::Node *node = fs->GetNodeFromPath(pPathname); + if (!node) + { + debug("Couldn't find %s", pPathname); + return -ENOENT; + } + + if (node->Type != vfs::NodeType::DIRECTORY) + { + debug("%s is not a directory", pPathname); + return -ENOTDIR; + } + } + + vfs::FileDescriptorTable *fdt = pcb->FileDescriptors; + return fdt->_open(pPathname, flags, mode); } /* https://man7.org/linux/man-pages/man2/close.2.html */ -static int linux_close(int fd) +static int linux_close(SysFrm *, int fd) { - return sys_close(thisFrame, fd); + PCB *pcb = thisProcess; + vfs::FileDescriptorTable *fdt = pcb->FileDescriptors; + return fdt->_close(fd); } /* https://man7.org/linux/man-pages/man2/stat.2.html */ -static int linux_stat(const char *pathname, struct stat *statbuf) +static int linux_stat(SysFrm *, const char *pathname, struct stat *statbuf) { - Tasking::PCB *pcb = thisProcess; + PCB *pcb = thisProcess; vfs::FileDescriptorTable *fdt = pcb->FileDescriptors; - Memory::Virtual vmm = Memory::Virtual(pcb->PageTable); + Memory::Virtual vmm(pcb->PageTable); if (!vmm.Check((void *)pathname, Memory::US)) { - warn("Invalid address %#lx", pathname); + debug("Invalid address %#lx", pathname); return -EFAULT; } auto pPathname = pcb->PageTable->Get(pathname); @@ -216,16 +143,16 @@ static int linux_stat(const char *pathname, struct stat *statbuf) } /* https://man7.org/linux/man-pages/man2/fstat.2.html */ -static int linux_fstat(int fd, struct stat *statbuf) +static int linux_fstat(SysFrm *, int fd, struct stat *statbuf) { #undef fstat - Tasking::PCB *pcb = thisProcess; + PCB *pcb = thisProcess; vfs::FileDescriptorTable *fdt = pcb->FileDescriptors; - Memory::Virtual vmm = Memory::Virtual(pcb->PageTable); + Memory::Virtual vmm(pcb->PageTable); if (!vmm.Check((void *)statbuf, Memory::US)) { - warn("Invalid address %#lx", statbuf); + debug("Invalid address %#lx", statbuf); return -EFAULT; } auto pStatbuf = pcb->PageTable->Get(statbuf); @@ -234,22 +161,22 @@ static int linux_fstat(int fd, struct stat *statbuf) } /* https://man7.org/linux/man-pages/man2/lstat.2.html */ -static int linux_lstat(const char *pathname, struct stat *statbuf) +static int linux_lstat(SysFrm *, const char *pathname, struct stat *statbuf) { #undef lstat - Tasking::PCB *pcb = thisProcess; + PCB *pcb = thisProcess; vfs::FileDescriptorTable *fdt = pcb->FileDescriptors; - Memory::Virtual vmm = Memory::Virtual(pcb->PageTable); + Memory::Virtual vmm(pcb->PageTable); if (!vmm.Check((void *)pathname, Memory::US)) { - warn("Invalid address %#lx", pathname); + debug("Invalid address %#lx", pathname); return -EFAULT; } if (!vmm.Check((void *)statbuf, Memory::US)) { - warn("Invalid address %#lx", statbuf); + debug("Invalid address %#lx", statbuf); return -EFAULT; } @@ -261,21 +188,19 @@ static int linux_lstat(const char *pathname, struct stat *statbuf) #include "../syscalls.h" /* https://man7.org/linux/man-pages/man2/lseek.2.html */ -static off_t linux_lseek(int fd, off_t offset, int whence) +static off_t linux_lseek(SysFrm *, int fd, off_t offset, int whence) { - int new_whence = 0; - if (whence == SEEK_SET) - new_whence = sc_SEEK_SET; - else if (whence == SEEK_CUR) - new_whence = sc_SEEK_CUR; - else if (whence == SEEK_END) - new_whence = sc_SEEK_END; + static_assert(SEEK_SET == sc_SEEK_SET); + static_assert(SEEK_CUR == sc_SEEK_CUR); + static_assert(SEEK_END == sc_SEEK_END); - return sys_lseek(thisFrame, fd, offset, new_whence); + PCB *pcb = thisProcess; + vfs::FileDescriptorTable *fdt = pcb->FileDescriptors; + return fdt->_lseek(fd, offset, whence); } /* https://man7.org/linux/man-pages/man2/mmap.2.html */ -static void *linux_mmap(void *addr, size_t length, int prot, +static void *linux_mmap(SysFrm *, void *addr, size_t length, int prot, int flags, int fildes, off_t offset) { static_assert(PROT_NONE == sc_PROT_NONE); @@ -306,43 +231,199 @@ static void *linux_mmap(void *addr, size_t length, int prot, } if (flags) fixme("unhandled flags: %#x", flags); + flags = new_flags; - return sys_mmap(thisFrame, addr, length, prot, - new_flags, fildes, offset); + if (length == 0) + return (void *)-EINVAL; + + if (fildes != -1) + return (void *)-ENOSYS; + + bool p_None = prot & sc_PROT_NONE; + bool p_Read = prot & sc_PROT_READ; + bool p_Write = prot & sc_PROT_WRITE; + bool p_Exec = prot & sc_PROT_EXEC; + + bool m_Shared = flags & sc_MAP_SHARED; + bool m_Private = flags & sc_MAP_PRIVATE; + bool m_Fixed = flags & sc_MAP_FIXED; + bool m_Anon = flags & sc_MAP_ANONYMOUS; + + UNUSED(p_None); + UNUSED(m_Anon); + + debug("N:%d R:%d W:%d E:%d", + p_None, p_Read, p_Write, + p_Exec); + + debug("S:%d P:%d F:%d A:%d", + m_Shared, m_Private, + m_Fixed, m_Anon); + + int UnknownFlags = flags & ~(sc_MAP_SHARED | + sc_MAP_PRIVATE | + sc_MAP_FIXED | + sc_MAP_ANONYMOUS); + + if (UnknownFlags) + { + debug("Unknown flags: %x", UnknownFlags); + return (void *)-EINVAL; + } + + if (length > PAGE_SIZE_2M) + fixme("large page 2 MiB (requested %d)", + TO_MiB(length)); + else if (length > PAGE_SIZE_1G) + fixme("huge page 1 GiB (requested %d)", + TO_GiB(length)); + + if (offset % PAGE_SIZE) + return (void *)-EINVAL; + + if (uintptr_t(addr) % PAGE_SIZE && m_Fixed) + return (void *)-EINVAL; + + if ((m_Shared && m_Private) || + (!m_Shared && !m_Private)) + return (void *)-EINVAL; + + PCB *pcb = thisProcess; + Memory::VirtualMemoryArea *vma = pcb->vma; + intptr_t ret = (intptr_t)vma->CreateCoWRegion(addr, length, + p_Read, p_Write, p_Exec, + m_Fixed, m_Shared); + + return (void *)ret; } #undef __FENNIX_KERNEL_SYSCALLS_LIST_H__ /* https://man7.org/linux/man-pages/man2/mprotect.2.html */ -static int linux_mprotect(void *addr, size_t len, int prot) +static int linux_mprotect(SysFrm *, void *addr, size_t len, int prot) { - return sys_mprotect(thisFrame, addr, len, prot); + if (len == 0) + return -EINVAL; + + if (uintptr_t(addr) % PAGE_SIZE) + return -EINVAL; + + // bool p_None = prot & sc_PROT_NONE; + bool p_Read = prot & sc_PROT_READ; + bool p_Write = prot & sc_PROT_WRITE; + // bool p_Exec = prot & sc_PROT_EXEC; + + PCB *pcb = thisProcess; + Memory::Virtual vmm = Memory::Virtual(pcb->PageTable); + + for (uintptr_t i = uintptr_t(addr); + i < uintptr_t(addr) + len; + i += PAGE_SIZE) + { + if (likely(!vmm.Check((void *)i, Memory::G))) + { + Memory::PageTableEntry *pte = vmm.GetPTE(addr); + if (pte == nullptr) + { + debug("Page %#lx is not mapped inside %#lx", + (void *)i, pcb->PageTable); + fixme("Page %#lx is not mapped", (void *)i); + continue; + return -ENOMEM; + } + + if (!pte->Present || + (!pte->UserSupervisor && p_Read) || + (!pte->ReadWrite && p_Write)) + { + debug("Page %p is not mapped with the correct permissions", + (void *)i); + return -EACCES; + } + + // pte->Present = !p_None; + pte->UserSupervisor = p_Read; + pte->ReadWrite = p_Write; + // pte->ExecuteDisable = p_Exec; + + debug("Changed permissions of page %#lx to %s %s %s %s", + (void *)i, + (prot & sc_PROT_NONE) ? "None" : "", + p_Read ? "Read" : "", + p_Write ? "Write" : "", + (prot & sc_PROT_EXEC) ? "Exec" : ""); + +#if defined(a64) + CPU::x64::invlpg(addr); +#elif defined(a32) + CPU::x32::invlpg(addr); +#elif defined(aa64) + asmv("dsb sy"); + asmv("tlbi vae1is, %0" + : + : "r"(addr) + : "memory"); + asmv("dsb sy"); + asmv("isb"); +#endif + } + else + { + warn("%p is a global page", (void *)i); + return -ENOMEM; + } + } + + return 0; } /* https://man7.org/linux/man-pages/man2/munmap.2.html */ -static int linux_munmap(void *addr, size_t length) +static int linux_munmap(SysFrm *, void *addr, size_t length) { - return sys_munmap(thisFrame, addr, length); + if (uintptr_t(addr) % PAGE_SIZE) + return -EINVAL; + + if (length == 0) + return -EINVAL; + + PCB *pcb = thisProcess; + Memory::VirtualMemoryArea *vma = pcb->vma; + Memory::Virtual vmm = Memory::Virtual(pcb->PageTable); + + for (uintptr_t i = uintptr_t(addr); + i < uintptr_t(addr) + length; + i += PAGE_SIZE) + { + if (likely(!vmm.Check((void *)i, Memory::G))) + vmm.Remap((void *)i, (void *)i, Memory::P | Memory::RW); + else + warn("%p is a global page", (void *)i); + } + + /* TODO: Check if the page is allocated + and not only mapped */ + vma->FreePages((void *)addr, TO_PAGES(length) + 1); + return 0; } /* https://man7.org/linux/man-pages/man2/brk.2.html */ -static void *linux_brk(void *addr) +static void *linux_brk(SysFrm *, void *addr) { - Tasking::PCB *pcb = thisProcess; + PCB *pcb = thisProcess; void *ret = pcb->ProgramBreak->brk(addr); debug("brk(%#lx) = %#lx", addr, ret); return ret; } /* https://man7.org/linux/man-pages/man2/ioctl.2.html */ -static int linux_ioctl(int fd, unsigned long request, void *argp) +static int linux_ioctl(SysFrm *, int fd, unsigned long request, void *argp) { - Tasking::PCB *pcb = thisProcess; + PCB *pcb = thisProcess; vfs::FileDescriptorTable *fdt = pcb->FileDescriptors; - Memory::Virtual vmm = Memory::Virtual(pcb->PageTable); + Memory::Virtual vmm(pcb->PageTable); if (!vmm.Check((void *)argp, Memory::US)) { - warn("Invalid address %#lx", argp); + debug("Invalid address %#lx", argp); return -EFAULT; } auto pArgp = pcb->PageTable->Get(argp); @@ -351,28 +432,35 @@ static int linux_ioctl(int fd, unsigned long request, void *argp) } /* https://man7.org/linux/man-pages/man2/readv.2.html */ -static ssize_t linux_readv(int fildes, const struct iovec *iov, int iovcnt) +static ssize_t linux_readv(SysFrm *sf, int fildes, const struct iovec *iov, int iovcnt) { - size_t iovec_size = sizeof(struct iovec) * iovcnt; - Tasking::PCB *pcb = thisProcess; - Memory::SmartHeap sh(iovec_size, pcb->vma); - { - Memory::SwapPT swap(pcb->PageTable); - memcpy(sh, iov, iovec_size); - } - iov = (struct iovec *)sh.Get(); + PCB *pcb = thisProcess; + const struct iovec *pIov = pcb->PageTable->Get(iov); ssize_t Total = 0; for (int i = 0; i < iovcnt; i++) { - debug("%d: iov[%d]: %p %d", fildes, i, iov[i].iov_base, iov[i].iov_len); - ssize_t n = linux_read(fildes, iov[i].iov_base, iov[i].iov_len); + debug("%d: iov[%d]: %p %d", fildes, i, pIov[i].iov_base, pIov[i].iov_len); + + if (!pIov[i].iov_base) + { + debug("invalid iov_base"); + return -EFAULT; + } + + if (pIov[i].iov_len == 0) + { + debug("invalid iov_len"); + continue; + } + + ssize_t n = linux_read(sf, fildes, pIov[i].iov_base, pIov[i].iov_len); if (n < 0) return n; debug("n: %d", n); Total += n; - if (n < (ssize_t)iov[i].iov_len) + if (n < (ssize_t)pIov[i].iov_len) { debug("break"); break; @@ -383,28 +471,35 @@ static ssize_t linux_readv(int fildes, const struct iovec *iov, int iovcnt) } /* https://man7.org/linux/man-pages/man2/writev.2.html */ -static ssize_t linux_writev(int fildes, const struct iovec *iov, int iovcnt) +static ssize_t linux_writev(SysFrm *sf, int fildes, const struct iovec *iov, int iovcnt) { - size_t iovec_size = sizeof(struct iovec) * iovcnt; - Tasking::PCB *pcb = thisProcess; - Memory::SmartHeap sh(iovec_size, pcb->vma); - { - Memory::SwapPT swap(pcb->PageTable); - memcpy(sh, iov, iovec_size); - } - iov = (struct iovec *)sh.Get(); + PCB *pcb = thisProcess; + const struct iovec *pIov = pcb->PageTable->Get(iov); ssize_t Total = 0; for (int i = 0; i < iovcnt; i++) { - debug("%d: iov[%d]: %p %d", fildes, i, iov[i].iov_base, iov[i].iov_len); - ssize_t n = linux_write(fildes, iov[i].iov_base, iov[i].iov_len); + debug("%d: iov[%d]: %p %d", fildes, i, pIov[i].iov_base, pIov[i].iov_len); + + if (!pIov[i].iov_base) + { + debug("invalid iov_base"); + return -EFAULT; + } + + if (pIov[i].iov_len == 0) + { + debug("invalid iov_len"); + continue; + } + + ssize_t n = linux_write(sf, fildes, pIov[i].iov_base, pIov[i].iov_len); if (n < 0) return n; debug("n: %d", n); Total += n; - if (n < (ssize_t)iov[i].iov_len) + if (n < (ssize_t)pIov[i].iov_len) { debug("break"); break; @@ -414,80 +509,593 @@ static ssize_t linux_writev(int fildes, const struct iovec *iov, int iovcnt) return Total; } -/* https://man7.org/linux/man-pages/man2/dup.2.html */ -static int linux_dup(int oldfd) +/* https://man7.org/linux/man-pages/man2/pipe.2.html */ +static int linux_pipe(SysFrm *, int pipefd[2]) { - Tasking::PCB *pcb = thisProcess; + PCB *pcb = thisProcess; + int *pPipefd = pcb->PageTable->Get(pipefd); + debug("pipefd=%#lx", pPipefd); + fixme("pipefd=[%d, %d]", pPipefd[0], pPipefd[1]); + return -ENOSYS; +} + +/* https://man7.org/linux/man-pages/man2/dup.2.html */ +static int linux_dup(SysFrm *, int oldfd) +{ + PCB *pcb = thisProcess; vfs::FileDescriptorTable *fdt = pcb->FileDescriptors; return fdt->_dup(oldfd); } /* https://man7.org/linux/man-pages/man2/dup.2.html */ -static int linux_dup2(int oldfd, int newfd) +static int linux_dup2(SysFrm *, int oldfd, int newfd) { - Tasking::PCB *pcb = thisProcess; + PCB *pcb = thisProcess; vfs::FileDescriptorTable *fdt = pcb->FileDescriptors; return fdt->_dup2(oldfd, newfd); } -/* https://man7.org/linux/man-pages/man2/fork.2.html */ -static pid_t linux_fork() +/* https://man7.org/linux/man-pages/man2/pause.2.html */ +static int linux_pause(SysFrm *) { - return sys_fork(thisFrame); + PCB *pcb = thisProcess; + return pcb->Signals->WaitAnySignal(); +} + +/* https://man7.org/linux/man-pages/man2/nanosleep.2.html */ +static int linux_nanosleep(SysFrm *, + const struct timespec *req, + struct timespec *rem) +{ + PCB *pcb = thisProcess; + Memory::Virtual vmm(pcb->PageTable); + + if (!vmm.Check((void *)req, Memory::US)) + { + debug("Invalid address %#lx", req); + return -EFAULT; + } + + if (rem && !vmm.Check((void *)rem, Memory::US)) + { + debug("Invalid address %#lx", rem); + return -EFAULT; + } + + auto pReq = pcb->PageTable->Get(req); + auto pRem = rem ? pcb->PageTable->Get(rem) : 0; + + if (pReq->tv_nsec < 0 || pReq->tv_nsec > 999999999) + { + debug("Invalid tv_nsec %ld", pReq->tv_nsec); + return -EINVAL; + } + + if (pReq->tv_sec < 0) + { + debug("Invalid tv_sec %ld", pReq->tv_sec); + return -EINVAL; + } + + debug("tv_nsec=%ld tv_sec=%ld", + pReq->tv_nsec, pReq->tv_sec); + + uint64_t nanoTime = pReq->tv_nsec; + uint64_t secTime = pReq->tv_sec * 1000000000; /* Nano */ + + uint64_t time = TimeManager->GetCounter(); + uint64_t sleepTime = TimeManager->CalculateTarget(nanoTime + secTime, Time::Nanoseconds); + + debug("time=%ld secTime=%ld nanoTime=%ld sleepTime=%ld", + time, secTime, nanoTime, sleepTime); + + while (time < sleepTime) + { + pcb->GetContext()->Yield(); + /* TODO: sleep should be interrupted by + the signal and return errno EINTR */ + time = TimeManager->GetCounter(); + } + debug("time= %ld", time); + debug("sleepTime=%ld", sleepTime); + + if (rem) + { + pRem->tv_sec = 0; + pRem->tv_nsec = 0; + } + return 0; +} + +/* https://man7.org/linux/man-pages/man2/getpid.2.html */ +static pid_t linux_getpid(SysFrm *) +{ + return thisProcess->ID; +} + +/* https://man7.org/linux/man-pages/man2/shutdown.2.html */ +static int linux_shutdown(SysFrm *, int sockfd, int how) +{ + stub; + return -ENOSYS; +} + +/* https://man7.org/linux/man-pages/man2/fork.2.html */ +static pid_t linux_fork(SysFrm *sf) +{ + TCB *Thread = thisThread; + PCB *Parent = Thread->Parent; + + PCB *NewProcess = + TaskManager->CreateProcess(Parent, + Parent->Name, + Parent->Security.ExecutionMode, + nullptr, true); + if (unlikely(!NewProcess)) + { + error("Failed to create process for fork"); + return -EAGAIN; + } + + NewProcess->PageTable = Parent->PageTable->Fork(); + NewProcess->vma->SetTable(NewProcess->PageTable); + NewProcess->vma->Fork(Parent->vma); + NewProcess->ProgramBreak->SetTable(NewProcess->PageTable); + NewProcess->FileDescriptors->Fork(Parent->FileDescriptors); + + if (Parent->ELFSymbolTable && + Parent->ELFSymbolTable->SymTableExists) + { + NewProcess->ELFSymbolTable = new SymbolResolver::Symbols(0); + foreach (auto sym in Parent->ELFSymbolTable->GetSymTable()) + { + NewProcess->ELFSymbolTable->AddSymbol(sym.Address, + sym.FunctionName); + } + } + + TCB *NewThread = + TaskManager->CreateThread(NewProcess, + 0, + nullptr, + nullptr, + std::vector(), + Thread->Info.Architecture, + Thread->Info.Compatibility, + true); + if (!NewThread) + { + error("Failed to create thread for fork"); + delete NewProcess; + return -EAGAIN; + } + NewThread->Rename(Thread->Name); + + TaskManager->UpdateFrame(); + + NewThread->FPU = Thread->FPU; + NewThread->Stack->Fork(Thread->Stack); + NewThread->Info.Architecture = Thread->Info.Architecture; + NewThread->Info.Compatibility = Thread->Info.Compatibility; + NewThread->Security.IsCritical = Thread->Security.IsCritical; + NewThread->Registers = Thread->Registers; +#if defined(a64) + NewThread->Registers.rip = (uintptr_t)linux_fork_return; + /* For sysretq */ + NewThread->Registers.rdi = (uintptr_t)NewProcess->PageTable; + NewThread->Registers.rcx = sf->ReturnAddress; + NewThread->Registers.r8 = sf->StackPointer; +#else +#warning "sys_fork not implemented for other platforms" +#endif + +#ifdef a86 + NewThread->GSBase = NewThread->ShadowGSBase; + NewThread->ShadowGSBase = Thread->ShadowGSBase; + NewThread->FSBase = Thread->FSBase; +#endif + + debug("ret addr: %#lx, stack: %#lx ip: %#lx", sf->ReturnAddress, + sf->StackPointer, (uintptr_t)linux_fork_return); + debug("Forked thread \"%s\"(%d) to \"%s\"(%d)", + Thread->Name, Thread->ID, + NewThread->Name, NewThread->ID); + NewThread->SetState(Tasking::Ready); + + // Parent->GetContext()->Yield(); + return (int)NewProcess->ID; } /* https://man7.org/linux/man-pages/man2/execve.2.html */ -static int linux_execve(const char *pathname, char *const argv[], +static int linux_execve(SysFrm *sf, const char *pathname, + char *const argv[], char *const envp[]) { - return sys_execve(thisFrame, pathname, argv, envp); + /* FIXME: exec doesn't follow the UNIX standard + The pid, open files, etc. should be preserved */ + PCB *pcb = thisProcess; + Memory::Virtual vmm = Memory::Virtual(pcb->PageTable); + + if (pathname == nullptr || + !vmm.Check((void *)pathname, Memory::US) || + !vmm.Check((void *)argv, Memory::US) || + !vmm.Check((void *)envp, Memory::US)) + return -ENOENT; + + const char *safe_path; + char **safe_argv; + char **safe_envp; + safe_path = (const char *)pcb->vma->RequestPages(1); + safe_argv = (char **)pcb->vma->RequestPages(TO_PAGES(MAX_ARG)); + safe_envp = (char **)pcb->vma->RequestPages(TO_PAGES(MAX_ARG)); + { + Memory::SwapPT swap(pcb->PageTable); + size_t len = strlen(pathname); + memset((void *)safe_path, 0, PAGE_SIZE); + memcpy((void *)safe_path, pathname, len); + + const char *arg; + char *n_arg; + for (int i = 0; argv[i] != nullptr; i++) + { + arg = argv[i]; + size_t len = strlen(arg); + + n_arg = (char *)pcb->vma->RequestPages(TO_PAGES(len)); + memcpy((void *)n_arg, arg, len); + n_arg[len] = '\0'; + + safe_argv[i] = n_arg; + + if (likely(i < MAX_ARG - 1)) + safe_argv[i + 1] = nullptr; + } + + for (int i = 0; envp[i] != nullptr; i++) + { + arg = envp[i]; + size_t len = strlen(arg); + + n_arg = (char *)pcb->vma->RequestPages(TO_PAGES(len)); + memcpy((void *)n_arg, arg, len); + n_arg[len] = '\0'; + + safe_envp[i] = n_arg; + + if (likely(i < MAX_ARG - 1)) + safe_envp[i + 1] = nullptr; + } + } + + function("%s %#lx %#lx", safe_path, safe_argv, safe_envp); + +#ifdef DEBUG + for (int i = 0; safe_argv[i] != nullptr; i++) + debug("safe_argv[%d]: %s", i, safe_argv[i]); + + for (int i = 0; safe_envp[i] != nullptr; i++) + debug("safe_envp[%d]: %s", i, safe_envp[i]); +#endif + + vfs::RefNode *File = fs->Open(safe_path, + pcb->CurrentWorkingDirectory); + + if (!File) + { + error("File not found"); + return -ENOENT; + } + + char shebang_magic[2]; + File->read((uint8_t *)shebang_magic, 2); + + if (shebang_magic[0] == '#' && shebang_magic[1] == '!') + { + char *orig_path = (char *)pcb->vma->RequestPages(TO_PAGES(strlen(pathname) + 1)); + memcpy(orig_path, pathname, strlen(pathname) + 1); + + char *shebang = (char *)safe_path; + size_t shebang_len = 0; + constexpr int shebang_len_max = 255; + File->seek(2, SEEK_SET); + off_t shebang_off = 2; + while (true) + { + char c; + if (File->node->read((uint8_t *)&c, 1, shebang_off) == 0) + break; + if (c == '\n' || shebang_len == shebang_len_max) + break; + shebang[shebang_len++] = c; + shebang_off++; + } + shebang[shebang_len] = '\0'; + debug("Shebang: %s", shebang); + + char **c_safe_argv = (char **)pcb->vma->RequestPages(TO_PAGES(MAX_ARG)); + int i = 0; + for (; safe_argv[i] != nullptr; i++) + { + size_t arg_len = strlen(safe_argv[i]); + char *c_arg = (char *)pcb->vma->RequestPages(TO_PAGES(arg_len)); + memcpy((void *)c_arg, safe_argv[i], arg_len); + c_arg[arg_len] = '\0'; + + c_safe_argv[i] = c_arg; + debug("c_safe_argv[%d]: %s", i, c_safe_argv[i]); + } + c_safe_argv[i] = nullptr; + + char *token = strtok(shebang, " "); + i = 0; + while (token != nullptr) + { + size_t len = strlen(token); + char *t_arg = (char *)pcb->vma->RequestPages(TO_PAGES(len)); + memcpy((void *)t_arg, token, len); + t_arg[len] = '\0'; + + safe_argv[i++] = t_arg; + token = strtok(nullptr, " "); + } + + safe_argv[i++] = orig_path; + for (int j = 1; c_safe_argv[j] != nullptr; j++) + { + safe_argv[i++] = c_safe_argv[j]; + debug("clone: safe_argv[%d]: %s", + i, safe_argv[i - 1]); + } + safe_argv[i] = nullptr; + + delete File; + return linux_execve(sf, safe_argv[0], + (char *const *)safe_argv, + (char *const *)safe_envp); + } + + int ret = Execute::Spawn((char *)safe_path, + (const char **)safe_argv, + (const char **)safe_envp, + pcb, true, + pcb->Info.Compatibility); + + if (ret < 0) + { + error("Failed to spawn"); + delete File; + return ret; + } + + delete File; + Tasking::Task *ctx = pcb->GetContext(); + // ctx->Sleep(1000); + // pcb->SetState(Tasking::Zombie); + // pcb->SetExitCode(0); /* FIXME: get process exit code */ + while (true) + ctx->Yield(); + __builtin_unreachable(); } /* https://man7.org/linux/man-pages/man2/exit.2.html */ -static __noreturn void linux_exit(int status) +static __noreturn void linux_exit(SysFrm *, int status) { - sys_exit(thisFrame, status); + TCB *t = thisThread; + + trace("Userspace thread %s(%d) exited with code %d (%#x)", + t->Name, + t->ID, status, + status < 0 ? -status : status); + + t->SetState(Tasking::Zombie); + t->SetExitCode(status); + while (true) + t->GetContext()->Yield(); + __builtin_unreachable(); } /* https://man7.org/linux/man-pages/man2/wait4.2.html */ -static pid_t linux_wait4(pid_t pid, int *wstatus, int options, struct rusage *rusage) +static pid_t linux_wait4(SysFrm *, pid_t pid, int *wstatus, + int options, struct rusage *rusage) { static_assert(sizeof(struct rusage) < PAGE_SIZE); + /* FIXME: this function is very poorly implemented, the way + it handles the zombie & coredump processes is very + inefficient and should be rewritten */ - Tasking::PCB *pcb = thisProcess; - Memory::Virtual vmm = Memory::Virtual(pcb->PageTable); + PCB *pcb = thisProcess; + Memory::Virtual vmm(pcb->PageTable); if (!vmm.Check(rusage, Memory::US) && rusage != nullptr) { - warn("Invalid address %#lx", rusage); + debug("Invalid address %#lx", rusage); return -EFAULT; } if (pid == -1) - pid = pcb->ID + 1; /* TODO: Wait for any child process */ + { + if (pcb->Children.empty()) + { + debug("No children"); + return -ECHILD; + } - Tasking::PCB *tPcb = pcb->GetContext()->GetProcessByID(pid); + std::vector wChilds; + for (auto child : pcb->Children) + { + if (child->State == Tasking::Zombie) + { + if (wstatus != nullptr) + { + int *pWstatus = pcb->PageTable->Get(wstatus); + *pWstatus = 0; + bool ProcessExited = true; + int ExitStatus = child->ExitCode.load(); + + debug("Process returned %d", ExitStatus); + + if (ProcessExited) + *pWstatus |= ExitStatus << 8; + } + + if (rusage != nullptr) + { + size_t kTime = child->Info.KernelTime; + size_t uTime = child->Info.UserTime; + size_t _maxrss = child->GetSize(); + + struct rusage *pRusage = pcb->PageTable->Get(rusage); + + pRusage->ru_utime.tv_sec = uTime / 1000000000000000; /* Seconds */ + pRusage->ru_utime.tv_usec = uTime / 1000000000; /* Microseconds */ + + pRusage->ru_stime.tv_sec = kTime / 1000000000000000; /* Seconds */ + pRusage->ru_stime.tv_usec = kTime / 1000000000; /* Microseconds */ + + pRusage->ru_maxrss = _maxrss; + } + + child->SetState(Tasking::Terminated); + return child->ID; + } + + if (child->State == Tasking::CoreDump) + { + if (wstatus != nullptr) + { + int *pWstatus = pcb->PageTable->Get(wstatus); + *pWstatus = 0; + + bool ProcessExited = true; + int ExitStatus = child->ExitCode.load(); + bool ProcessSignaled = true; + bool CoreDumped = true; + int TermSignal = child->Signals->GetLastSignal(); + + debug("Process returned %d", ExitStatus); + + if (ProcessExited) + *pWstatus |= ExitStatus << 8; + + if (ProcessSignaled) + *pWstatus |= TermSignal; + + if (CoreDumped) + *pWstatus |= 0x80; + } + + if (rusage != nullptr) + { + size_t kTime = child->Info.KernelTime; + size_t uTime = child->Info.UserTime; + size_t _maxrss = child->GetSize(); + + struct rusage *pRusage = pcb->PageTable->Get(rusage); + + pRusage->ru_utime.tv_sec = uTime / 1000000000000000; /* Seconds */ + pRusage->ru_utime.tv_usec = uTime / 1000000000; /* Microseconds */ + + pRusage->ru_stime.tv_sec = kTime / 1000000000000000; /* Seconds */ + pRusage->ru_stime.tv_usec = kTime / 1000000000; /* Microseconds */ + + pRusage->ru_maxrss = _maxrss; + } + + child->SetState(Tasking::Terminated); + return child->ID; + } + + if (child->State != Tasking::Terminated) + wChilds.push_back(child); + } + + if (wChilds.empty()) + { + debug("No children"); + return -ECHILD; + } + + fixme("Waiting for %d children", wChilds.size()); + pid = wChilds.front()->ID; + } + + if (pid == 0) + { + fixme("Waiting for any child process whose process group ID is equal to that of the calling process"); + return -ENOSYS; + } + + if (pid < -1) + { + fixme("Waiting for any child process whose process group ID is equal to the absolute value of pid"); + return -ENOSYS; + } + + /* Wait for a child process, or any process? */ + PCB *tPcb = pcb->GetContext()->GetProcessByID(pid); if (!tPcb) { warn("Invalid PID %d", pid); return -ECHILD; } - tPcb->KeepInMemory = true; - - Tasking::TaskState state = tPcb->State; - debug("Waiting for %d(%#lx) state %d", pid, tPcb, state); - while (tPcb->State == state) - pcb->GetContext()->Yield(); - debug("Waited for %d(%#lx) state %d", pid, tPcb, state); - - if (wstatus) + if (options) { - int status = tPcb->ExitCode.load(); +#define WCONTINUED 1 +#define WNOHANG 2 +#define WUNTRACED 4 +#define WEXITED 8 +#define WNOWAIT 16 +#define WSTOPPED 32 + fixme("options=%#x", options); + } - Memory::SwapPT swap(pcb->PageTable); - *wstatus = status; +#ifdef DEBUG + foreach (auto child in pcb->Children) + debug("Child: %s(%d)", child->Name, child->ID); +#endif + + debug("Waiting for %d(%#lx) state %d", pid, tPcb, tPcb->State); + while (tPcb->State != Tasking::Zombie && + tPcb->State != Tasking::CoreDump && + tPcb->State != Tasking::Terminated) + pcb->GetContext()->Yield(); + debug("Waited for %d(%#lx) state %d", pid, tPcb, tPcb->State); + + if (wstatus != nullptr) + { + int *pWstatus = pcb->PageTable->Get(wstatus); + *pWstatus = 0; + + bool ProcessExited = true; + int ExitStatus = tPcb->ExitCode.load(); + bool ProcessSignaled = false; + bool CoreDumped = false; + bool ProcessStopped = false; + bool ProcessContinued = false; + int TermSignal = 0; + + debug("Process returned %d", ExitStatus); + + if (ProcessExited) + *pWstatus |= ExitStatus << 8; + + if (ProcessSignaled) + *pWstatus |= TermSignal; + + if (CoreDumped) + *pWstatus |= 0x80; + + /* FIXME: Untested */ + + if (ProcessStopped) + *pWstatus |= 0x7F; + + if (ProcessContinued) + *pWstatus = 0xFFFF; + + debug("wstatus=%#x", *pWstatus); } if (rusage != nullptr) @@ -496,48 +1104,267 @@ static pid_t linux_wait4(pid_t pid, int *wstatus, int options, struct rusage *ru size_t uTime = tPcb->Info.UserTime; size_t _maxrss = tPcb->GetSize(); - { - Memory::SwapPT swap(pcb->PageTable); + struct rusage *pRusage = pcb->PageTable->Get(rusage); - rusage->ru_utime.tv_sec = uTime / 1000000000000000; /* Seconds */ - rusage->ru_utime.tv_usec = uTime / 1000000000; /* Microseconds */ + pRusage->ru_utime.tv_sec = uTime / 1000000000000000; /* Seconds */ + pRusage->ru_utime.tv_usec = uTime / 1000000000; /* Microseconds */ - rusage->ru_stime.tv_sec = kTime / 1000000000000000; /* Seconds */ - rusage->ru_stime.tv_usec = kTime / 1000000000; /* Microseconds */ + pRusage->ru_stime.tv_sec = kTime / 1000000000000000; /* Seconds */ + pRusage->ru_stime.tv_usec = kTime / 1000000000; /* Microseconds */ - rusage->ru_maxrss = _maxrss; - /* TODO: The rest of the fields */ - } + pRusage->ru_maxrss = _maxrss; + /* TODO: The rest of the fields */ } - tPcb->KeepInMemory = false; - debug("%d", pid); return pid; } -/* https://man7.org/linux/man-pages/man2/creat.2.html */ -static int linux_creat(const char *pathname, mode_t mode) +/* https://man7.org/linux/man-pages/man2/kill.2.html */ +static int linux_kill(SysFrm *, pid_t pid, int sig) { - Tasking::PCB *pcb = thisProcess; + PCB *target = thisProcess->GetContext()->GetProcessByID(pid); + if (!target) + return -ESRCH; + + /* TODO: Check permissions */ + + if (sig == 0) + return 0; + + if (pid == 0) + { + fixme("Sending signal %d to all processes", sig); + return -ENOSYS; + } + + if (pid == -1) + { + fixme("Sending signal %d to all processes except init", sig); + return -ENOSYS; + } + + if (pid < -1) + { + fixme("Sending signal %d to process group %d", sig, pid); + return -ENOSYS; + } + + return target->Signals->SendSignal(sig); +} + +/* https://man7.org/linux/man-pages/man2/uname.2.html */ +static int linux_uname(SysFrm *, struct utsname *buf) +{ + assert(sizeof(struct utsname) < PAGE_SIZE); + + PCB *pcb = thisProcess; + Memory::Virtual vmm(pcb->PageTable); + + if (!vmm.Check(buf, Memory::US)) + { + debug("Invalid address %#lx", buf); + return -EFAULT; + } + + auto pBuf = pcb->PageTable->Get(buf); + + struct utsname uname = + { + /* TODO: This shouldn't be hardcoded */ + .sysname = KERNEL_NAME, + .nodename = "fennix", + .release = KERNEL_VERSION, + .version = KERNEL_VERSION, +#if defined(a64) + .machine = "x86_64", +#elif defined(a32) + .machine = "i386", +#elif defined(aa64) + .machine = "arm64", +#elif defined(aa32) + .machine = "arm", +#endif + }; + + vfs::RefNode *rn = fs->Open("/etc/cross/linux"); + if (rn) + { + Memory::SmartHeap sh(rn->Size); + rn->read(sh, rn->Size); + delete rn; + + ini_t *ini = ini_load(sh, NULL); + int section = ini_find_section(ini, "uname", NULL); + int sysIdx = ini_find_property(ini, section, "sysname", NULL); + int nodIdx = ini_find_property(ini, section, "nodename", NULL); + int relIdx = ini_find_property(ini, section, "release", NULL); + int verIdx = ini_find_property(ini, section, "version", NULL); + int macIdx = ini_find_property(ini, section, "machine", NULL); + const char *uSys = ini_property_value(ini, section, sysIdx); + const char *uNod = ini_property_value(ini, section, nodIdx); + const char *uRel = ini_property_value(ini, section, relIdx); + const char *uVer = ini_property_value(ini, section, verIdx); + const char *uMac = ini_property_value(ini, section, macIdx); + debug("sysname=%s", uSys); + debug("nodename=%s", uNod); + debug("release=%s", uRel); + debug("version=%s", uVer); + debug("machine=%s", uMac); + + if (uSys && strcmp(uSys, "auto") != 0) + strncpy(uname.sysname, uSys, sizeof(uname.sysname)); + if (uNod && strcmp(uNod, "auto") != 0) + strncpy(uname.nodename, uNod, sizeof(uname.nodename)); + if (uRel && strcmp(uRel, "auto") != 0) + strncpy(uname.release, uRel, sizeof(uname.release)); + if (uVer && strcmp(uVer, "auto") != 0) + strncpy(uname.version, uVer, sizeof(uname.version)); + if (uMac && strcmp(uMac, "auto") != 0) + strncpy(uname.machine, uMac, sizeof(uname.machine)); + ini_destroy(ini); + } + else + warn("Couldn't open /etc/cross/linux"); + + memcpy(pBuf, &uname, sizeof(struct utsname)); + return 0; +} + +static int linux_fcntl(SysFrm *, int fd, int cmd, void *arg) +{ + PCB *pcb = thisProcess; + vfs::FileDescriptorTable *fdt = pcb->FileDescriptors; + Memory::Virtual vmm(pcb->PageTable); + + switch (cmd) + { + case F_DUPFD: + return fdt->_dup2(fd, s_cst(int, (uintptr_t)arg)); + case F_GETFD: + return fdt->GetFlags(fd); + case F_SETFD: + return fdt->SetFlags(fd, s_cst(int, (uintptr_t)arg)); + case F_GETFL: + case F_SETFL: + case F_SETOWN: + case F_GETOWN: + case F_SETSIG: + case F_GETSIG: + case F_GETLK: + case F_SETLK: + case F_SETLKW: + case F_SETOWN_EX: + case F_GETOWN_EX: + { + fixme("cmd %d not implemented", cmd); + return -ENOSYS; + } + default: + { + debug("Invalid cmd %#x", cmd); + return -EINVAL; + } + } +} + +/* https://man7.org/linux/man-pages/man2/creat.2.html */ +static int linux_creat(SysFrm *, const char *pathname, mode_t mode) +{ + PCB *pcb = thisProcess; vfs::FileDescriptorTable *fdt = pcb->FileDescriptors; return fdt->_creat(pathname, mode); } -/* https://man7.org/linux/man-pages/man2/arch_prctl.2.html */ -static int linux_arch_prctl(int code, unsigned long addr) +/* https://man7.org/linux/man-pages/man2/mkdir.2.html */ +static int linux_mkdir(SysFrm *, const char *pathname, mode_t mode) { - Tasking::PCB *pcb = thisProcess; - Memory::Virtual vmm = Memory::Virtual(pcb->PageTable); + PCB *pcb = thisProcess; + fixme("semi-stub"); + + const char *pPathname = pcb->PageTable->Get(pathname); + vfs::Node *n = fs->Create(pPathname, vfs::DIRECTORY, pcb->CurrentWorkingDirectory); + if (!n) + return -EEXIST; + return 0; +} + +/* https://man7.org/linux/man-pages/man2/readlink.2.html */ +static ssize_t linux_readlink(SysFrm *, const char *pathname, + char *buf, size_t bufsiz) +{ + if (!pathname || !buf) + return -EINVAL; + + if (bufsiz > PAGE_SIZE) + { + warn("bufsiz is too large: %ld", bufsiz); + return -EINVAL; + } + + PCB *pcb = thisProcess; + Memory::Virtual vmm(pcb->PageTable); + if (!vmm.Check((void *)buf, Memory::US)) + { + warn("Invalid address %#lx", buf); + return -EFAULT; + } + + const char *pPath = pcb->PageTable->Get(pathname); + char *pBuf = pcb->PageTable->Get(buf); + function("%s %#lx %ld", pPath, buf, bufsiz); + vfs::FileDescriptorTable *fdt = pcb->FileDescriptors; + int fd = fdt->_open(pPath, O_RDONLY, 0); + if (fd < 0) + return -ENOENT; + + vfs::FileDescriptorTable::Fildes fildes = fdt->GetDescriptor(fd); + vfs::Node *node = fildes.Handle->node; + fdt->_close(fd); + + if (node->Type != vfs::NodeType::SYMLINK) + return -EINVAL; + + if (!node->Symlink) + { + warn("Symlink null for \"%s\"?", pPath); + return -EINVAL; + } + + size_t len = strlen(node->Symlink); + if (len > bufsiz) + len = bufsiz; + + strncpy(pBuf, node->Symlink, len); + return len; +} + +/* https://man7.org/linux/man-pages/man2/getuid.2.html */ +static uid_t linux_getuid(SysFrm *) +{ + return thisProcess->Security.Real.UserID; +} + +/* https://man7.org/linux/man-pages/man2/getpid.2.html */ +static pid_t linux_getppid(SysFrm *) +{ + return thisProcess->Parent->ID; +} + +/* https://man7.org/linux/man-pages/man2/arch_prctl.2.html */ +static int linux_arch_prctl(SysFrm *, int code, unsigned long addr) +{ + PCB *pcb = thisProcess; + Memory::Virtual vmm(pcb->PageTable); if (!vmm.Check((void *)addr)) { - warn("Invalid address %#lx", addr); + debug("Invalid address %#lx", addr); return -EFAULT; } if (!vmm.Check((void *)addr, Memory::US)) { - warn("Address %#lx is not user accessible", addr); + debug("Address %#lx is not user accessible", addr); return -EPERM; } @@ -605,20 +1432,194 @@ static int linux_arch_prctl(int code, unsigned long addr) } default: { - warn("Invalid code %#lx", code); + debug("Invalid code %#lx", code); return -EINVAL; } } } +/* https://man7.org/linux/man-pages/man2/reboot.2.html */ +static int linux_reboot(SysFrm *, int magic, int magic2, int cmd, void *arg) +{ + if (magic != LINUX_REBOOT_MAGIC1 || + (magic2 != LINUX_REBOOT_MAGIC2 && + magic2 != LINUX_REBOOT_MAGIC2A && + magic2 != LINUX_REBOOT_MAGIC2B && + magic2 != LINUX_REBOOT_MAGIC2C)) + { + warn("Invalid magic %#x %#x", magic, magic2); + return -EINVAL; + } + + PCB *pcb = thisProcess; + + debug("cmd=%#x arg=%#lx", cmd, arg); + switch ((unsigned int)cmd) + { + case LINUX_REBOOT_CMD_RESTART: + { + KPrint("Restarting system."); + + Tasking::Task *ctx = pcb->GetContext(); + ctx->CreateThread(ctx->GetKernelProcess(), + Tasking::IP(KST_Reboot)) + ->Rename("Restart"); + return 0; + } + case LINUX_REBOOT_CMD_HALT: + { + KPrint("System halted."); + + pcb->GetContext()->Panic(); + CPU::Stop(); + } + case LINUX_REBOOT_CMD_POWER_OFF: + { + KPrint("Power down."); + + Tasking::Task *ctx = pcb->GetContext(); + ctx->CreateThread(ctx->GetKernelProcess(), + Tasking::IP(KST_Shutdown)) + ->Rename("Shutdown"); + return 0; + } + case LINUX_REBOOT_CMD_RESTART2: + { + Memory::Virtual vmm(pcb->PageTable); + if (!vmm.Check(arg, Memory::US)) + { + debug("Invalid address %#lx", arg); + return -EFAULT; + } + + void *pArg = pcb->PageTable->Get(arg); + KPrint("Restarting system with command '%s'", + (const char *)pArg); + + Tasking::Task *ctx = pcb->GetContext(); + ctx->CreateThread(ctx->GetKernelProcess(), + Tasking::IP(KST_Reboot)) + ->Rename("Restart"); + break; + } + case LINUX_REBOOT_CMD_CAD_ON: + case LINUX_REBOOT_CMD_CAD_OFF: + case LINUX_REBOOT_CMD_SW_SUSPEND: + case LINUX_REBOOT_CMD_KEXEC: + { + fixme("cmd %#x not implemented", cmd); + return -ENOSYS; + } + default: + { + debug("Invalid cmd %#x", cmd); + return -EINVAL; + } + } + return 0; +} + +/* https://man7.org/linux/man-pages/man2/sigaction.2.html */ +static int linux_sigaction(SysFrm *, int signum, + const struct sigaction *act, + struct sigaction *oldact) +{ + if (signum == linux_SIGKILL || signum == linux_SIGSTOP) + { + debug("Invalid signal %d", signum); + return -EINVAL; + } + + PCB *pcb = thisProcess; + Memory::Virtual vmm(pcb->PageTable); + + if (oldact && !vmm.Check(oldact, Memory::US)) + { + debug("Invalid address %#lx", oldact); + return -EFAULT; + } + + if (act && !vmm.Check((void *)act, Memory::US)) + { + debug("Invalid address %#lx", act); + return -EFAULT; + } + + debug("signum=%d act=%#lx oldact=%#lx", signum, act, oldact); + + auto pOldact = pcb->PageTable->Get(oldact); + auto pAct = pcb->PageTable->Get(act); + int ret = 0; + + if (pOldact) + ret = pcb->Signals->GetAction(signum, pOldact); + + if (unlikely(ret < 0)) + return ret; + + if (pAct) + ret = pcb->Signals->SetAction(signum, *pAct); + + return ret; +} + +/* https://man7.org/linux/man-pages/man2/sigprocmask.2.html */ +static int linux_sigprocmask(SysFrm *, int how, const sigset_t *set, + sigset_t *oldset, size_t sigsetsize) +{ + static_assert(sizeof(sigset_t) < PAGE_SIZE); + + if (sigsetsize != sizeof(sigset_t)) + { + warn("Unsupported sigsetsize %d!", sigsetsize); + return -EINVAL; + } + + PCB *pcb = thisProcess; + const sigset_t *pSet = (const sigset_t *)pcb->PageTable->Get((void *)set); + sigset_t *pOldset = (sigset_t *)pcb->PageTable->Get(oldset); + + debug("how=%#x set=%#lx oldset=%#lx", + how, pSet ? *pSet : 0, pOldset ? *pOldset : 0); + + if (pOldset) + *pOldset = pcb->Signals->GetMask(); + + if (!pSet) + return 0; + + switch (how) + { + case SIG_BLOCK: + pcb->Signals->Block(*pSet); + break; + case SIG_UNBLOCK: + pcb->Signals->Unblock(*pSet); + break; + case SIG_SETMASK: + pcb->Signals->SetMask(*pSet); + break; + default: + warn("Invalid how %#x", how); + return -EINVAL; + } + return 0; +} + +/* https://man7.org/linux/man-pages/man2/sigreturn.2.html */ +static void linux_sigreturn(SysFrm *sf) +{ + thisProcess->Signals->RestoreHandleSignal(sf); +} + /* https://man7.org/linux/man-pages/man2/gettid.2.html */ -static pid_t linux_gettid() +static pid_t linux_gettid(SysFrm *) { return thisThread->ID; } /* https://man7.org/linux/man-pages/man2/set_tid_address.2.html */ -static pid_t linux_set_tid_address(int *tidptr) +static pid_t linux_set_tid_address(SysFrm *, int *tidptr) { if (tidptr == nullptr) return -EINVAL; @@ -629,349 +1630,615 @@ static pid_t linux_set_tid_address(int *tidptr) return tcb->ID; } -/* https://man7.org/linux/man-pages/man2/exit_group.2.html */ -static __noreturn void linux_exit_group(int status) +/* https://man7.org/linux/man-pages/man2/getdents.2.html */ +static ssize_t linux_getdents64(SysFrm *, int fd, struct linux_dirent64 *dirp, + size_t count) { - fixme("status=%d", status); - linux_exit(status); + PCB *pcb = thisProcess; + vfs::FileDescriptorTable *fdt = pcb->FileDescriptors; + + if (count < sizeof(struct linux_dirent64)) + { + debug("Invalid count %d", count); + return -EINVAL; + } + + vfs::FileDescriptorTable::Fildes & + fildes = fdt->GetDescriptor(fd); + if (!fildes.Handle) + { + debug("Invalid fd %d", fd); + return -EBADF; + } + + if (fildes.Handle->node->Type != vfs::NodeType::DIRECTORY) + { + debug("Invalid node type %d", + fildes.Handle->node->Type); + return -ENOTDIR; + } + + auto pDirp = pcb->PageTable->Get(dirp); + UNUSED(pDirp); + stub; + return -ENOSYS; } -static SyscallData LinuxSyscallsTable[] = { - [__NR_read] = {"read", (void *)linux_read}, - [__NR_write] = {"write", (void *)linux_write}, - [__NR_open] = {"open", (void *)linux_open}, - [__NR_close] = {"close", (void *)linux_close}, - [__NR_stat] = {"stat", (void *)linux_stat}, - [__NR_fstat] = {"fstat", (void *)linux_fstat}, - [__NR_lstat] = {"lstat", (void *)linux_lstat}, - [__NR_poll] = {"poll", (void *)nullptr}, - [__NR_lseek] = {"lseek", (void *)linux_lseek}, - [__NR_mmap] = {"mmap", (void *)linux_mmap}, - [__NR_mprotect] = {"mprotect", (void *)linux_mprotect}, - [__NR_munmap] = {"munmap", (void *)linux_munmap}, - [__NR_brk] = {"brk", (void *)linux_brk}, - [__NR_rt_sigaction] = {"rt_sigaction", (void *)nullptr}, - [__NR_rt_sigprocmask] = {"rt_sigprocmask", (void *)nullptr}, - [__NR_rt_sigreturn] = {"rt_sigreturn", (void *)nullptr}, - [__NR_ioctl] = {"ioctl", (void *)linux_ioctl}, - [__NR_pread64] = {"pread64", (void *)nullptr}, - [__NR_pwrite64] = {"pwrite64", (void *)nullptr}, - [__NR_readv] = {"readv", (void *)linux_readv}, - [__NR_writev] = {"writev", (void *)linux_writev}, - [__NR_access] = {"access", (void *)nullptr}, - [__NR_pipe] = {"pipe", (void *)nullptr}, - [__NR_select] = {"select", (void *)nullptr}, - [__NR_sched_yield] = {"sched_yield", (void *)nullptr}, - [__NR_mremap] = {"mremap", (void *)nullptr}, - [__NR_msync] = {"msync", (void *)nullptr}, - [__NR_mincore] = {"mincore", (void *)nullptr}, - [__NR_madvise] = {"madvise", (void *)nullptr}, - [__NR_shmget] = {"shmget", (void *)nullptr}, - [__NR_shmat] = {"shmat", (void *)nullptr}, - [__NR_shmctl] = {"shmctl", (void *)nullptr}, - [__NR_dup] = {"dup", (void *)linux_dup}, - [__NR_dup2] = {"dup2", (void *)linux_dup2}, - [__NR_pause] = {"pause", (void *)nullptr}, - [__NR_nanosleep] = {"nanosleep", (void *)nullptr}, - [__NR_getitimer] = {"getitimer", (void *)nullptr}, - [__NR_alarm] = {"alarm", (void *)nullptr}, - [__NR_setitimer] = {"setitimer", (void *)nullptr}, - [__NR_getpid] = {"getpid", (void *)nullptr}, - [__NR_sendfile] = {"sendfile", (void *)nullptr}, - [__NR_socket] = {"socket", (void *)nullptr}, - [__NR_connect] = {"connect", (void *)nullptr}, - [__NR_accept] = {"accept", (void *)nullptr}, - [__NR_sendto] = {"sendto", (void *)nullptr}, - [__NR_recvfrom] = {"recvfrom", (void *)nullptr}, - [__NR_sendmsg] = {"sendmsg", (void *)nullptr}, - [__NR_recvmsg] = {"recvmsg", (void *)nullptr}, - [__NR_shutdown] = {"shutdown", (void *)nullptr}, - [__NR_bind] = {"bind", (void *)nullptr}, - [__NR_listen] = {"listen", (void *)nullptr}, - [__NR_getsockname] = {"getsockname", (void *)nullptr}, - [__NR_getpeername] = {"getpeername", (void *)nullptr}, - [__NR_socketpair] = {"socketpair", (void *)nullptr}, - [__NR_setsockopt] = {"setsockopt", (void *)nullptr}, - [__NR_getsockopt] = {"getsockopt", (void *)nullptr}, - [__NR_clone] = {"clone", (void *)nullptr}, - [__NR_fork] = {"fork", (void *)linux_fork}, - [__NR_vfork] = {"vfork", (void *)nullptr}, - [__NR_execve] = {"execve", (void *)linux_execve}, - [__NR_exit] = {"exit", (void *)linux_exit}, - [__NR_wait4] = {"wait4", (void *)linux_wait4}, - [__NR_kill] = {"kill", (void *)nullptr}, - [__NR_uname] = {"uname", (void *)nullptr}, - [__NR_semget] = {"semget", (void *)nullptr}, - [__NR_semop] = {"semop", (void *)nullptr}, - [__NR_semctl] = {"semctl", (void *)nullptr}, - [__NR_shmdt] = {"shmdt", (void *)nullptr}, - [__NR_msgget] = {"msgget", (void *)nullptr}, - [__NR_msgsnd] = {"msgsnd", (void *)nullptr}, - [__NR_msgrcv] = {"msgrcv", (void *)nullptr}, - [__NR_msgctl] = {"msgctl", (void *)nullptr}, - [__NR_fcntl] = {"fcntl", (void *)nullptr}, - [__NR_flock] = {"flock", (void *)nullptr}, - [__NR_fsync] = {"fsync", (void *)nullptr}, - [__NR_fdatasync] = {"fdatasync", (void *)nullptr}, - [__NR_truncate] = {"truncate", (void *)nullptr}, - [__NR_ftruncate] = {"ftruncate", (void *)nullptr}, - [__NR_getdents] = {"getdents", (void *)nullptr}, - [__NR_getcwd] = {"getcwd", (void *)nullptr}, - [__NR_chdir] = {"chdir", (void *)nullptr}, - [__NR_fchdir] = {"fchdir", (void *)nullptr}, - [__NR_rename] = {"rename", (void *)nullptr}, - [__NR_mkdir] = {"mkdir", (void *)nullptr}, - [__NR_rmdir] = {"rmdir", (void *)nullptr}, - [__NR_creat] = {"creat", (void *)linux_creat}, - [__NR_link] = {"link", (void *)nullptr}, - [__NR_unlink] = {"unlink", (void *)nullptr}, - [__NR_symlink] = {"symlink", (void *)nullptr}, - [__NR_readlink] = {"readlink", (void *)nullptr}, - [__NR_chmod] = {"chmod", (void *)nullptr}, - [__NR_fchmod] = {"fchmod", (void *)nullptr}, - [__NR_chown] = {"chown", (void *)nullptr}, - [__NR_fchown] = {"fchown", (void *)nullptr}, - [__NR_lchown] = {"lchown", (void *)nullptr}, - [__NR_umask] = {"umask", (void *)nullptr}, - [__NR_gettimeofday] = {"gettimeofday", (void *)nullptr}, - [__NR_getrlimit] = {"getrlimit", (void *)nullptr}, - [__NR_getrusage] = {"getrusage", (void *)nullptr}, - [__NR_sysinfo] = {"sysinfo", (void *)nullptr}, - [__NR_times] = {"times", (void *)nullptr}, - [__NR_ptrace] = {"ptrace", (void *)nullptr}, - [__NR_getuid] = {"getuid", (void *)nullptr}, - [__NR_syslog] = {"syslog", (void *)nullptr}, - [__NR_getgid] = {"getgid", (void *)nullptr}, - [__NR_setuid] = {"setuid", (void *)nullptr}, - [__NR_setgid] = {"setgid", (void *)nullptr}, - [__NR_geteuid] = {"geteuid", (void *)nullptr}, - [__NR_getegid] = {"getegid", (void *)nullptr}, - [__NR_setpgid] = {"setpgid", (void *)nullptr}, - [__NR_getppid] = {"getppid", (void *)nullptr}, - [__NR_getpgrp] = {"getpgrp", (void *)nullptr}, - [__NR_setsid] = {"setsid", (void *)nullptr}, - [__NR_setreuid] = {"setreuid", (void *)nullptr}, - [__NR_setregid] = {"setregid", (void *)nullptr}, - [__NR_getgroups] = {"getgroups", (void *)nullptr}, - [__NR_setgroups] = {"setgroups", (void *)nullptr}, - [__NR_setresuid] = {"setresuid", (void *)nullptr}, - [__NR_getresuid] = {"getresuid", (void *)nullptr}, - [__NR_setresgid] = {"setresgid", (void *)nullptr}, - [__NR_getresgid] = {"getresgid", (void *)nullptr}, - [__NR_getpgid] = {"getpgid", (void *)nullptr}, - [__NR_setfsuid] = {"setfsuid", (void *)nullptr}, - [__NR_setfsgid] = {"setfsgid", (void *)nullptr}, - [__NR_getsid] = {"getsid", (void *)nullptr}, - [__NR_capget] = {"capget", (void *)nullptr}, - [__NR_capset] = {"capset", (void *)nullptr}, - [__NR_rt_sigpending] = {"rt_sigpending", (void *)nullptr}, - [__NR_rt_sigtimedwait] = {"rt_sigtimedwait", (void *)nullptr}, - [__NR_rt_sigqueueinfo] = {"rt_sigqueueinfo", (void *)nullptr}, - [__NR_rt_sigsuspend] = {"rt_sigsuspend", (void *)nullptr}, - [__NR_sigaltstack] = {"sigaltstack", (void *)nullptr}, - [__NR_utime] = {"utime", (void *)nullptr}, - [__NR_mknod] = {"mknod", (void *)nullptr}, - [__NR_uselib] = {"uselib", (void *)nullptr}, - [__NR_personality] = {"personality", (void *)nullptr}, - [__NR_ustat] = {"ustat", (void *)nullptr}, - [__NR_statfs] = {"statfs", (void *)nullptr}, - [__NR_fstatfs] = {"fstatfs", (void *)nullptr}, - [__NR_sysfs] = {"sysfs", (void *)nullptr}, - [__NR_getpriority] = {"getpriority", (void *)nullptr}, - [__NR_setpriority] = {"setpriority", (void *)nullptr}, - [__NR_sched_setparam] = {"sched_setparam", (void *)nullptr}, - [__NR_sched_getparam] = {"sched_getparam", (void *)nullptr}, - [__NR_sched_setscheduler] = {"sched_setscheduler", (void *)nullptr}, - [__NR_sched_getscheduler] = {"sched_getscheduler", (void *)nullptr}, - [__NR_sched_get_priority_max] = {"sched_get_priority_max", (void *)nullptr}, - [__NR_sched_get_priority_min] = {"sched_get_priority_min", (void *)nullptr}, - [__NR_sched_rr_get_interval] = {"sched_rr_get_interval", (void *)nullptr}, - [__NR_mlock] = {"mlock", (void *)nullptr}, - [__NR_munlock] = {"munlock", (void *)nullptr}, - [__NR_mlockall] = {"mlockall", (void *)nullptr}, - [__NR_munlockall] = {"munlockall", (void *)nullptr}, - [__NR_vhangup] = {"vhangup", (void *)nullptr}, - [__NR_modify_ldt] = {"modify_ldt", (void *)nullptr}, - [__NR_pivot_root] = {"pivot_root", (void *)nullptr}, - [__NR__sysctl] = {"_sysctl", (void *)nullptr}, - [__NR_prctl] = {"prctl", (void *)nullptr}, - [__NR_arch_prctl] = {"arch_prctl", (void *)linux_arch_prctl}, - [__NR_adjtimex] = {"adjtimex", (void *)nullptr}, - [__NR_setrlimit] = {"setrlimit", (void *)nullptr}, - [__NR_chroot] = {"chroot", (void *)nullptr}, - [__NR_sync] = {"sync", (void *)nullptr}, - [__NR_acct] = {"acct", (void *)nullptr}, - [__NR_settimeofday] = {"settimeofday", (void *)nullptr}, - [__NR_mount] = {"mount", (void *)nullptr}, - [__NR_umount2] = {"umount2", (void *)nullptr}, - [__NR_swapon] = {"swapon", (void *)nullptr}, - [__NR_swapoff] = {"swapoff", (void *)nullptr}, - [__NR_reboot] = {"reboot", (void *)nullptr}, - [__NR_sethostname] = {"sethostname", (void *)nullptr}, - [__NR_setdomainname] = {"setdomainname", (void *)nullptr}, - [__NR_iopl] = {"iopl", (void *)nullptr}, - [__NR_ioperm] = {"ioperm", (void *)nullptr}, - [__NR_create_module] = {"create_module", (void *)nullptr}, - [__NR_init_module] = {"init_module", (void *)nullptr}, - [__NR_delete_module] = {"delete_module", (void *)nullptr}, - [__NR_get_kernel_syms] = {"get_kernel_syms", (void *)nullptr}, - [__NR_query_module] = {"query_module", (void *)nullptr}, - [__NR_quotactl] = {"quotactl", (void *)nullptr}, - [__NR_nfsservctl] = {"nfsservctl", (void *)nullptr}, - [__NR_getpmsg] = {"getpmsg", (void *)nullptr}, - [__NR_putpmsg] = {"putpmsg", (void *)nullptr}, - [__NR_afs_syscall] = {"afs_syscall", (void *)nullptr}, - [__NR_tuxcall] = {"tuxcall", (void *)nullptr}, - [__NR_security] = {"security", (void *)nullptr}, - [__NR_gettid] = {"gettid", (void *)linux_gettid}, - [__NR_readahead] = {"readahead", (void *)nullptr}, - [__NR_setxattr] = {"setxattr", (void *)nullptr}, - [__NR_lsetxattr] = {"lsetxattr", (void *)nullptr}, - [__NR_fsetxattr] = {"fsetxattr", (void *)nullptr}, - [__NR_getxattr] = {"getxattr", (void *)nullptr}, - [__NR_lgetxattr] = {"lgetxattr", (void *)nullptr}, - [__NR_fgetxattr] = {"fgetxattr", (void *)nullptr}, - [__NR_listxattr] = {"listxattr", (void *)nullptr}, - [__NR_llistxattr] = {"llistxattr", (void *)nullptr}, - [__NR_flistxattr] = {"flistxattr", (void *)nullptr}, - [__NR_removexattr] = {"removexattr", (void *)nullptr}, - [__NR_lremovexattr] = {"lremovexattr", (void *)nullptr}, - [__NR_fremovexattr] = {"fremovexattr", (void *)nullptr}, - [__NR_tkill] = {"tkill", (void *)nullptr}, - [__NR_time] = {"time", (void *)nullptr}, - [__NR_futex] = {"futex", (void *)nullptr}, - [__NR_sched_setaffinity] = {"sched_setaffinity", (void *)nullptr}, - [__NR_sched_getaffinity] = {"sched_getaffinity", (void *)nullptr}, - [__NR_set_thread_area] = {"set_thread_area", (void *)nullptr}, - [__NR_io_setup] = {"io_setup", (void *)nullptr}, - [__NR_io_destroy] = {"io_destroy", (void *)nullptr}, - [__NR_io_getevents] = {"io_getevents", (void *)nullptr}, - [__NR_io_submit] = {"io_submit", (void *)nullptr}, - [__NR_io_cancel] = {"io_cancel", (void *)nullptr}, - [__NR_get_thread_area] = {"get_thread_area", (void *)nullptr}, - [__NR_lookup_dcookie] = {"lookup_dcookie", (void *)nullptr}, - [__NR_epoll_create] = {"epoll_create", (void *)nullptr}, - [__NR_epoll_ctl_old] = {"epoll_ctl_old", (void *)nullptr}, - [__NR_epoll_wait_old] = {"epoll_wait_old", (void *)nullptr}, - [__NR_remap_file_pages] = {"remap_file_pages", (void *)nullptr}, - [__NR_getdents64] = {"getdents64", (void *)nullptr}, - [__NR_set_tid_address] = {"set_tid_address", (void *)linux_set_tid_address}, - [__NR_restart_syscall] = {"restart_syscall", (void *)nullptr}, - [__NR_semtimedop] = {"semtimedop", (void *)nullptr}, - [__NR_fadvise64] = {"fadvise64", (void *)nullptr}, - [__NR_timer_create] = {"timer_create", (void *)nullptr}, - [__NR_timer_settime] = {"timer_settime", (void *)nullptr}, - [__NR_timer_gettime] = {"timer_gettime", (void *)nullptr}, - [__NR_timer_getoverrun] = {"timer_getoverrun", (void *)nullptr}, - [__NR_timer_delete] = {"timer_delete", (void *)nullptr}, - [__NR_clock_settime] = {"clock_settime", (void *)nullptr}, - [__NR_clock_gettime] = {"clock_gettime", (void *)nullptr}, - [__NR_clock_getres] = {"clock_getres", (void *)nullptr}, - [__NR_clock_nanosleep] = {"clock_nanosleep", (void *)nullptr}, - [__NR_exit_group] = {"exit_group", (void *)linux_exit_group}, - [__NR_epoll_wait] = {"epoll_wait", (void *)nullptr}, - [__NR_epoll_ctl] = {"epoll_ctl", (void *)nullptr}, - [__NR_tgkill] = {"tgkill", (void *)nullptr}, - [__NR_utimes] = {"utimes", (void *)nullptr}, - [__NR_vserver] = {"vserver", (void *)nullptr}, - [__NR_mbind] = {"mbind", (void *)nullptr}, - [__NR_set_mempolicy] = {"set_mempolicy", (void *)nullptr}, - [__NR_get_mempolicy] = {"get_mempolicy", (void *)nullptr}, - [__NR_mq_open] = {"mq_open", (void *)nullptr}, - [__NR_mq_unlink] = {"mq_unlink", (void *)nullptr}, - [__NR_mq_timedsend] = {"mq_timedsend", (void *)nullptr}, - [__NR_mq_timedreceive] = {"mq_timedreceive", (void *)nullptr}, - [__NR_mq_notify] = {"mq_notify", (void *)nullptr}, - [__NR_mq_getsetattr] = {"mq_getsetattr", (void *)nullptr}, - [__NR_kexec_load] = {"kexec_load", (void *)nullptr}, - [__NR_waitid] = {"waitid", (void *)nullptr}, - [__NR_add_key] = {"add_key", (void *)nullptr}, - [__NR_request_key] = {"request_key", (void *)nullptr}, - [__NR_keyctl] = {"keyctl", (void *)nullptr}, - [__NR_ioprio_set] = {"ioprio_set", (void *)nullptr}, - [__NR_ioprio_get] = {"ioprio_get", (void *)nullptr}, - [__NR_inotify_init] = {"inotify_init", (void *)nullptr}, - [__NR_inotify_add_watch] = {"inotify_add_watch", (void *)nullptr}, - [__NR_inotify_rm_watch] = {"inotify_rm_watch", (void *)nullptr}, - [__NR_migrate_pages] = {"migrate_pages", (void *)nullptr}, - [__NR_openat] = {"openat", (void *)nullptr}, - [__NR_mkdirat] = {"mkdirat", (void *)nullptr}, - [__NR_mknodat] = {"mknodat", (void *)nullptr}, - [__NR_fchownat] = {"fchownat", (void *)nullptr}, - [__NR_futimesat] = {"futimesat", (void *)nullptr}, - [__NR_newfstatat] = {"newfstatat", (void *)nullptr}, - [__NR_unlinkat] = {"unlinkat", (void *)nullptr}, - [__NR_renameat] = {"renameat", (void *)nullptr}, - [__NR_linkat] = {"linkat", (void *)nullptr}, - [__NR_symlinkat] = {"symlinkat", (void *)nullptr}, - [__NR_readlinkat] = {"readlinkat", (void *)nullptr}, - [__NR_fchmodat] = {"fchmodat", (void *)nullptr}, - [__NR_faccessat] = {"faccessat", (void *)nullptr}, - [__NR_pselect6] = {"pselect6", (void *)nullptr}, - [__NR_ppoll] = {"ppoll", (void *)nullptr}, - [__NR_unshare] = {"unshare", (void *)nullptr}, - [__NR_set_robust_list] = {"set_robust_list", (void *)nullptr}, - [__NR_get_robust_list] = {"get_robust_list", (void *)nullptr}, - [__NR_splice] = {"splice", (void *)nullptr}, - [__NR_tee] = {"tee", (void *)nullptr}, - [__NR_sync_file_range] = {"sync_file_range", (void *)nullptr}, - [__NR_vmsplice] = {"vmsplice", (void *)nullptr}, - [__NR_move_pages] = {"move_pages", (void *)nullptr}, - [__NR_utimensat] = {"utimensat", (void *)nullptr}, - [__NR_epoll_pwait] = {"epoll_pwait", (void *)nullptr}, - [__NR_signalfd] = {"signalfd", (void *)nullptr}, - [__NR_timerfd_create] = {"timerfd_create", (void *)nullptr}, - [__NR_eventfd] = {"eventfd", (void *)nullptr}, - [__NR_fallocate] = {"fallocate", (void *)nullptr}, - [__NR_timerfd_settime] = {"timerfd_settime", (void *)nullptr}, - [__NR_timerfd_gettime] = {"timerfd_gettime", (void *)nullptr}, - [__NR_accept4] = {"accept4", (void *)nullptr}, - [__NR_signalfd4] = {"signalfd4", (void *)nullptr}, - [__NR_eventfd2] = {"eventfd2", (void *)nullptr}, - [__NR_epoll_create1] = {"epoll_create1", (void *)nullptr}, - [__NR_dup3] = {"dup3", (void *)nullptr}, - [__NR_pipe2] = {"pipe2", (void *)nullptr}, - [__NR_inotify_init1] = {"inotify_init1", (void *)nullptr}, - [__NR_preadv] = {"preadv", (void *)nullptr}, - [__NR_pwritev] = {"pwritev", (void *)nullptr}, - [__NR_rt_tgsigqueueinfo] = {"rt_tgsigqueueinfo", (void *)nullptr}, - [__NR_perf_event_open] = {"perf_event_open", (void *)nullptr}, - [__NR_recvmmsg] = {"recvmmsg", (void *)nullptr}, - [__NR_fanotify_init] = {"fanotify_init", (void *)nullptr}, - [__NR_fanotify_mark] = {"fanotify_mark", (void *)nullptr}, - [__NR_prlimit64] = {"prlimit64", (void *)nullptr}, - [__NR_name_to_handle_at] = {"name_to_handle_at", (void *)nullptr}, - [__NR_open_by_handle_at] = {"open_by_handle_at", (void *)nullptr}, - [__NR_clock_adjtime] = {"clock_adjtime", (void *)nullptr}, - [__NR_syncfs] = {"syncfs", (void *)nullptr}, - [__NR_sendmmsg] = {"sendmmsg", (void *)nullptr}, - [__NR_setns] = {"setns", (void *)nullptr}, - [__NR_getcpu] = {"getcpu", (void *)nullptr}, - [__NR_process_vm_readv] = {"process_vm_readv", (void *)nullptr}, - [__NR_process_vm_writev] = {"process_vm_writev", (void *)nullptr}, - [__NR_kcmp] = {"kcmp", (void *)nullptr}, - [__NR_finit_module] = {"finit_module", (void *)nullptr}, - [__NR_sched_setattr] = {"sched_setattr", (void *)nullptr}, - [__NR_sched_getattr] = {"sched_getattr", (void *)nullptr}, - [__NR_renameat2] = {"renameat2", (void *)nullptr}, - [__NR_seccomp] = {"seccomp", (void *)nullptr}, - [__NR_getrandom] = {"getrandom", (void *)nullptr}, - [__NR_memfd_create] = {"memfd_create", (void *)nullptr}, - [__NR_kexec_file_load] = {"kexec_file_load", (void *)nullptr}, - [__NR_bpf] = {"bpf", (void *)nullptr}, - [__NR_execveat] = {"execveat", (void *)nullptr}, - [__NR_userfaultfd] = {"userfaultfd", (void *)nullptr}, - [__NR_membarrier] = {"membarrier", (void *)nullptr}, - [__NR_mlock2] = {"mlock2", (void *)nullptr}, - [__NR_copy_file_range] = {"copy_file_range", (void *)nullptr}, - [__NR_preadv2] = {"preadv2", (void *)nullptr}, - [__NR_pwritev2] = {"pwritev2", (void *)nullptr}, - [__NR_pkey_mprotect] = {"pkey_mprotect", (void *)nullptr}, - [__NR_pkey_alloc] = {"pkey_alloc", (void *)nullptr}, - [__NR_pkey_free] = {"pkey_free", (void *)nullptr}, - [__NR_statx] = {"statx", (void *)nullptr}, - [__NR_io_pgetevents] = {"io_pgetevents", (void *)nullptr}, - [__NR_rseq] = {"rseq", (void *)nullptr}, +/* https://man7.org/linux/man-pages/man3/clock_gettime.3.html */ +static int linux_clock_gettime(SysFrm *, clockid_t clockid, struct timespec *tp) +{ + static_assert(sizeof(struct timespec) < PAGE_SIZE); + + PCB *pcb = thisProcess; + Memory::Virtual vmm(pcb->PageTable); + + if (!vmm.Check(tp, Memory::US)) + { + debug("Invalid address %#lx", tp); + return -EFAULT; + } + + timespec *pTp = pcb->PageTable->Get(tp); + + /* FIXME: This is not correct? */ + switch (clockid) + { + case CLOCK_REALTIME: + { + uint64_t time = TimeManager->GetCounter(); + pTp->tv_sec = time / Time::ConvertUnit(Time::Seconds); + pTp->tv_nsec = time / Time::ConvertUnit(Time::Nanoseconds); + debug("time=%ld sec=%ld nsec=%ld", + time, pTp->tv_sec, pTp->tv_nsec); + break; + } + case CLOCK_MONOTONIC: + { + uint64_t time = TimeManager->GetCounter(); + pTp->tv_sec = time / Time::ConvertUnit(Time::Seconds); + pTp->tv_nsec = time / Time::ConvertUnit(Time::Nanoseconds); + debug("time=%ld sec=%ld nsec=%ld", + time, pTp->tv_sec, pTp->tv_nsec); + break; + } + case CLOCK_PROCESS_CPUTIME_ID: + case CLOCK_THREAD_CPUTIME_ID: + case CLOCK_MONOTONIC_RAW: + case CLOCK_REALTIME_COARSE: + case CLOCK_MONOTONIC_COARSE: + case CLOCK_BOOTTIME: + case CLOCK_REALTIME_ALARM: + case CLOCK_BOOTTIME_ALARM: + case CLOCK_SGI_CYCLE: + case CLOCK_TAI: + { + fixme("clockid %d is stub", clockid); + return -ENOSYS; + } + default: + { + warn("Invalid clockid %#lx", clockid); + return -EINVAL; + } + } + return 0; +} + +/* https://man7.org/linux/man-pages/man2/exit_group.2.html */ +static __noreturn void linux_exit_group(SysFrm *sf, int status) +{ + fixme("status=%d", status); + linux_exit(sf, status); +} + +/* https://man7.org/linux/man-pages/man2/tgkill.2.html */ +static int linux_tgkill(SysFrm *sf, pid_t tgid, pid_t tid, int sig) +{ + Tasking::TCB *target = thisProcess->GetContext()->GetThreadByID(tid); + if (!target) + return -ESRCH; + + fixme("semi-stub: %d %d %d", tgid, tid, sig); + return target->Parent->Signals->SendSignal(sig); +} + +/* Undocumented? */ +static long linux_newfstatat(SysFrm *, int dfd, const char *filename, + struct stat *statbuf, int flag) +{ + /* FIXME: This function is not working at all? */ + + PCB *pcb = thisProcess; + vfs::FileDescriptorTable *fdt = pcb->FileDescriptors; + Memory::Virtual vmm(pcb->PageTable); + + if (flag) + fixme("flag %#x is stub", flag); + + if (!filename) + { + debug("Invalid filename %#lx", filename); + return -EFAULT; + } + + if (!statbuf) + { + debug("Invalid statbuf %#lx", statbuf); + return -EFAULT; + } + + if (dfd == AT_FDCWD) + { + fixme("dfd AT_FDCWD is stub"); + return -ENOSYS; + } + + vfs::FileDescriptorTable::Fildes & + fildes = fdt->GetDescriptor(dfd); + if (!fildes.Handle) + { + debug("Invalid fd %d", dfd); + return -EBADF; + } + + const char *pFilename = pcb->PageTable->Get(filename); + struct stat *pStatbuf = pcb->PageTable->Get(statbuf); + + debug("%s %#lx %#lx", pFilename, filename, statbuf); + return fdt->_stat(pFilename, pStatbuf); +} + +/* https://man7.org/linux/man-pages/man2/pipe2.2.html */ +static int linux_pipe2(SysFrm *sf, int pipefd[2], int flags) +{ + if (flags == 0) + return linux_pipe(sf, pipefd); + + PCB *pcb = thisProcess; + int *pPipefd = pcb->PageTable->Get(pipefd); + debug("pipefd=%#lx", pPipefd); + fixme("pipefd=[%d, %d] flags=%#x", pPipefd[0], pPipefd[1], flags); + return -ENOSYS; +} + +/* https://man7.org/linux/man-pages/man2/getrlimit.2.html */ +static int linux_prlimit64(SysFrm *, pid_t pid, int resource, + const struct rlimit *new_limit, + struct rlimit *old_limit) +{ + static_assert(sizeof(struct rlimit) < PAGE_SIZE); + + PCB *pcb = thisProcess; + Memory::Virtual vmm(pcb->PageTable); + + if (old_limit && !vmm.Check(old_limit, Memory::US)) + { + debug("Invalid address %#lx", old_limit); + return -EFAULT; + } + + if (new_limit && !vmm.Check((void *)new_limit, Memory::US)) + { + debug("Invalid address %#lx", new_limit); + return -EFAULT; + } + + auto pOldLimit = pcb->PageTable->Get(old_limit); + auto pNewLimit = pcb->PageTable->Get(new_limit); + + UNUSED(pOldLimit); + UNUSED(pNewLimit); + + switch (resource) + { + case RLIMIT_CPU: + case RLIMIT_FSIZE: + case RLIMIT_DATA: + case RLIMIT_STACK: + case RLIMIT_CORE: + case RLIMIT_RSS: + case RLIMIT_NPROC: + case RLIMIT_NOFILE: + case RLIMIT_MEMLOCK: + case RLIMIT_AS: + case RLIMIT_LOCKS: + case RLIMIT_SIGPENDING: + case RLIMIT_MSGQUEUE: + case RLIMIT_NICE: + case RLIMIT_RTPRIO: + case RLIMIT_RTTIME: + case RLIMIT_NLIMITS: + { + fixme("resource %d is stub", resource); + return -ENOSYS; + } + default: + { + debug("Invalid resource %d", resource); + return -EINVAL; + } + } + + return 0; +} + +/* https://man7.org/linux/man-pages/man2/getrandom.2.html */ +static ssize_t linux_getrandom(SysFrm *, void *buf, + size_t buflen, unsigned int flags) +{ + PCB *pcb = thisProcess; + Memory::Virtual vmm(pcb->PageTable); + + if (!vmm.Check(buf, Memory::US)) + { + debug("Invalid address %#lx", buf); + return -EFAULT; + } + + if (flags & GRND_NONBLOCK) + fixme("GRND_NONBLOCK not implemented"); + + if (flags & ~(GRND_NONBLOCK | + GRND_RANDOM | + GRND_INSECURE)) + { + warn("Invalid flags %#x", flags); + return -EINVAL; + } + + if (flags & GRND_RANDOM) + { + uint16_t random; + for (size_t i = 0; i < buflen; i++) + { + random = Random::rand16(); + { + Memory::SwapPT swap(pcb->PageTable); + ((uint8_t *)buf)[i] = uint8_t(random & 0xFF); + } + } + return buflen; + } + + return 0; +} + +static SyscallData LinuxSyscallsTableAMD64[] = { + [__NR_amd64_read] = {"read", (void *)linux_read}, + [__NR_amd64_write] = {"write", (void *)linux_write}, + [__NR_amd64_open] = {"open", (void *)linux_open}, + [__NR_amd64_close] = {"close", (void *)linux_close}, + [__NR_amd64_stat] = {"stat", (void *)linux_stat}, + [__NR_amd64_fstat] = {"fstat", (void *)linux_fstat}, + [__NR_amd64_lstat] = {"lstat", (void *)linux_lstat}, + [__NR_amd64_poll] = {"poll", (void *)nullptr}, + [__NR_amd64_lseek] = {"lseek", (void *)linux_lseek}, + [__NR_amd64_mmap] = {"mmap", (void *)linux_mmap}, + [__NR_amd64_mprotect] = {"mprotect", (void *)linux_mprotect}, + [__NR_amd64_munmap] = {"munmap", (void *)linux_munmap}, + [__NR_amd64_brk] = {"brk", (void *)linux_brk}, + [__NR_amd64_rt_sigaction] = {"rt_sigaction", (void *)linux_sigaction}, + [__NR_amd64_rt_sigprocmask] = {"rt_sigprocmask", (void *)linux_sigprocmask}, + [__NR_amd64_rt_sigreturn] = {"rt_sigreturn", (void *)linux_sigreturn}, + [__NR_amd64_ioctl] = {"ioctl", (void *)linux_ioctl}, + [__NR_amd64_pread64] = {"pread64", (void *)nullptr}, + [__NR_amd64_pwrite64] = {"pwrite64", (void *)nullptr}, + [__NR_amd64_readv] = {"readv", (void *)linux_readv}, + [__NR_amd64_writev] = {"writev", (void *)linux_writev}, + [__NR_amd64_access] = {"access", (void *)nullptr}, + [__NR_amd64_pipe] = {"pipe", (void *)linux_pipe}, + [__NR_amd64_select] = {"select", (void *)nullptr}, + [__NR_amd64_sched_yield] = {"sched_yield", (void *)nullptr}, + [__NR_amd64_mremap] = {"mremap", (void *)nullptr}, + [__NR_amd64_msync] = {"msync", (void *)nullptr}, + [__NR_amd64_mincore] = {"mincore", (void *)nullptr}, + [__NR_amd64_madvise] = {"madvise", (void *)nullptr}, + [__NR_amd64_shmget] = {"shmget", (void *)nullptr}, + [__NR_amd64_shmat] = {"shmat", (void *)nullptr}, + [__NR_amd64_shmctl] = {"shmctl", (void *)nullptr}, + [__NR_amd64_dup] = {"dup", (void *)linux_dup}, + [__NR_amd64_dup2] = {"dup2", (void *)linux_dup2}, + [__NR_amd64_pause] = {"pause", (void *)linux_pause}, + [__NR_amd64_nanosleep] = {"nanosleep", (void *)linux_nanosleep}, + [__NR_amd64_getitimer] = {"getitimer", (void *)nullptr}, + [__NR_amd64_alarm] = {"alarm", (void *)nullptr}, + [__NR_amd64_setitimer] = {"setitimer", (void *)nullptr}, + [__NR_amd64_getpid] = {"getpid", (void *)linux_getpid}, + [__NR_amd64_sendfile] = {"sendfile", (void *)nullptr}, + [__NR_amd64_socket] = {"socket", (void *)nullptr}, + [__NR_amd64_connect] = {"connect", (void *)nullptr}, + [__NR_amd64_accept] = {"accept", (void *)nullptr}, + [__NR_amd64_sendto] = {"sendto", (void *)nullptr}, + [__NR_amd64_recvfrom] = {"recvfrom", (void *)nullptr}, + [__NR_amd64_sendmsg] = {"sendmsg", (void *)nullptr}, + [__NR_amd64_recvmsg] = {"recvmsg", (void *)nullptr}, + [__NR_amd64_shutdown] = {"shutdown", (void *)linux_shutdown}, + [__NR_amd64_bind] = {"bind", (void *)nullptr}, + [__NR_amd64_listen] = {"listen", (void *)nullptr}, + [__NR_amd64_getsockname] = {"getsockname", (void *)nullptr}, + [__NR_amd64_getpeername] = {"getpeername", (void *)nullptr}, + [__NR_amd64_socketpair] = {"socketpair", (void *)nullptr}, + [__NR_amd64_setsockopt] = {"setsockopt", (void *)nullptr}, + [__NR_amd64_getsockopt] = {"getsockopt", (void *)nullptr}, + [__NR_amd64_clone] = {"clone", (void *)nullptr}, + [__NR_amd64_fork] = {"fork", (void *)linux_fork}, + [__NR_amd64_vfork] = {"vfork", (void *)nullptr}, + [__NR_amd64_execve] = {"execve", (void *)linux_execve}, + [__NR_amd64_exit] = {"exit", (void *)linux_exit}, + [__NR_amd64_wait4] = {"wait4", (void *)linux_wait4}, + [__NR_amd64_kill] = {"kill", (void *)linux_kill}, + [__NR_amd64_uname] = {"uname", (void *)linux_uname}, + [__NR_amd64_semget] = {"semget", (void *)nullptr}, + [__NR_amd64_semop] = {"semop", (void *)nullptr}, + [__NR_amd64_semctl] = {"semctl", (void *)nullptr}, + [__NR_amd64_shmdt] = {"shmdt", (void *)nullptr}, + [__NR_amd64_msgget] = {"msgget", (void *)nullptr}, + [__NR_amd64_msgsnd] = {"msgsnd", (void *)nullptr}, + [__NR_amd64_msgrcv] = {"msgrcv", (void *)nullptr}, + [__NR_amd64_msgctl] = {"msgctl", (void *)nullptr}, + [__NR_amd64_fcntl] = {"fcntl", (void *)linux_fcntl}, + [__NR_amd64_flock] = {"flock", (void *)nullptr}, + [__NR_amd64_fsync] = {"fsync", (void *)nullptr}, + [__NR_amd64_fdatasync] = {"fdatasync", (void *)nullptr}, + [__NR_amd64_truncate] = {"truncate", (void *)nullptr}, + [__NR_amd64_ftruncate] = {"ftruncate", (void *)nullptr}, + [__NR_amd64_getdents] = {"getdents", (void *)nullptr}, + [__NR_amd64_getcwd] = {"getcwd", (void *)nullptr}, + [__NR_amd64_chdir] = {"chdir", (void *)nullptr}, + [__NR_amd64_fchdir] = {"fchdir", (void *)nullptr}, + [__NR_amd64_rename] = {"rename", (void *)nullptr}, + [__NR_amd64_mkdir] = {"mkdir", (void *)linux_mkdir}, + [__NR_amd64_rmdir] = {"rmdir", (void *)nullptr}, + [__NR_amd64_creat] = {"creat", (void *)linux_creat}, + [__NR_amd64_link] = {"link", (void *)nullptr}, + [__NR_amd64_unlink] = {"unlink", (void *)nullptr}, + [__NR_amd64_symlink] = {"symlink", (void *)nullptr}, + [__NR_amd64_readlink] = {"readlink", (void *)linux_readlink}, + [__NR_amd64_chmod] = {"chmod", (void *)nullptr}, + [__NR_amd64_fchmod] = {"fchmod", (void *)nullptr}, + [__NR_amd64_chown] = {"chown", (void *)nullptr}, + [__NR_amd64_fchown] = {"fchown", (void *)nullptr}, + [__NR_amd64_lchown] = {"lchown", (void *)nullptr}, + [__NR_amd64_umask] = {"umask", (void *)nullptr}, + [__NR_amd64_gettimeofday] = {"gettimeofday", (void *)nullptr}, + [__NR_amd64_getrlimit] = {"getrlimit", (void *)nullptr}, + [__NR_amd64_getrusage] = {"getrusage", (void *)nullptr}, + [__NR_amd64_sysinfo] = {"sysinfo", (void *)nullptr}, + [__NR_amd64_times] = {"times", (void *)nullptr}, + [__NR_amd64_ptrace] = {"ptrace", (void *)nullptr}, + [__NR_amd64_getuid] = {"getuid", (void *)linux_getuid}, + [__NR_amd64_syslog] = {"syslog", (void *)nullptr}, + [__NR_amd64_getgid] = {"getgid", (void *)nullptr}, + [__NR_amd64_setuid] = {"setuid", (void *)nullptr}, + [__NR_amd64_setgid] = {"setgid", (void *)nullptr}, + [__NR_amd64_geteuid] = {"geteuid", (void *)nullptr}, + [__NR_amd64_getegid] = {"getegid", (void *)nullptr}, + [__NR_amd64_setpgid] = {"setpgid", (void *)nullptr}, + [__NR_amd64_getppid] = {"getppid", (void *)linux_getppid}, + [__NR_amd64_getpgrp] = {"getpgrp", (void *)nullptr}, + [__NR_amd64_setsid] = {"setsid", (void *)nullptr}, + [__NR_amd64_setreuid] = {"setreuid", (void *)nullptr}, + [__NR_amd64_setregid] = {"setregid", (void *)nullptr}, + [__NR_amd64_getgroups] = {"getgroups", (void *)nullptr}, + [__NR_amd64_setgroups] = {"setgroups", (void *)nullptr}, + [__NR_amd64_setresuid] = {"setresuid", (void *)nullptr}, + [__NR_amd64_getresuid] = {"getresuid", (void *)nullptr}, + [__NR_amd64_setresgid] = {"setresgid", (void *)nullptr}, + [__NR_amd64_getresgid] = {"getresgid", (void *)nullptr}, + [__NR_amd64_getpgid] = {"getpgid", (void *)nullptr}, + [__NR_amd64_setfsuid] = {"setfsuid", (void *)nullptr}, + [__NR_amd64_setfsgid] = {"setfsgid", (void *)nullptr}, + [__NR_amd64_getsid] = {"getsid", (void *)nullptr}, + [__NR_amd64_capget] = {"capget", (void *)nullptr}, + [__NR_amd64_capset] = {"capset", (void *)nullptr}, + [__NR_amd64_rt_sigpending] = {"rt_sigpending", (void *)nullptr}, + [__NR_amd64_rt_sigtimedwait] = {"rt_sigtimedwait", (void *)nullptr}, + [__NR_amd64_rt_sigqueueinfo] = {"rt_sigqueueinfo", (void *)nullptr}, + [__NR_amd64_rt_sigsuspend] = {"rt_sigsuspend", (void *)nullptr}, + [__NR_amd64_sigaltstack] = {"sigaltstack", (void *)nullptr}, + [__NR_amd64_utime] = {"utime", (void *)nullptr}, + [__NR_amd64_mknod] = {"mknod", (void *)nullptr}, + [__NR_amd64_uselib] = {"uselib", (void *)nullptr}, + [__NR_amd64_personality] = {"personality", (void *)nullptr}, + [__NR_amd64_ustat] = {"ustat", (void *)nullptr}, + [__NR_amd64_statfs] = {"statfs", (void *)nullptr}, + [__NR_amd64_fstatfs] = {"fstatfs", (void *)nullptr}, + [__NR_amd64_sysfs] = {"sysfs", (void *)nullptr}, + [__NR_amd64_getpriority] = {"getpriority", (void *)nullptr}, + [__NR_amd64_setpriority] = {"setpriority", (void *)nullptr}, + [__NR_amd64_sched_setparam] = {"sched_setparam", (void *)nullptr}, + [__NR_amd64_sched_getparam] = {"sched_getparam", (void *)nullptr}, + [__NR_amd64_sched_setscheduler] = {"sched_setscheduler", (void *)nullptr}, + [__NR_amd64_sched_getscheduler] = {"sched_getscheduler", (void *)nullptr}, + [__NR_amd64_sched_get_priority_max] = {"sched_get_priority_max", (void *)nullptr}, + [__NR_amd64_sched_get_priority_min] = {"sched_get_priority_min", (void *)nullptr}, + [__NR_amd64_sched_rr_get_interval] = {"sched_rr_get_interval", (void *)nullptr}, + [__NR_amd64_mlock] = {"mlock", (void *)nullptr}, + [__NR_amd64_munlock] = {"munlock", (void *)nullptr}, + [__NR_amd64_mlockall] = {"mlockall", (void *)nullptr}, + [__NR_amd64_munlockall] = {"munlockall", (void *)nullptr}, + [__NR_amd64_vhangup] = {"vhangup", (void *)nullptr}, + [__NR_amd64_modify_ldt] = {"modify_ldt", (void *)nullptr}, + [__NR_amd64_pivot_root] = {"pivot_root", (void *)nullptr}, + [__NR_amd64__sysctl] = {"_sysctl", (void *)nullptr}, + [__NR_amd64_prctl] = {"prctl", (void *)nullptr}, + [__NR_amd64_arch_prctl] = {"arch_prctl", (void *)linux_arch_prctl}, + [__NR_amd64_adjtimex] = {"adjtimex", (void *)nullptr}, + [__NR_amd64_setrlimit] = {"setrlimit", (void *)nullptr}, + [__NR_amd64_chroot] = {"chroot", (void *)nullptr}, + [__NR_amd64_sync] = {"sync", (void *)nullptr}, + [__NR_amd64_acct] = {"acct", (void *)nullptr}, + [__NR_amd64_settimeofday] = {"settimeofday", (void *)nullptr}, + [__NR_amd64_mount] = {"mount", (void *)nullptr}, + [__NR_amd64_umount2] = {"umount2", (void *)nullptr}, + [__NR_amd64_swapon] = {"swapon", (void *)nullptr}, + [__NR_amd64_swapoff] = {"swapoff", (void *)nullptr}, + [__NR_amd64_reboot] = {"reboot", (void *)linux_reboot}, + [__NR_amd64_sethostname] = {"sethostname", (void *)nullptr}, + [__NR_amd64_setdomainname] = {"setdomainname", (void *)nullptr}, + [__NR_amd64_iopl] = {"iopl", (void *)nullptr}, + [__NR_amd64_ioperm] = {"ioperm", (void *)nullptr}, + [__NR_amd64_create_module] = {"create_module", (void *)nullptr}, + [__NR_amd64_init_module] = {"init_module", (void *)nullptr}, + [__NR_amd64_delete_module] = {"delete_module", (void *)nullptr}, + [__NR_amd64_get_kernel_syms] = {"get_kernel_syms", (void *)nullptr}, + [__NR_amd64_query_module] = {"query_module", (void *)nullptr}, + [__NR_amd64_quotactl] = {"quotactl", (void *)nullptr}, + [__NR_amd64_nfsservctl] = {"nfsservctl", (void *)nullptr}, + [__NR_amd64_getpmsg] = {"getpmsg", (void *)nullptr}, + [__NR_amd64_putpmsg] = {"putpmsg", (void *)nullptr}, + [__NR_amd64_afs_syscall] = {"afs_syscall", (void *)nullptr}, + [__NR_amd64_tuxcall] = {"tuxcall", (void *)nullptr}, + [__NR_amd64_security] = {"security", (void *)nullptr}, + [__NR_amd64_gettid] = {"gettid", (void *)linux_gettid}, + [__NR_amd64_readahead] = {"readahead", (void *)nullptr}, + [__NR_amd64_setxattr] = {"setxattr", (void *)nullptr}, + [__NR_amd64_lsetxattr] = {"lsetxattr", (void *)nullptr}, + [__NR_amd64_fsetxattr] = {"fsetxattr", (void *)nullptr}, + [__NR_amd64_getxattr] = {"getxattr", (void *)nullptr}, + [__NR_amd64_lgetxattr] = {"lgetxattr", (void *)nullptr}, + [__NR_amd64_fgetxattr] = {"fgetxattr", (void *)nullptr}, + [__NR_amd64_listxattr] = {"listxattr", (void *)nullptr}, + [__NR_amd64_llistxattr] = {"llistxattr", (void *)nullptr}, + [__NR_amd64_flistxattr] = {"flistxattr", (void *)nullptr}, + [__NR_amd64_removexattr] = {"removexattr", (void *)nullptr}, + [__NR_amd64_lremovexattr] = {"lremovexattr", (void *)nullptr}, + [__NR_amd64_fremovexattr] = {"fremovexattr", (void *)nullptr}, + [__NR_amd64_tkill] = {"tkill", (void *)nullptr}, + [__NR_amd64_time] = {"time", (void *)nullptr}, + [__NR_amd64_futex] = {"futex", (void *)nullptr}, + [__NR_amd64_sched_setaffinity] = {"sched_setaffinity", (void *)nullptr}, + [__NR_amd64_sched_getaffinity] = {"sched_getaffinity", (void *)nullptr}, + [__NR_amd64_set_thread_area] = {"set_thread_area", (void *)nullptr}, + [__NR_amd64_io_setup] = {"io_setup", (void *)nullptr}, + [__NR_amd64_io_destroy] = {"io_destroy", (void *)nullptr}, + [__NR_amd64_io_getevents] = {"io_getevents", (void *)nullptr}, + [__NR_amd64_io_submit] = {"io_submit", (void *)nullptr}, + [__NR_amd64_io_cancel] = {"io_cancel", (void *)nullptr}, + [__NR_amd64_get_thread_area] = {"get_thread_area", (void *)nullptr}, + [__NR_amd64_lookup_dcookie] = {"lookup_dcookie", (void *)nullptr}, + [__NR_amd64_epoll_create] = {"epoll_create", (void *)nullptr}, + [__NR_amd64_epoll_ctl_old] = {"epoll_ctl_old", (void *)nullptr}, + [__NR_amd64_epoll_wait_old] = {"epoll_wait_old", (void *)nullptr}, + [__NR_amd64_remap_file_pages] = {"remap_file_pages", (void *)nullptr}, + [__NR_amd64_getdents64] = {"getdents64", (void *)linux_getdents64}, + [__NR_amd64_set_tid_address] = {"set_tid_address", (void *)linux_set_tid_address}, + [__NR_amd64_restart_syscall] = {"restart_syscall", (void *)nullptr}, + [__NR_amd64_semtimedop] = {"semtimedop", (void *)nullptr}, + [__NR_amd64_fadvise64] = {"fadvise64", (void *)nullptr}, + [__NR_amd64_timer_create] = {"timer_create", (void *)nullptr}, + [__NR_amd64_timer_settime] = {"timer_settime", (void *)nullptr}, + [__NR_amd64_timer_gettime] = {"timer_gettime", (void *)nullptr}, + [__NR_amd64_timer_getoverrun] = {"timer_getoverrun", (void *)nullptr}, + [__NR_amd64_timer_delete] = {"timer_delete", (void *)nullptr}, + [__NR_amd64_clock_settime] = {"clock_settime", (void *)nullptr}, + [__NR_amd64_clock_gettime] = {"clock_gettime", (void *)linux_clock_gettime}, + [__NR_amd64_clock_getres] = {"clock_getres", (void *)nullptr}, + [__NR_amd64_clock_nanosleep] = {"clock_nanosleep", (void *)nullptr}, + [__NR_amd64_exit_group] = {"exit_group", (void *)linux_exit_group}, + [__NR_amd64_epoll_wait] = {"epoll_wait", (void *)nullptr}, + [__NR_amd64_epoll_ctl] = {"epoll_ctl", (void *)nullptr}, + [__NR_amd64_tgkill] = {"tgkill", (void *)linux_tgkill}, + [__NR_amd64_utimes] = {"utimes", (void *)nullptr}, + [__NR_amd64_vserver] = {"vserver", (void *)nullptr}, + [__NR_amd64_mbind] = {"mbind", (void *)nullptr}, + [__NR_amd64_set_mempolicy] = {"set_mempolicy", (void *)nullptr}, + [__NR_amd64_get_mempolicy] = {"get_mempolicy", (void *)nullptr}, + [__NR_amd64_mq_open] = {"mq_open", (void *)nullptr}, + [__NR_amd64_mq_unlink] = {"mq_unlink", (void *)nullptr}, + [__NR_amd64_mq_timedsend] = {"mq_timedsend", (void *)nullptr}, + [__NR_amd64_mq_timedreceive] = {"mq_timedreceive", (void *)nullptr}, + [__NR_amd64_mq_notify] = {"mq_notify", (void *)nullptr}, + [__NR_amd64_mq_getsetattr] = {"mq_getsetattr", (void *)nullptr}, + [__NR_amd64_kexec_load] = {"kexec_load", (void *)nullptr}, + [__NR_amd64_waitid] = {"waitid", (void *)nullptr}, + [__NR_amd64_add_key] = {"add_key", (void *)nullptr}, + [__NR_amd64_request_key] = {"request_key", (void *)nullptr}, + [__NR_amd64_keyctl] = {"keyctl", (void *)nullptr}, + [__NR_amd64_ioprio_set] = {"ioprio_set", (void *)nullptr}, + [__NR_amd64_ioprio_get] = {"ioprio_get", (void *)nullptr}, + [__NR_amd64_inotify_init] = {"inotify_init", (void *)nullptr}, + [__NR_amd64_inotify_add_watch] = {"inotify_add_watch", (void *)nullptr}, + [__NR_amd64_inotify_rm_watch] = {"inotify_rm_watch", (void *)nullptr}, + [__NR_amd64_migrate_pages] = {"migrate_pages", (void *)nullptr}, + [__NR_amd64_openat] = {"openat", (void *)nullptr}, + [__NR_amd64_mkdirat] = {"mkdirat", (void *)nullptr}, + [__NR_amd64_mknodat] = {"mknodat", (void *)nullptr}, + [__NR_amd64_fchownat] = {"fchownat", (void *)nullptr}, + [__NR_amd64_futimesat] = {"futimesat", (void *)nullptr}, + [__NR_amd64_newfstatat] = {"newfstatat", (void *)linux_newfstatat}, + [__NR_amd64_unlinkat] = {"unlinkat", (void *)nullptr}, + [__NR_amd64_renameat] = {"renameat", (void *)nullptr}, + [__NR_amd64_linkat] = {"linkat", (void *)nullptr}, + [__NR_amd64_symlinkat] = {"symlinkat", (void *)nullptr}, + [__NR_amd64_readlinkat] = {"readlinkat", (void *)nullptr}, + [__NR_amd64_fchmodat] = {"fchmodat", (void *)nullptr}, + [__NR_amd64_faccessat] = {"faccessat", (void *)nullptr}, + [__NR_amd64_pselect6] = {"pselect6", (void *)nullptr}, + [__NR_amd64_ppoll] = {"ppoll", (void *)nullptr}, + [__NR_amd64_unshare] = {"unshare", (void *)nullptr}, + [__NR_amd64_set_robust_list] = {"set_robust_list", (void *)nullptr}, + [__NR_amd64_get_robust_list] = {"get_robust_list", (void *)nullptr}, + [__NR_amd64_splice] = {"splice", (void *)nullptr}, + [__NR_amd64_tee] = {"tee", (void *)nullptr}, + [__NR_amd64_sync_file_range] = {"sync_file_range", (void *)nullptr}, + [__NR_amd64_vmsplice] = {"vmsplice", (void *)nullptr}, + [__NR_amd64_move_pages] = {"move_pages", (void *)nullptr}, + [__NR_amd64_utimensat] = {"utimensat", (void *)nullptr}, + [__NR_amd64_epoll_pwait] = {"epoll_pwait", (void *)nullptr}, + [__NR_amd64_signalfd] = {"signalfd", (void *)nullptr}, + [__NR_amd64_timerfd_create] = {"timerfd_create", (void *)nullptr}, + [__NR_amd64_eventfd] = {"eventfd", (void *)nullptr}, + [__NR_amd64_fallocate] = {"fallocate", (void *)nullptr}, + [__NR_amd64_timerfd_settime] = {"timerfd_settime", (void *)nullptr}, + [__NR_amd64_timerfd_gettime] = {"timerfd_gettime", (void *)nullptr}, + [__NR_amd64_accept4] = {"accept4", (void *)nullptr}, + [__NR_amd64_signalfd4] = {"signalfd4", (void *)nullptr}, + [__NR_amd64_eventfd2] = {"eventfd2", (void *)nullptr}, + [__NR_amd64_epoll_create1] = {"epoll_create1", (void *)nullptr}, + [__NR_amd64_dup3] = {"dup3", (void *)nullptr}, + [__NR_amd64_pipe2] = {"pipe2", (void *)linux_pipe2}, + [__NR_amd64_inotify_init1] = {"inotify_init1", (void *)nullptr}, + [__NR_amd64_preadv] = {"preadv", (void *)nullptr}, + [__NR_amd64_pwritev] = {"pwritev", (void *)nullptr}, + [__NR_amd64_rt_tgsigqueueinfo] = {"rt_tgsigqueueinfo", (void *)nullptr}, + [__NR_amd64_perf_event_open] = {"perf_event_open", (void *)nullptr}, + [__NR_amd64_recvmmsg] = {"recvmmsg", (void *)nullptr}, + [__NR_amd64_fanotify_init] = {"fanotify_init", (void *)nullptr}, + [__NR_amd64_fanotify_mark] = {"fanotify_mark", (void *)nullptr}, + [__NR_amd64_prlimit64] = {"prlimit64", (void *)linux_prlimit64}, + [__NR_amd64_name_to_handle_at] = {"name_to_handle_at", (void *)nullptr}, + [__NR_amd64_open_by_handle_at] = {"open_by_handle_at", (void *)nullptr}, + [__NR_amd64_clock_adjtime] = {"clock_adjtime", (void *)nullptr}, + [__NR_amd64_syncfs] = {"syncfs", (void *)nullptr}, + [__NR_amd64_sendmmsg] = {"sendmmsg", (void *)nullptr}, + [__NR_amd64_setns] = {"setns", (void *)nullptr}, + [__NR_amd64_getcpu] = {"getcpu", (void *)nullptr}, + [__NR_amd64_process_vm_readv] = {"process_vm_readv", (void *)nullptr}, + [__NR_amd64_process_vm_writev] = {"process_vm_writev", (void *)nullptr}, + [__NR_amd64_kcmp] = {"kcmp", (void *)nullptr}, + [__NR_amd64_finit_module] = {"finit_module", (void *)nullptr}, + [__NR_amd64_sched_setattr] = {"sched_setattr", (void *)nullptr}, + [__NR_amd64_sched_getattr] = {"sched_getattr", (void *)nullptr}, + [__NR_amd64_renameat2] = {"renameat2", (void *)nullptr}, + [__NR_amd64_seccomp] = {"seccomp", (void *)nullptr}, + [__NR_amd64_getrandom] = {"getrandom", (void *)linux_getrandom}, + [__NR_amd64_memfd_create] = {"memfd_create", (void *)nullptr}, + [__NR_amd64_kexec_file_load] = {"kexec_file_load", (void *)nullptr}, + [__NR_amd64_bpf] = {"bpf", (void *)nullptr}, + [__NR_amd64_execveat] = {"execveat", (void *)nullptr}, + [__NR_amd64_userfaultfd] = {"userfaultfd", (void *)nullptr}, + [__NR_amd64_membarrier] = {"membarrier", (void *)nullptr}, + [__NR_amd64_mlock2] = {"mlock2", (void *)nullptr}, + [__NR_amd64_copy_file_range] = {"copy_file_range", (void *)nullptr}, + [__NR_amd64_preadv2] = {"preadv2", (void *)nullptr}, + [__NR_amd64_pwritev2] = {"pwritev2", (void *)nullptr}, + [__NR_amd64_pkey_mprotect] = {"pkey_mprotect", (void *)nullptr}, + [__NR_amd64_pkey_alloc] = {"pkey_alloc", (void *)nullptr}, + [__NR_amd64_pkey_free] = {"pkey_free", (void *)nullptr}, + [__NR_amd64_statx] = {"statx", (void *)nullptr}, + [__NR_amd64_io_pgetevents] = {"io_pgetevents", (void *)nullptr}, + [__NR_amd64_rseq] = {"rseq", (void *)nullptr}, [335] = {"reserved", (void *)nullptr}, [336] = {"reserved", (void *)nullptr}, [337] = {"reserved", (void *)nullptr}, @@ -1061,46 +2328,495 @@ static SyscallData LinuxSyscallsTable[] = { [421] = {"reserved", (void *)nullptr}, [422] = {"reserved", (void *)nullptr}, [423] = {"reserved", (void *)nullptr}, - [__NR_pidfd_send_signal] = {"pidfd_send_signal", (void *)nullptr}, - [__NR_io_uring_setup] = {"io_uring_setup", (void *)nullptr}, - [__NR_io_uring_enter] = {"io_uring_enter", (void *)nullptr}, - [__NR_io_uring_register] = {"io_uring_register", (void *)nullptr}, - [__NR_open_tree] = {"open_tree", (void *)nullptr}, - [__NR_move_mount] = {"move_mount", (void *)nullptr}, - [__NR_fsopen] = {"fsopen", (void *)nullptr}, - [__NR_fsconfig] = {"fsconfig", (void *)nullptr}, - [__NR_fsmount] = {"fsmount", (void *)nullptr}, - [__NR_fspick] = {"fspick", (void *)nullptr}, - [__NR_pidfd_open] = {"pidfd_open", (void *)nullptr}, - [__NR_clone3] = {"clone3", (void *)nullptr}, - [__NR_close_range] = {"close_range", (void *)nullptr}, - [__NR_openat2] = {"openat2", (void *)nullptr}, - [__NR_pidfd_getfd] = {"pidfd_getfd", (void *)nullptr}, - [__NR_faccessat2] = {"faccessat2", (void *)nullptr}, - [__NR_process_madvise] = {"process_madvise", (void *)nullptr}, - [__NR_epoll_pwait2] = {"epoll_pwait2", (void *)nullptr}, - [__NR_mount_setattr] = {"mount_setattr", (void *)nullptr}, + [__NR_amd64_pidfd_send_signal] = {"pidfd_send_signal", (void *)nullptr}, + [__NR_amd64_io_uring_setup] = {"io_uring_setup", (void *)nullptr}, + [__NR_amd64_io_uring_enter] = {"io_uring_enter", (void *)nullptr}, + [__NR_amd64_io_uring_register] = {"io_uring_register", (void *)nullptr}, + [__NR_amd64_open_tree] = {"open_tree", (void *)nullptr}, + [__NR_amd64_move_mount] = {"move_mount", (void *)nullptr}, + [__NR_amd64_fsopen] = {"fsopen", (void *)nullptr}, + [__NR_amd64_fsconfig] = {"fsconfig", (void *)nullptr}, + [__NR_amd64_fsmount] = {"fsmount", (void *)nullptr}, + [__NR_amd64_fspick] = {"fspick", (void *)nullptr}, + [__NR_amd64_pidfd_open] = {"pidfd_open", (void *)nullptr}, + [__NR_amd64_clone3] = {"clone3", (void *)nullptr}, + [__NR_amd64_close_range] = {"close_range", (void *)nullptr}, + [__NR_amd64_openat2] = {"openat2", (void *)nullptr}, + [__NR_amd64_pidfd_getfd] = {"pidfd_getfd", (void *)nullptr}, + [__NR_amd64_faccessat2] = {"faccessat2", (void *)nullptr}, + [__NR_amd64_process_madvise] = {"process_madvise", (void *)nullptr}, + [__NR_amd64_epoll_pwait2] = {"epoll_pwait2", (void *)nullptr}, + [__NR_amd64_mount_setattr] = {"mount_setattr", (void *)nullptr}, [443] = {"reserved", (void *)nullptr}, - [__NR_landlock_create_ruleset] = {"landlock_create_ruleset", (void *)nullptr}, - [__NR_landlock_add_rule] = {"landlock_add_rule", (void *)nullptr}, - [__NR_landlock_restrict_self] = {"landlock_restrict_self", (void *)nullptr}, + [__NR_amd64_landlock_create_ruleset] = {"landlock_create_ruleset", (void *)nullptr}, + [__NR_amd64_landlock_add_rule] = {"landlock_add_rule", (void *)nullptr}, + [__NR_amd64_landlock_restrict_self] = {"landlock_restrict_self", (void *)nullptr}, +}; + +static SyscallData LinuxSyscallsTableI386[] = { + [__NR_i386_restart_syscall] = {"restart_syscall", (void *)nullptr}, + [__NR_i386_exit] = {"exit", (void *)linux_exit}, + [__NR_i386_fork] = {"fork", (void *)linux_fork}, + [__NR_i386_read] = {"read", (void *)linux_read}, + [__NR_i386_write] = {"write", (void *)linux_write}, + [__NR_i386_open] = {"open", (void *)linux_open}, + [__NR_i386_close] = {"close", (void *)linux_close}, + [__NR_i386_waitpid] = {"waitpid", (void *)nullptr}, + [__NR_i386_creat] = {"creat", (void *)linux_creat}, + [__NR_i386_link] = {"link", (void *)nullptr}, + [__NR_i386_unlink] = {"unlink", (void *)nullptr}, + [__NR_i386_execve] = {"execve", (void *)linux_execve}, + [__NR_i386_chdir] = {"chdir", (void *)nullptr}, + [__NR_i386_time] = {"time", (void *)nullptr}, + [__NR_i386_mknod] = {"mknod", (void *)nullptr}, + [__NR_i386_chmod] = {"chmod", (void *)nullptr}, + [__NR_i386_lchown] = {"lchown", (void *)nullptr}, + [__NR_i386_break] = {"break", (void *)nullptr}, + [__NR_i386_oldstat] = {"oldstat", (void *)nullptr}, + [__NR_i386_lseek] = {"lseek", (void *)linux_lseek}, + [__NR_i386_getpid] = {"getpid", (void *)linux_getpid}, + [__NR_i386_mount] = {"mount", (void *)nullptr}, + [__NR_i386_umount] = {"umount", (void *)nullptr}, + [__NR_i386_setuid] = {"setuid", (void *)nullptr}, + [__NR_i386_getuid] = {"getuid", (void *)nullptr}, + [__NR_i386_stime] = {"stime", (void *)nullptr}, + [__NR_i386_ptrace] = {"ptrace", (void *)nullptr}, + [__NR_i386_alarm] = {"alarm", (void *)nullptr}, + [__NR_i386_oldfstat] = {"oldfstat", (void *)nullptr}, + [__NR_i386_pause] = {"pause", (void *)nullptr}, + [__NR_i386_utime] = {"utime", (void *)nullptr}, + [__NR_i386_stty] = {"stty", (void *)nullptr}, + [__NR_i386_gtty] = {"gtty", (void *)nullptr}, + [__NR_i386_access] = {"access", (void *)nullptr}, + [__NR_i386_nice] = {"nice", (void *)nullptr}, + [__NR_i386_ftime] = {"ftime", (void *)nullptr}, + [__NR_i386_sync] = {"sync", (void *)nullptr}, + [__NR_i386_kill] = {"kill", (void *)linux_kill}, + [__NR_i386_rename] = {"rename", (void *)nullptr}, + [__NR_i386_mkdir] = {"mkdir", (void *)linux_mkdir}, + [__NR_i386_rmdir] = {"rmdir", (void *)nullptr}, + [__NR_i386_dup] = {"dup", (void *)linux_dup}, + [__NR_i386_pipe] = {"pipe", (void *)nullptr}, + [__NR_i386_times] = {"times", (void *)nullptr}, + [__NR_i386_prof] = {"prof", (void *)nullptr}, + [__NR_i386_brk] = {"brk", (void *)linux_brk}, + [__NR_i386_setgid] = {"setgid", (void *)nullptr}, + [__NR_i386_getgid] = {"getgid", (void *)nullptr}, + [__NR_i386_signal] = {"signal", (void *)nullptr}, + [__NR_i386_geteuid] = {"geteuid", (void *)nullptr}, + [__NR_i386_getegid] = {"getegid", (void *)nullptr}, + [__NR_i386_acct] = {"acct", (void *)nullptr}, + [__NR_i386_umount2] = {"umount2", (void *)nullptr}, + [__NR_i386_lock] = {"lock", (void *)nullptr}, + [__NR_i386_ioctl] = {"ioctl", (void *)linux_ioctl}, + [__NR_i386_fcntl] = {"fcntl", (void *)linux_fcntl}, + [__NR_i386_mpx] = {"mpx", (void *)nullptr}, + [__NR_i386_setpgid] = {"setpgid", (void *)nullptr}, + [__NR_i386_ulimit] = {"ulimit", (void *)nullptr}, + [__NR_i386_oldolduname] = {"oldolduname", (void *)nullptr}, + [__NR_i386_umask] = {"umask", (void *)nullptr}, + [__NR_i386_chroot] = {"chroot", (void *)nullptr}, + [__NR_i386_ustat] = {"ustat", (void *)nullptr}, + [__NR_i386_dup2] = {"dup2", (void *)linux_dup2}, + [__NR_i386_getppid] = {"getppid", (void *)linux_getppid}, + [__NR_i386_getpgrp] = {"getpgrp", (void *)nullptr}, + [__NR_i386_setsid] = {"setsid", (void *)nullptr}, + [__NR_i386_sigaction] = {"sigaction", (void *)nullptr}, + [__NR_i386_sgetmask] = {"sgetmask", (void *)nullptr}, + [__NR_i386_ssetmask] = {"ssetmask", (void *)nullptr}, + [__NR_i386_setreuid] = {"setreuid", (void *)nullptr}, + [__NR_i386_setregid] = {"setregid", (void *)nullptr}, + [__NR_i386_sigsuspend] = {"sigsuspend", (void *)nullptr}, + [__NR_i386_sigpending] = {"sigpending", (void *)nullptr}, + [__NR_i386_sethostname] = {"sethostname", (void *)nullptr}, + [__NR_i386_setrlimit] = {"setrlimit", (void *)nullptr}, + [__NR_i386_getrlimit] = {"getrlimit", (void *)nullptr}, + [__NR_i386_getrusage] = {"getrusage", (void *)nullptr}, + [__NR_i386_gettimeofday_time32] = {"gettimeofday_time32", (void *)nullptr}, + [__NR_i386_settimeofday_time32] = {"settimeofday_time32", (void *)nullptr}, + [__NR_i386_getgroups] = {"getgroups", (void *)nullptr}, + [__NR_i386_setgroups] = {"setgroups", (void *)nullptr}, + [__NR_i386_select] = {"select", (void *)nullptr}, + [__NR_i386_symlink] = {"symlink", (void *)nullptr}, + [__NR_i386_oldlstat] = {"oldlstat", (void *)nullptr}, + [__NR_i386_readlink] = {"readlink", (void *)linux_readlink}, + [__NR_i386_uselib] = {"uselib", (void *)nullptr}, + [__NR_i386_swapon] = {"swapon", (void *)nullptr}, + [__NR_i386_reboot] = {"reboot", (void *)linux_reboot}, + [__NR_i386_readdir] = {"readdir", (void *)nullptr}, + [__NR_i386_mmap] = {"mmap", (void *)linux_mmap}, + [__NR_i386_munmap] = {"munmap", (void *)linux_munmap}, + [__NR_i386_truncate] = {"truncate", (void *)nullptr}, + [__NR_i386_ftruncate] = {"ftruncate", (void *)nullptr}, + [__NR_i386_fchmod] = {"fchmod", (void *)nullptr}, + [__NR_i386_fchown] = {"fchown", (void *)nullptr}, + [__NR_i386_getpriority] = {"getpriority", (void *)nullptr}, + [__NR_i386_setpriority] = {"setpriority", (void *)nullptr}, + [__NR_i386_profil] = {"profil", (void *)nullptr}, + [__NR_i386_statfs] = {"statfs", (void *)nullptr}, + [__NR_i386_fstatfs] = {"fstatfs", (void *)nullptr}, + [__NR_i386_ioperm] = {"ioperm", (void *)nullptr}, + [__NR_i386_socketcall] = {"socketcall", (void *)nullptr}, + [__NR_i386_syslog] = {"syslog", (void *)nullptr}, + [__NR_i386_setitimer] = {"setitimer", (void *)nullptr}, + [__NR_i386_getitimer] = {"getitimer", (void *)nullptr}, + [__NR_i386_stat] = {"stat", (void *)linux_stat}, + [__NR_i386_lstat] = {"lstat", (void *)linux_lstat}, + [__NR_i386_fstat] = {"fstat", (void *)linux_fstat}, + [__NR_i386_olduname] = {"olduname", (void *)nullptr}, + [__NR_i386_iopl] = {"iopl", (void *)nullptr}, + [__NR_i386_vhangup] = {"vhangup", (void *)nullptr}, + [__NR_i386_idle] = {"idle", (void *)nullptr}, + [__NR_i386_vm86old] = {"vm86old", (void *)nullptr}, + [__NR_i386_wait4] = {"wait4", (void *)linux_wait4}, + [__NR_i386_swapoff] = {"swapoff", (void *)nullptr}, + [__NR_i386_sysinfo] = {"sysinfo", (void *)nullptr}, + [__NR_i386_ipc] = {"ipc", (void *)nullptr}, + [__NR_i386_fsync] = {"fsync", (void *)nullptr}, + [__NR_i386_sigreturn] = {"sigreturn", (void *)nullptr}, + [__NR_i386_clone] = {"clone", (void *)nullptr}, + [__NR_i386_setdomainname] = {"setdomainname", (void *)nullptr}, + [__NR_i386_uname] = {"uname", (void *)linux_uname}, + [__NR_i386_modify_ldt] = {"modify_ldt", (void *)nullptr}, + [__NR_i386_adjtimex] = {"adjtimex", (void *)nullptr}, + [__NR_i386_mprotect] = {"mprotect", (void *)linux_mprotect}, + [__NR_i386_sigprocmask] = {"sigprocmask", (void *)nullptr}, + [__NR_i386_create_module] = {"create_module", (void *)nullptr}, + [__NR_i386_init_module] = {"init_module", (void *)nullptr}, + [__NR_i386_delete_module] = {"delete_module", (void *)nullptr}, + [__NR_i386_get_kernel_syms] = {"get_kernel_syms", (void *)nullptr}, + [__NR_i386_quotactl] = {"quotactl", (void *)nullptr}, + [__NR_i386_getpgid] = {"getpgid", (void *)nullptr}, + [__NR_i386_fchdir] = {"fchdir", (void *)nullptr}, + [__NR_i386_bdflush] = {"bdflush", (void *)nullptr}, + [__NR_i386_sysfs] = {"sysfs", (void *)nullptr}, + [__NR_i386_personality] = {"personality", (void *)nullptr}, + [__NR_i386_afs_syscall] = {"afs_syscall", (void *)nullptr}, + [__NR_i386_setfsuid] = {"setfsuid", (void *)nullptr}, + [__NR_i386_setfsgid] = {"setfsgid", (void *)nullptr}, + [__NR_i386__llseek] = {"_llseek", (void *)nullptr}, + [__NR_i386_getdents] = {"getdents", (void *)nullptr}, + [__NR_i386__newselect] = {"_newselect", (void *)nullptr}, + [__NR_i386_flock] = {"flock", (void *)nullptr}, + [__NR_i386_msync] = {"msync", (void *)nullptr}, + [__NR_i386_readv] = {"readv", (void *)linux_readv}, + [__NR_i386_writev] = {"writev", (void *)linux_writev}, + [__NR_i386_getsid] = {"getsid", (void *)nullptr}, + [__NR_i386_fdatasync] = {"fdatasync", (void *)nullptr}, + [__NR_i386__sysctl] = {"_sysctl", (void *)nullptr}, + [__NR_i386_mlock] = {"mlock", (void *)nullptr}, + [__NR_i386_munlock] = {"munlock", (void *)nullptr}, + [__NR_i386_mlockall] = {"mlockall", (void *)nullptr}, + [__NR_i386_munlockall] = {"munlockall", (void *)nullptr}, + [__NR_i386_sched_setparam] = {"sched_setparam", (void *)nullptr}, + [__NR_i386_sched_getparam] = {"sched_getparam", (void *)nullptr}, + [__NR_i386_sched_setscheduler] = {"sched_setscheduler", (void *)nullptr}, + [__NR_i386_sched_getscheduler] = {"sched_getscheduler", (void *)nullptr}, + [__NR_i386_sched_yield] = {"sched_yield", (void *)nullptr}, + [__NR_i386_sched_get_priority_max] = {"sched_get_priority_max", (void *)nullptr}, + [__NR_i386_sched_get_priority_min] = {"sched_get_priority_min", (void *)nullptr}, + [__NR_i386_sched_rr_get_interval] = {"sched_rr_get_interval", (void *)nullptr}, + [__NR_i386_nanosleep] = {"nanosleep", (void *)nullptr}, + [__NR_i386_mremap] = {"mremap", (void *)nullptr}, + [__NR_i386_setresuid] = {"setresuid", (void *)nullptr}, + [__NR_i386_getresuid] = {"getresuid", (void *)nullptr}, + [__NR_i386_vm86] = {"vm86", (void *)nullptr}, + [__NR_i386_query_module] = {"query_module", (void *)nullptr}, + [__NR_i386_poll] = {"poll", (void *)nullptr}, + [__NR_i386_nfsservctl] = {"nfsservctl", (void *)nullptr}, + [__NR_i386_setresgid] = {"setresgid", (void *)nullptr}, + [__NR_i386_getresgid] = {"getresgid", (void *)nullptr}, + [__NR_i386_prctl] = {"prctl", (void *)nullptr}, + [__NR_i386_rt_sigreturn] = {"rt_sigreturn", (void *)linux_sigreturn}, + [__NR_i386_rt_sigaction] = {"rt_sigaction", (void *)nullptr}, + [__NR_i386_rt_sigprocmask] = {"rt_sigprocmask", (void *)linux_sigprocmask}, + [__NR_i386_rt_sigpending] = {"rt_sigpending", (void *)nullptr}, + [__NR_i386_rt_sigtimedwait] = {"rt_sigtimedwait", (void *)nullptr}, + [__NR_i386_rt_sigqueueinfo] = {"rt_sigqueueinfo", (void *)nullptr}, + [__NR_i386_rt_sigsuspend] = {"rt_sigsuspend", (void *)nullptr}, + [__NR_i386_pread64] = {"pread64", (void *)nullptr}, + [__NR_i386_pwrite64] = {"pwrite64", (void *)nullptr}, + [__NR_i386_chown] = {"chown", (void *)nullptr}, + [__NR_i386_getcwd] = {"getcwd", (void *)nullptr}, + [__NR_i386_capget] = {"capget", (void *)nullptr}, + [__NR_i386_capset] = {"capset", (void *)nullptr}, + [__NR_i386_sigaltstack] = {"sigaltstack", (void *)nullptr}, + [__NR_i386_sendfile] = {"sendfile", (void *)nullptr}, + [__NR_i386_getpmsg] = {"getpmsg", (void *)nullptr}, + [__NR_i386_putpmsg] = {"putpmsg", (void *)nullptr}, + [__NR_i386_vfork] = {"vfork", (void *)nullptr}, + [__NR_i386_ugetrlimit] = {"ugetrlimit", (void *)nullptr}, + [__NR_i386_mmap2] = {"mmap2", (void *)nullptr}, + [__NR_i386_truncate64] = {"truncate64", (void *)nullptr}, + [__NR_i386_ftruncate64] = {"ftruncate64", (void *)nullptr}, + [__NR_i386_stat64] = {"stat64", (void *)nullptr}, + [__NR_i386_lstat64] = {"lstat64", (void *)nullptr}, + [__NR_i386_fstat64] = {"fstat64", (void *)nullptr}, + [__NR_i386_lchown32] = {"lchown32", (void *)nullptr}, + [__NR_i386_getuid32] = {"getuid32", (void *)nullptr}, + [__NR_i386_getgid32] = {"getgid32", (void *)nullptr}, + [__NR_i386_geteuid32] = {"geteuid32", (void *)nullptr}, + [__NR_i386_getegid32] = {"getegid32", (void *)nullptr}, + [__NR_i386_setreuid32] = {"setreuid32", (void *)nullptr}, + [__NR_i386_setregid32] = {"setregid32", (void *)nullptr}, + [__NR_i386_getgroups32] = {"getgroups32", (void *)nullptr}, + [__NR_i386_setgroups32] = {"setgroups32", (void *)nullptr}, + [__NR_i386_fchown32] = {"fchown32", (void *)nullptr}, + [__NR_i386_setresuid32] = {"setresuid32", (void *)nullptr}, + [__NR_i386_getresuid32] = {"getresuid32", (void *)nullptr}, + [__NR_i386_setresgid32] = {"setresgid32", (void *)nullptr}, + [__NR_i386_getresgid32] = {"getresgid32", (void *)nullptr}, + [__NR_i386_chown32] = {"chown32", (void *)nullptr}, + [__NR_i386_setuid32] = {"setuid32", (void *)nullptr}, + [__NR_i386_setgid32] = {"setgid32", (void *)nullptr}, + [__NR_i386_setfsuid32] = {"setfsuid32", (void *)nullptr}, + [__NR_i386_setfsgid32] = {"setfsgid32", (void *)nullptr}, + [__NR_i386_pivot_root] = {"pivot_root", (void *)nullptr}, + [__NR_i386_mincore] = {"mincore", (void *)nullptr}, + [__NR_i386_madvise] = {"madvise", (void *)nullptr}, + [__NR_i386_getdents64] = {"getdents64", (void *)linux_getdents64}, + [__NR_i386_fcntl64] = {"fcntl64", (void *)nullptr}, + [222] = {"reserved", (void *)nullptr}, + [223] = {"reserved", (void *)nullptr}, + [__NR_i386_gettid] = {"gettid", (void *)linux_gettid}, + [__NR_i386_readahead] = {"readahead", (void *)nullptr}, + [__NR_i386_setxattr] = {"setxattr", (void *)nullptr}, + [__NR_i386_lsetxattr] = {"lsetxattr", (void *)nullptr}, + [__NR_i386_fsetxattr] = {"fsetxattr", (void *)nullptr}, + [__NR_i386_getxattr] = {"getxattr", (void *)nullptr}, + [__NR_i386_lgetxattr] = {"lgetxattr", (void *)nullptr}, + [__NR_i386_fgetxattr] = {"fgetxattr", (void *)nullptr}, + [__NR_i386_listxattr] = {"listxattr", (void *)nullptr}, + [__NR_i386_llistxattr] = {"llistxattr", (void *)nullptr}, + [__NR_i386_flistxattr] = {"flistxattr", (void *)nullptr}, + [__NR_i386_removexattr] = {"removexattr", (void *)nullptr}, + [__NR_i386_lremovexattr] = {"lremovexattr", (void *)nullptr}, + [__NR_i386_fremovexattr] = {"fremovexattr", (void *)nullptr}, + [__NR_i386_tkill] = {"tkill", (void *)nullptr}, + [__NR_i386_sendfile64] = {"sendfile64", (void *)nullptr}, + [__NR_i386_futex] = {"futex", (void *)nullptr}, + [__NR_i386_sched_setaffinity] = {"sched_setaffinity", (void *)nullptr}, + [__NR_i386_sched_getaffinity] = {"sched_getaffinity", (void *)nullptr}, + [__NR_i386_set_thread_area] = {"set_thread_area", (void *)nullptr}, + [__NR_i386_get_thread_area] = {"get_thread_area", (void *)nullptr}, + [__NR_i386_io_setup] = {"io_setup", (void *)nullptr}, + [__NR_i386_io_destroy] = {"io_destroy", (void *)nullptr}, + [__NR_i386_io_getevents] = {"io_getevents", (void *)nullptr}, + [__NR_i386_io_submit] = {"io_submit", (void *)nullptr}, + [__NR_i386_io_cancel] = {"io_cancel", (void *)nullptr}, + [__NR_i386_fadvise64] = {"fadvise64", (void *)nullptr}, + [__NR_i386_set_zone_reclaim] = {"set_zone_reclaim", (void *)nullptr}, + [__NR_i386_exit_group] = {"exit_group", (void *)linux_exit_group}, + [__NR_i386_lookup_dcookie] = {"lookup_dcookie", (void *)nullptr}, + [__NR_i386_epoll_create] = {"epoll_create", (void *)nullptr}, + [__NR_i386_epoll_ctl] = {"epoll_ctl", (void *)nullptr}, + [__NR_i386_epoll_wait] = {"epoll_wait", (void *)nullptr}, + [__NR_i386_remap_file_pages] = {"remap_file_pages", (void *)nullptr}, + [__NR_i386_set_tid_address] = {"set_tid_address", (void *)linux_set_tid_address}, + [__NR_i386_timer_create] = {"timer_create", (void *)nullptr}, + [__NR_i386_timer_settime32] = {"timer_settime32", (void *)nullptr}, + [__NR_i386_timer_gettime32] = {"timer_gettime32", (void *)nullptr}, + [__NR_i386_timer_getoverrun] = {"timer_getoverrun", (void *)nullptr}, + [__NR_i386_timer_delete] = {"timer_delete", (void *)nullptr}, + [__NR_i386_clock_settime32] = {"clock_settime32", (void *)nullptr}, + [__NR_i386_clock_gettime32] = {"clock_gettime32", (void *)nullptr}, + [__NR_i386_clock_getres_time32] = {"clock_getres_time32", (void *)nullptr}, + [__NR_i386_clock_nanosleep_time32] = {"clock_nanosleep_time32", (void *)nullptr}, + [__NR_i386_statfs64] = {"statfs64", (void *)nullptr}, + [__NR_i386_fstatfs64] = {"fstatfs64", (void *)nullptr}, + [__NR_i386_tgkill] = {"tgkill", (void *)linux_tgkill}, + [__NR_i386_utimes] = {"utimes", (void *)nullptr}, + [__NR_i386_fadvise64_64] = {"fadvise64_64", (void *)nullptr}, + [__NR_i386_vserver] = {"vserver", (void *)nullptr}, + [__NR_i386_mbind] = {"mbind", (void *)nullptr}, + [__NR_i386_get_mempolicy] = {"get_mempolicy", (void *)nullptr}, + [__NR_i386_set_mempolicy] = {"set_mempolicy", (void *)nullptr}, + [__NR_i386_mq_open] = {"mq_open", (void *)nullptr}, + [__NR_i386_mq_unlink] = {"mq_unlink", (void *)nullptr}, + [__NR_i386_mq_timedsend] = {"mq_timedsend", (void *)nullptr}, + [__NR_i386_mq_timedreceive] = {"mq_timedreceive", (void *)nullptr}, + [__NR_i386_mq_notify] = {"mq_notify", (void *)nullptr}, + [__NR_i386_mq_getsetattr] = {"mq_getsetattr", (void *)nullptr}, + [__NR_i386_kexec_load] = {"kexec_load", (void *)nullptr}, + [__NR_i386_waitid] = {"waitid", (void *)nullptr}, + [__NR_i386_sys_setaltroot] = {"sys_setaltroot", (void *)nullptr}, + [__NR_i386_add_key] = {"add_key", (void *)nullptr}, + [__NR_i386_request_key] = {"request_key", (void *)nullptr}, + [__NR_i386_keyctl] = {"keyctl", (void *)nullptr}, + [__NR_i386_ioprio_set] = {"ioprio_set", (void *)nullptr}, + [__NR_i386_ioprio_get] = {"ioprio_get", (void *)nullptr}, + [__NR_i386_inotify_init] = {"inotify_init", (void *)nullptr}, + [__NR_i386_inotify_add_watch] = {"inotify_add_watch", (void *)nullptr}, + [__NR_i386_inotify_rm_watch] = {"inotify_rm_watch", (void *)nullptr}, + [__NR_i386_migrate_pages] = {"migrate_pages", (void *)nullptr}, + [__NR_i386_openat] = {"openat", (void *)nullptr}, + [__NR_i386_mkdirat] = {"mkdirat", (void *)nullptr}, + [__NR_i386_mknodat] = {"mknodat", (void *)nullptr}, + [__NR_i386_fchownat] = {"fchownat", (void *)nullptr}, + [__NR_i386_futimesat] = {"futimesat", (void *)nullptr}, + [__NR_i386_fstatat64] = {"fstatat64", (void *)nullptr}, + [__NR_i386_unlinkat] = {"unlinkat", (void *)nullptr}, + [__NR_i386_renameat] = {"renameat", (void *)nullptr}, + [__NR_i386_linkat] = {"linkat", (void *)nullptr}, + [__NR_i386_symlinkat] = {"symlinkat", (void *)nullptr}, + [__NR_i386_readlinkat] = {"readlinkat", (void *)nullptr}, + [__NR_i386_fchmodat] = {"fchmodat", (void *)nullptr}, + [__NR_i386_faccessat] = {"faccessat", (void *)nullptr}, + [__NR_i386_pselect6] = {"pselect6", (void *)nullptr}, + [__NR_i386_ppoll] = {"ppoll", (void *)nullptr}, + [__NR_i386_unshare] = {"unshare", (void *)nullptr}, + [__NR_i386_set_robust_list] = {"set_robust_list", (void *)nullptr}, + [__NR_i386_get_robust_list] = {"get_robust_list", (void *)nullptr}, + [__NR_i386_splice] = {"splice", (void *)nullptr}, + [__NR_i386_sync_file_range] = {"sync_file_range", (void *)nullptr}, + [__NR_i386_tee] = {"tee", (void *)nullptr}, + [__NR_i386_vmsplice] = {"vmsplice", (void *)nullptr}, + [__NR_i386_move_pages] = {"move_pages", (void *)nullptr}, + [__NR_i386_getcpu] = {"getcpu", (void *)nullptr}, + [__NR_i386_epoll_pwait] = {"epoll_pwait", (void *)nullptr}, + [__NR_i386_utimensat] = {"utimensat", (void *)nullptr}, + [__NR_i386_signalfd] = {"signalfd", (void *)nullptr}, + [__NR_i386_timerfd_create] = {"timerfd_create", (void *)nullptr}, + [__NR_i386_eventfd] = {"eventfd", (void *)nullptr}, + [__NR_i386_fallocate] = {"fallocate", (void *)nullptr}, + [__NR_i386_timerfd_settime32] = {"timerfd_settime32", (void *)nullptr}, + [__NR_i386_timerfd_gettime32] = {"timerfd_gettime32", (void *)nullptr}, + [__NR_i386_signalfd4] = {"signalfd4", (void *)nullptr}, + [__NR_i386_eventfd2] = {"eventfd2", (void *)nullptr}, + [__NR_i386_epoll_create1] = {"epoll_create1", (void *)nullptr}, + [__NR_i386_dup3] = {"dup3", (void *)nullptr}, + [__NR_i386_pipe2] = {"pipe2", (void *)nullptr}, + [__NR_i386_inotify_init1] = {"inotify_init1", (void *)nullptr}, + [__NR_i386_preadv] = {"preadv", (void *)nullptr}, + [__NR_i386_pwritev] = {"pwritev", (void *)nullptr}, + [__NR_i386_rt_tgsigqueueinfo] = {"rt_tgsigqueueinfo", (void *)nullptr}, + [__NR_i386_perf_event_open] = {"perf_event_open", (void *)nullptr}, + [__NR_i386_recvmmsg] = {"recvmmsg", (void *)nullptr}, + [__NR_i386_fanotify_init] = {"fanotify_init", (void *)nullptr}, + [__NR_i386_fanotify_mark] = {"fanotify_mark", (void *)nullptr}, + [__NR_i386_prlimit64] = {"prlimit64", (void *)nullptr}, + [__NR_i386_name_to_handle_at] = {"name_to_handle_at", (void *)nullptr}, + [__NR_i386_open_by_handle_at] = {"open_by_handle_at", (void *)nullptr}, + [__NR_i386_clock_adjtime] = {"clock_adjtime", (void *)nullptr}, + [__NR_i386_syncfs] = {"syncfs", (void *)nullptr}, + [__NR_i386_sendmmsg] = {"sendmmsg", (void *)nullptr}, + [__NR_i386_setns] = {"setns", (void *)nullptr}, + [__NR_i386_process_vm_readv] = {"process_vm_readv", (void *)nullptr}, + [__NR_i386_process_vm_writev] = {"process_vm_writev", (void *)nullptr}, + [__NR_i386_kcmp] = {"kcmp", (void *)nullptr}, + [__NR_i386_finit_module] = {"finit_module", (void *)nullptr}, + [__NR_i386_sched_setattr] = {"sched_setattr", (void *)nullptr}, + [__NR_i386_sched_getattr] = {"sched_getattr", (void *)nullptr}, + [__NR_i386_renameat2] = {"renameat2", (void *)nullptr}, + [__NR_i386_seccomp] = {"seccomp", (void *)nullptr}, + [__NR_i386_getrandom] = {"getrandom", (void *)linux_getrandom}, + [__NR_i386_memfd_create] = {"memfd_create", (void *)nullptr}, + [__NR_i386_bpf] = {"bpf", (void *)nullptr}, + [__NR_i386_execveat] = {"execveat", (void *)nullptr}, + [__NR_i386_socket] = {"socket", (void *)nullptr}, + [__NR_i386_socketpair] = {"socketpair", (void *)nullptr}, + [__NR_i386_bind] = {"bind", (void *)nullptr}, + [__NR_i386_connect] = {"connect", (void *)nullptr}, + [__NR_i386_listen] = {"listen", (void *)nullptr}, + [__NR_i386_accept4] = {"accept4", (void *)nullptr}, + [__NR_i386_getsockopt] = {"getsockopt", (void *)nullptr}, + [__NR_i386_setsockopt] = {"setsockopt", (void *)nullptr}, + [__NR_i386_getsockname] = {"getsockname", (void *)nullptr}, + [__NR_i386_getpeername] = {"getpeername", (void *)nullptr}, + [__NR_i386_sendto] = {"sendto", (void *)nullptr}, + [__NR_i386_sendmsg] = {"sendmsg", (void *)nullptr}, + [__NR_i386_recvfrom] = {"recvfrom", (void *)nullptr}, + [__NR_i386_recvmsg] = {"recvmsg", (void *)nullptr}, + [__NR_i386_shutdown] = {"shutdown", (void *)linux_shutdown}, + [__NR_i386_userfaultfd] = {"userfaultfd", (void *)nullptr}, + [__NR_i386_membarrier] = {"membarrier", (void *)nullptr}, + [__NR_i386_mlock2] = {"mlock2", (void *)nullptr}, + [__NR_i386_copy_file_range] = {"copy_file_range", (void *)nullptr}, + [__NR_i386_preadv2] = {"preadv2", (void *)nullptr}, + [__NR_i386_pwritev2] = {"pwritev2", (void *)nullptr}, + [__NR_i386_pkey_mprotect] = {"pkey_mprotect", (void *)nullptr}, + [__NR_i386_pkey_alloc] = {"pkey_alloc", (void *)nullptr}, + [__NR_i386_pkey_free] = {"pkey_free", (void *)nullptr}, + [__NR_i386_statx] = {"statx", (void *)nullptr}, + [__NR_i386_arch_prctl] = {"arch_prctl", (void *)linux_arch_prctl}, + [__NR_i386_io_pgetevents] = {"io_pgetevents", (void *)nullptr}, + [__NR_i386_rseq] = {"rseq", (void *)nullptr}, + [387] = {"reserved", (void *)nullptr}, + [388] = {"reserved", (void *)nullptr}, + [389] = {"reserved", (void *)nullptr}, + [390] = {"reserved", (void *)nullptr}, + [391] = {"reserved", (void *)nullptr}, + [392] = {"reserved", (void *)nullptr}, + [__NR_i386_semget] = {"semget", (void *)nullptr}, + [__NR_i386_semctl] = {"semctl", (void *)nullptr}, + [__NR_i386_shmget] = {"shmget", (void *)nullptr}, + [__NR_i386_shmctl] = {"shmctl", (void *)nullptr}, + [__NR_i386_shmat] = {"shmat", (void *)nullptr}, + [__NR_i386_shmdt] = {"shmdt", (void *)nullptr}, + [__NR_i386_msgget] = {"msgget", (void *)nullptr}, + [__NR_i386_msgsnd] = {"msgsnd", (void *)nullptr}, + [__NR_i386_msgrcv] = {"msgrcv", (void *)nullptr}, + [__NR_i386_msgctl] = {"msgctl", (void *)nullptr}, + [__NR_i386_clock_gettime64] = {"clock_gettime64", (void *)nullptr}, + [__NR_i386_clock_settime64] = {"clock_settime64", (void *)nullptr}, + [__NR_i386_clock_adjtime64] = {"clock_adjtime64", (void *)nullptr}, + [__NR_i386_clock_getres_time64] = {"clock_getres_time64", (void *)nullptr}, + [__NR_i386_clock_nanosleep_time64] = {"clock_nanosleep_time64", (void *)nullptr}, + [__NR_i386_timer_gettime64] = {"timer_gettime64", (void *)nullptr}, + [__NR_i386_timer_settime64] = {"timer_settime64", (void *)nullptr}, + [__NR_i386_timerfd_gettime64] = {"timerfd_gettime64", (void *)nullptr}, + [__NR_i386_timerfd_settime64] = {"timerfd_settime64", (void *)nullptr}, + [__NR_i386_utimensat_time64] = {"utimensat_time64", (void *)nullptr}, + [__NR_i386_pselect6_time64] = {"pselect6_time64", (void *)nullptr}, + [__NR_i386_ppoll_time64] = {"ppoll_time64", (void *)nullptr}, + [415] = {"reserved", (void *)nullptr}, + [__NR_i386_io_pgetevents_time64] = {"io_pgetevents_time64", (void *)nullptr}, + [__NR_i386_recvmmsg_time64] = {"recvmmsg_time64", (void *)nullptr}, + [__NR_i386_mq_timedsend_time64] = {"mq_timedsend_time64", (void *)nullptr}, + [__NR_i386_mq_timedreceive_time64] = {"mq_timedreceive_time64", (void *)nullptr}, + [__NR_i386_semtimedop_time64] = {"semtimedop_time64", (void *)nullptr}, + [__NR_i386_rt_sigtimedwait_time64] = {"rt_sigtimedwait_time64", (void *)nullptr}, + [__NR_i386_futex_time64] = {"futex_time64", (void *)nullptr}, + [__NR_i386_sched_rr_get_interval_time64] = {"sched_rr_get_interval_time64", (void *)nullptr}, + [__NR_i386_pidfd_send_signal] = {"pidfd_send_signal", (void *)nullptr}, + [__NR_i386_io_uring_setup] = {"io_uring_setup", (void *)nullptr}, + [__NR_i386_io_uring_enter] = {"io_uring_enter", (void *)nullptr}, + [__NR_i386_io_uring_register] = {"io_uring_register", (void *)nullptr}, + [__NR_i386_open_tree] = {"open_tree", (void *)nullptr}, + [__NR_i386_move_mount] = {"move_mount", (void *)nullptr}, + [__NR_i386_fsopen] = {"fsopen", (void *)nullptr}, + [__NR_i386_fsconfig] = {"fsconfig", (void *)nullptr}, + [__NR_i386_fsmount] = {"fsmount", (void *)nullptr}, + [__NR_i386_fspick] = {"fspick", (void *)nullptr}, + [__NR_i386_pidfd_open] = {"pidfd_open", (void *)nullptr}, + [__NR_i386_clone3] = {"clone3", (void *)nullptr}, + [__NR_i386_close_range] = {"close_range", (void *)nullptr}, + [__NR_i386_openat2] = {"openat2", (void *)nullptr}, + [__NR_i386_pidfd_getfd] = {"pidfd_getfd", (void *)nullptr}, + [__NR_i386_faccessat2] = {"faccessat2", (void *)nullptr}, + [__NR_i386_process_madvise] = {"process_madvise", (void *)nullptr}, + [__NR_i386_epoll_pwait2] = {"epoll_pwait2", (void *)nullptr}, + [__NR_i386_mount_setattr] = {"mount_setattr", (void *)nullptr}, + [443] = {"reserved", (void *)nullptr}, + [__NR_i386_landlock_create_ruleset] = {"landlock_create_ruleset", (void *)nullptr}, + [__NR_i386_landlock_add_rule] = {"landlock_add_rule", (void *)nullptr}, + [__NR_i386_landlock_restrict_self] = {"landlock_restrict_self", (void *)nullptr}, }; uintptr_t HandleLinuxSyscalls(SyscallsFrame *Frame) { - thisFrame = Frame; #if defined(a64) - if (Frame->rax > sizeof(LinuxSyscallsTable) / sizeof(SyscallData)) + if (Frame->rax > sizeof(LinuxSyscallsTableAMD64) / sizeof(SyscallData)) { fixme("Syscall %d not implemented", Frame->rax); return -ENOSYS; } - SyscallData Syscall = LinuxSyscallsTable[Frame->rax]; + SyscallData Syscall = LinuxSyscallsTableAMD64[Frame->rax]; - long (*call)(long, ...) = r_cst(long (*)(long, ...), - Syscall.Handler); + long (*call)(SysFrm *, long, ...) = r_cst(long (*)(SysFrm *, long, ...), + Syscall.Handler); if (unlikely(!call)) { @@ -1114,23 +2830,24 @@ uintptr_t HandleLinuxSyscalls(SyscallsFrame *Frame) Frame->rdi, Frame->rsi, Frame->rdx, Frame->r10, Frame->r8, Frame->r9); - long sc_ret = call(Frame->rdi, Frame->rsi, Frame->rdx, + long sc_ret = call(Frame, + Frame->rdi, Frame->rsi, Frame->rdx, Frame->r10, Frame->r8, Frame->r9); debug("< [%d:\"%s\"] = %d", Frame->rax, Syscall.Name, sc_ret); return sc_ret; #elif defined(a32) - if (Frame->eax > sizeof(LinuxSyscallsTable) / sizeof(SyscallData)) + if (Frame->eax > sizeof(LinuxSyscallsTableI386) / sizeof(SyscallData)) { fixme("Syscall %d not implemented", Frame->eax); return -ENOSYS; } - SyscallData Syscall = LinuxSyscallsTable[Frame->eax]; + SyscallData Syscall = LinuxSyscallsTableI386[Frame->eax]; - long (*call)(long, ...) = r_cst(long (*)(long, ...), - Syscall.Handler); + long (*call)(SysFrm *, long, ...) = r_cst(long (*)(SysFrm *, long, ...), + Syscall.Handler); if (unlikely(!call)) { @@ -1144,7 +2861,8 @@ uintptr_t HandleLinuxSyscalls(SyscallsFrame *Frame) Frame->ebx, Frame->ecx, Frame->edx, Frame->esi, Frame->edi, Frame->ebp); - int sc_ret = call(Frame->ebx, Frame->ecx, Frame->edx, + int sc_ret = call(Frame, + Frame->ebx, Frame->ecx, Frame->edx, Frame->esi, Frame->edi, Frame->ebp); debug("< [%d:\"%s\"] = %d", Frame->eax, Syscall.Name, sc_ret); @@ -1152,4 +2870,10 @@ uintptr_t HandleLinuxSyscalls(SyscallsFrame *Frame) #elif defined(aa64) return -ENOSYS; #endif + +#if defined(a64) + UNUSED(LinuxSyscallsTableI386); +#elif defined(a32) + UNUSED(LinuxSyscallsTableAMD64); +#endif } diff --git a/syscalls/linux_syscalls.hpp b/syscalls/linux_syscalls.hpp deleted file mode 100644 index ab6620f..0000000 --- a/syscalls/linux_syscalls.hpp +++ /dev/null @@ -1,381 +0,0 @@ -/* - This file is part of Fennix Kernel. - - Fennix Kernel is free software: you can redistribute it and/or - modify it under the terms of the GNU General Public License as - published by the Free Software Foundation, either version 3 of - the License, or (at your option) any later version. - - Fennix Kernel is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Fennix Kernel. If not, see . -*/ - -#ifndef __FENNIX_KERNEL_LINUX_SYSCALLS_H__ -#define __FENNIX_KERNEL_LINUX_SYSCALLS_H__ - -#include - -#define __NR_read 0 -#define __NR_write 1 -#define __NR_open 2 -#define __NR_close 3 -#define __NR_stat 4 -#define __NR_fstat 5 -#define __NR_lstat 6 -#define __NR_poll 7 -#define __NR_lseek 8 -#define __NR_mmap 9 -#define __NR_mprotect 10 -#define __NR_munmap 11 -#define __NR_brk 12 -#define __NR_rt_sigaction 13 -#define __NR_rt_sigprocmask 14 -#define __NR_rt_sigreturn 15 -#define __NR_ioctl 16 -#define __NR_pread64 17 -#define __NR_pwrite64 18 -#define __NR_readv 19 -#define __NR_writev 20 -#define __NR_access 21 -#define __NR_pipe 22 -#define __NR_select 23 -#define __NR_sched_yield 24 -#define __NR_mremap 25 -#define __NR_msync 26 -#define __NR_mincore 27 -#define __NR_madvise 28 -#define __NR_shmget 29 -#define __NR_shmat 30 -#define __NR_shmctl 31 -#define __NR_dup 32 -#define __NR_dup2 33 -#define __NR_pause 34 -#define __NR_nanosleep 35 -#define __NR_getitimer 36 -#define __NR_alarm 37 -#define __NR_setitimer 38 -#define __NR_getpid 39 -#define __NR_sendfile 40 -#define __NR_socket 41 -#define __NR_connect 42 -#define __NR_accept 43 -#define __NR_sendto 44 -#define __NR_recvfrom 45 -#define __NR_sendmsg 46 -#define __NR_recvmsg 47 -#define __NR_shutdown 48 -#define __NR_bind 49 -#define __NR_listen 50 -#define __NR_getsockname 51 -#define __NR_getpeername 52 -#define __NR_socketpair 53 -#define __NR_setsockopt 54 -#define __NR_getsockopt 55 -#define __NR_clone 56 -#define __NR_fork 57 -#define __NR_vfork 58 -#define __NR_execve 59 -#define __NR_exit 60 -#define __NR_wait4 61 -#define __NR_kill 62 -#define __NR_uname 63 -#define __NR_semget 64 -#define __NR_semop 65 -#define __NR_semctl 66 -#define __NR_shmdt 67 -#define __NR_msgget 68 -#define __NR_msgsnd 69 -#define __NR_msgrcv 70 -#define __NR_msgctl 71 -#define __NR_fcntl 72 -#define __NR_flock 73 -#define __NR_fsync 74 -#define __NR_fdatasync 75 -#define __NR_truncate 76 -#define __NR_ftruncate 77 -#define __NR_getdents 78 -#define __NR_getcwd 79 -#define __NR_chdir 80 -#define __NR_fchdir 81 -#define __NR_rename 82 -#define __NR_mkdir 83 -#define __NR_rmdir 84 -#define __NR_creat 85 -#define __NR_link 86 -#define __NR_unlink 87 -#define __NR_symlink 88 -#define __NR_readlink 89 -#define __NR_chmod 90 -#define __NR_fchmod 91 -#define __NR_chown 92 -#define __NR_fchown 93 -#define __NR_lchown 94 -#define __NR_umask 95 -#define __NR_gettimeofday 96 -#define __NR_getrlimit 97 -#define __NR_getrusage 98 -#define __NR_sysinfo 99 -#define __NR_times 100 -#define __NR_ptrace 101 -#define __NR_getuid 102 -#define __NR_syslog 103 -#define __NR_getgid 104 -#define __NR_setuid 105 -#define __NR_setgid 106 -#define __NR_geteuid 107 -#define __NR_getegid 108 -#define __NR_setpgid 109 -#define __NR_getppid 110 -#define __NR_getpgrp 111 -#define __NR_setsid 112 -#define __NR_setreuid 113 -#define __NR_setregid 114 -#define __NR_getgroups 115 -#define __NR_setgroups 116 -#define __NR_setresuid 117 -#define __NR_getresuid 118 -#define __NR_setresgid 119 -#define __NR_getresgid 120 -#define __NR_getpgid 121 -#define __NR_setfsuid 122 -#define __NR_setfsgid 123 -#define __NR_getsid 124 -#define __NR_capget 125 -#define __NR_capset 126 -#define __NR_rt_sigpending 127 -#define __NR_rt_sigtimedwait 128 -#define __NR_rt_sigqueueinfo 129 -#define __NR_rt_sigsuspend 130 -#define __NR_sigaltstack 131 -#define __NR_utime 132 -#define __NR_mknod 133 -#define __NR_uselib 134 -#define __NR_personality 135 -#define __NR_ustat 136 -#define __NR_statfs 137 -#define __NR_fstatfs 138 -#define __NR_sysfs 139 -#define __NR_getpriority 140 -#define __NR_setpriority 141 -#define __NR_sched_setparam 142 -#define __NR_sched_getparam 143 -#define __NR_sched_setscheduler 144 -#define __NR_sched_getscheduler 145 -#define __NR_sched_get_priority_max 146 -#define __NR_sched_get_priority_min 147 -#define __NR_sched_rr_get_interval 148 -#define __NR_mlock 149 -#define __NR_munlock 150 -#define __NR_mlockall 151 -#define __NR_munlockall 152 -#define __NR_vhangup 153 -#define __NR_modify_ldt 154 -#define __NR_pivot_root 155 -#define __NR__sysctl 156 -#define __NR_prctl 157 -#define __NR_arch_prctl 158 -#define __NR_adjtimex 159 -#define __NR_setrlimit 160 -#define __NR_chroot 161 -#define __NR_sync 162 -#define __NR_acct 163 -#define __NR_settimeofday 164 -#define __NR_mount 165 -#define __NR_umount2 166 -#define __NR_swapon 167 -#define __NR_swapoff 168 -#define __NR_reboot 169 -#define __NR_sethostname 170 -#define __NR_setdomainname 171 -#define __NR_iopl 172 -#define __NR_ioperm 173 -#define __NR_create_module 174 -#define __NR_init_module 175 -#define __NR_delete_module 176 -#define __NR_get_kernel_syms 177 -#define __NR_query_module 178 -#define __NR_quotactl 179 -#define __NR_nfsservctl 180 -#define __NR_getpmsg 181 -#define __NR_putpmsg 182 -#define __NR_afs_syscall 183 -#define __NR_tuxcall 184 -#define __NR_security 185 -#define __NR_gettid 186 -#define __NR_readahead 187 -#define __NR_setxattr 188 -#define __NR_lsetxattr 189 -#define __NR_fsetxattr 190 -#define __NR_getxattr 191 -#define __NR_lgetxattr 192 -#define __NR_fgetxattr 193 -#define __NR_listxattr 194 -#define __NR_llistxattr 195 -#define __NR_flistxattr 196 -#define __NR_removexattr 197 -#define __NR_lremovexattr 198 -#define __NR_fremovexattr 199 -#define __NR_tkill 200 -#define __NR_time 201 -#define __NR_futex 202 -#define __NR_sched_setaffinity 203 -#define __NR_sched_getaffinity 204 -#define __NR_set_thread_area 205 -#define __NR_io_setup 206 -#define __NR_io_destroy 207 -#define __NR_io_getevents 208 -#define __NR_io_submit 209 -#define __NR_io_cancel 210 -#define __NR_get_thread_area 211 -#define __NR_lookup_dcookie 212 -#define __NR_epoll_create 213 -#define __NR_epoll_ctl_old 214 -#define __NR_epoll_wait_old 215 -#define __NR_remap_file_pages 216 -#define __NR_getdents64 217 -#define __NR_set_tid_address 218 -#define __NR_restart_syscall 219 -#define __NR_semtimedop 220 -#define __NR_fadvise64 221 -#define __NR_timer_create 222 -#define __NR_timer_settime 223 -#define __NR_timer_gettime 224 -#define __NR_timer_getoverrun 225 -#define __NR_timer_delete 226 -#define __NR_clock_settime 227 -#define __NR_clock_gettime 228 -#define __NR_clock_getres 229 -#define __NR_clock_nanosleep 230 -#define __NR_exit_group 231 -#define __NR_epoll_wait 232 -#define __NR_epoll_ctl 233 -#define __NR_tgkill 234 -#define __NR_utimes 235 -#define __NR_vserver 236 -#define __NR_mbind 237 -#define __NR_set_mempolicy 238 -#define __NR_get_mempolicy 239 -#define __NR_mq_open 240 -#define __NR_mq_unlink 241 -#define __NR_mq_timedsend 242 -#define __NR_mq_timedreceive 243 -#define __NR_mq_notify 244 -#define __NR_mq_getsetattr 245 -#define __NR_kexec_load 246 -#define __NR_waitid 247 -#define __NR_add_key 248 -#define __NR_request_key 249 -#define __NR_keyctl 250 -#define __NR_ioprio_set 251 -#define __NR_ioprio_get 252 -#define __NR_inotify_init 253 -#define __NR_inotify_add_watch 254 -#define __NR_inotify_rm_watch 255 -#define __NR_migrate_pages 256 -#define __NR_openat 257 -#define __NR_mkdirat 258 -#define __NR_mknodat 259 -#define __NR_fchownat 260 -#define __NR_futimesat 261 -#define __NR_newfstatat 262 -#define __NR_unlinkat 263 -#define __NR_renameat 264 -#define __NR_linkat 265 -#define __NR_symlinkat 266 -#define __NR_readlinkat 267 -#define __NR_fchmodat 268 -#define __NR_faccessat 269 -#define __NR_pselect6 270 -#define __NR_ppoll 271 -#define __NR_unshare 272 -#define __NR_set_robust_list 273 -#define __NR_get_robust_list 274 -#define __NR_splice 275 -#define __NR_tee 276 -#define __NR_sync_file_range 277 -#define __NR_vmsplice 278 -#define __NR_move_pages 279 -#define __NR_utimensat 280 -#define __NR_epoll_pwait 281 -#define __NR_signalfd 282 -#define __NR_timerfd_create 283 -#define __NR_eventfd 284 -#define __NR_fallocate 285 -#define __NR_timerfd_settime 286 -#define __NR_timerfd_gettime 287 -#define __NR_accept4 288 -#define __NR_signalfd4 289 -#define __NR_eventfd2 290 -#define __NR_epoll_create1 291 -#define __NR_dup3 292 -#define __NR_pipe2 293 -#define __NR_inotify_init1 294 -#define __NR_preadv 295 -#define __NR_pwritev 296 -#define __NR_rt_tgsigqueueinfo 297 -#define __NR_perf_event_open 298 -#define __NR_recvmmsg 299 -#define __NR_fanotify_init 300 -#define __NR_fanotify_mark 301 -#define __NR_prlimit64 302 -#define __NR_name_to_handle_at 303 -#define __NR_open_by_handle_at 304 -#define __NR_clock_adjtime 305 -#define __NR_syncfs 306 -#define __NR_sendmmsg 307 -#define __NR_setns 308 -#define __NR_getcpu 309 -#define __NR_process_vm_readv 310 -#define __NR_process_vm_writev 311 -#define __NR_kcmp 312 -#define __NR_finit_module 313 -#define __NR_sched_setattr 314 -#define __NR_sched_getattr 315 -#define __NR_renameat2 316 -#define __NR_seccomp 317 -#define __NR_getrandom 318 -#define __NR_memfd_create 319 -#define __NR_kexec_file_load 320 -#define __NR_bpf 321 -#define __NR_execveat 322 -#define __NR_userfaultfd 323 -#define __NR_membarrier 324 -#define __NR_mlock2 325 -#define __NR_copy_file_range 326 -#define __NR_preadv2 327 -#define __NR_pwritev2 328 -#define __NR_pkey_mprotect 329 -#define __NR_pkey_alloc 330 -#define __NR_pkey_free 331 -#define __NR_statx 332 -#define __NR_io_pgetevents 333 -#define __NR_rseq 334 -#define __NR_pidfd_send_signal 424 -#define __NR_io_uring_setup 425 -#define __NR_io_uring_enter 426 -#define __NR_io_uring_register 427 -#define __NR_open_tree 428 -#define __NR_move_mount 429 -#define __NR_fsopen 430 -#define __NR_fsconfig 431 -#define __NR_fsmount 432 -#define __NR_fspick 433 -#define __NR_pidfd_open 434 -#define __NR_clone3 435 -#define __NR_close_range 436 -#define __NR_openat2 437 -#define __NR_pidfd_getfd 438 -#define __NR_faccessat2 439 -#define __NR_process_madvise 440 -#define __NR_epoll_pwait2 441 -#define __NR_mount_setattr 442 -#define __NR_landlock_create_ruleset 444 -#define __NR_landlock_add_rule 445 -#define __NR_landlock_restrict_self 446 - -#endif // !__FENNIX_KERNEL_LINUX_SYSCALLS_H__ diff --git a/syscalls/native.cpp b/syscalls/native.cpp index 340d5c1..94a108b 100644 --- a/syscalls/native.cpp +++ b/syscalls/native.cpp @@ -25,7 +25,6 @@ #include "../syscalls.h" #include "../kernel.h" -#include "../ipc.h" struct SyscallData { @@ -34,16 +33,8 @@ struct SyscallData int RequiredID; }; -using InterProcessCommunication::IPC; -using InterProcessCommunication::IPCID; -using Tasking::PCB; -using Tasking::TCB; -using Tasking::TaskState::Ready; -using Tasking::TaskState::Terminated; using namespace Memory; -#define SysFrm SyscallsFrame - #if defined(a64) typedef long arch_t; #elif defined(a32) diff --git a/syscalls/native/close.cpp b/syscalls/native/close.cpp index 8410625..97d083a 100644 --- a/syscalls/native/close.cpp +++ b/syscalls/native/close.cpp @@ -25,23 +25,8 @@ #include "../../syscalls.h" #include "../../kernel.h" -#include "../../ipc.h" -using InterProcessCommunication::IPC; -using InterProcessCommunication::IPCID; using Tasking::PCB; -using Tasking::TCB; -using Tasking::TaskState::Ready; -using Tasking::TaskState::Terminated; -using namespace Memory; - -#define SysFrm SyscallsFrame - -#if defined(a64) -typedef long arch_t; -#elif defined(a32) -typedef int arch_t; -#endif /* https://pubs.opengroup.org/onlinepubs/009604499/functions/close.html */ int sys_close(SysFrm *, diff --git a/syscalls/native/execve.cpp b/syscalls/native/execve.cpp index a1e0ac3..2ee6b93 100644 --- a/syscalls/native/execve.cpp +++ b/syscalls/native/execve.cpp @@ -26,36 +26,22 @@ #include "../../syscalls.h" #include "../../kernel.h" -#include "../../ipc.h" -using InterProcessCommunication::IPC; -using InterProcessCommunication::IPCID; using Tasking::PCB; -using Tasking::TCB; -using Tasking::TaskState::Ready; -using Tasking::TaskState::Terminated; using vfs::RefNode; using namespace Memory; -#define SysFrm SyscallsFrame - -#if defined(a64) -typedef long arch_t; -#elif defined(a32) -typedef int arch_t; -#endif - /* https://pubs.opengroup.org/onlinepubs/9699919799/functions/exec.html */ int sys_execve(SysFrm *Frame, const char *path, char *const argv[], char *const envp[]) { PCB *pcb = thisProcess; - Memory::Virtual vmm(pcb->PageTable); + Virtual vmm = Virtual(pcb->PageTable); if (path == nullptr || - !vmm.Check((void *)path, Memory::US) || - !vmm.Check((void *)argv, Memory::US) || - !vmm.Check((void *)envp, Memory::US)) + !vmm.Check((void *)path, US) || + !vmm.Check((void *)argv, US) || + !vmm.Check((void *)envp, US)) return -ENOENT; const char *safe_path; @@ -65,7 +51,7 @@ int sys_execve(SysFrm *Frame, const char *path, safe_argv = (char **)pcb->vma->RequestPages(TO_PAGES(MAX_ARG)); safe_envp = (char **)pcb->vma->RequestPages(TO_PAGES(MAX_ARG)); { - Memory::SwapPT swap(pcb->PageTable); + SwapPT swap(pcb->PageTable); size_t len = strlen(path); memset((void *)safe_path, 0, PAGE_SIZE); memcpy((void *)safe_path, path, len); @@ -114,7 +100,7 @@ int sys_execve(SysFrm *Frame, const char *path, #endif RefNode *File = fs->Open(safe_path, - pcb->CurrentWorkingDirectory); + pcb->CurrentWorkingDirectory); if (!File) { @@ -193,7 +179,8 @@ int sys_execve(SysFrm *Frame, const char *path, int ret = Execute::Spawn((char *)safe_path, (const char **)safe_argv, (const char **)safe_envp, - pcb->Parent, pcb->Info.Compatibility); + pcb->Parent, true, + pcb->Info.Compatibility); if (ret < 0) { @@ -205,8 +192,8 @@ int sys_execve(SysFrm *Frame, const char *path, delete File; Tasking::Task *ctx = pcb->GetContext(); ctx->Sleep(1000); - pcb->State = Tasking::Zombie; - pcb->ExitCode = 0; + pcb->SetState(Tasking::Zombie); + pcb->SetExitCode(0); /* FIXME: get process exit code */ while (true) ctx->Yield(); __builtin_unreachable(); diff --git a/syscalls/native/exit.cpp b/syscalls/native/exit.cpp index 116a95a..9096ee6 100644 --- a/syscalls/native/exit.cpp +++ b/syscalls/native/exit.cpp @@ -25,23 +25,9 @@ #include "../../syscalls.h" #include "../../kernel.h" -#include "../../ipc.h" -using InterProcessCommunication::IPC; -using InterProcessCommunication::IPCID; -using Tasking::PCB; using Tasking::TCB; -using Tasking::TaskState::Ready; -using Tasking::TaskState::Terminated; -using namespace Memory; - -#define SysFrm SyscallsFrame - -#if defined(a64) -typedef long arch_t; -#elif defined(a32) -typedef int arch_t; -#endif +using Tasking::TaskState::Zombie; /* https://pubs.opengroup.org/onlinepubs/009604499/functions/exit.html */ __noreturn void sys_exit(SysFrm *, int status) @@ -53,9 +39,8 @@ __noreturn void sys_exit(SysFrm *, int status) t->ID, status, status < 0 ? -status : status); - t->ExitCode = status; - t->KeepTime = TimeManager->CalculateTarget(10, Time::Seconds); - t->State = Terminated; + t->SetState(Zombie); + t->SetExitCode(status); while (true) t->GetContext()->Yield(); __builtin_unreachable(); diff --git a/syscalls/native/fork.cpp b/syscalls/native/fork.cpp index 555409b..5602c78 100644 --- a/syscalls/native/fork.cpp +++ b/syscalls/native/fork.cpp @@ -25,23 +25,26 @@ #include "../../syscalls.h" #include "../../kernel.h" -#include "../../ipc.h" -using InterProcessCommunication::IPC; -using InterProcessCommunication::IPCID; using Tasking::PCB; using Tasking::TCB; using Tasking::TaskState::Ready; -using Tasking::TaskState::Terminated; using namespace Memory; -#define SysFrm SyscallsFrame - +void sys_fork_return() +{ #if defined(a64) -typedef long arch_t; + asmv("movq $0, %rax\n"); /* Return 0 */ + asmv("movq %r8, %rsp\n"); /* Restore stack pointer */ + asmv("movq %r8, %rbp\n"); /* Restore base pointer */ + asmv("swapgs\n"); /* Swap GS back to the user GS */ + asmv("sti\n"); /* Enable interrupts */ + asmv("sysretq\n"); /* Return to rcx address in user mode */ #elif defined(a32) -typedef int arch_t; +#warning "sys_fork not implemented for i386" #endif + __builtin_unreachable(); +} /* https://pubs.opengroup.org/onlinepubs/009604499/functions/fork.html */ int sys_fork(SysFrm *Frame) @@ -54,15 +57,11 @@ int sys_fork(SysFrm *Frame) PCB *Parent = thisThread->Parent; TCB *Thread = thisThread; - void *ProcSymTable = nullptr; - if (Parent->ELFSymbolTable) - ProcSymTable = Parent->ELFSymbolTable->GetImage(); - PCB *NewProcess = TaskManager->CreateProcess(Parent, Parent->Name, Parent->Security.ExecutionMode, - ProcSymTable); + nullptr, true); if (!NewProcess) { @@ -70,7 +69,18 @@ int sys_fork(SysFrm *Frame) return -EAGAIN; } - NewProcess->IPC->Fork(Parent->IPC); + if (Parent->ELFSymbolTable && + Parent->ELFSymbolTable->SymTableExists) + { + NewProcess->ELFSymbolTable = new SymbolResolver::Symbols(0); + foreach (auto sym in Parent->ELFSymbolTable->GetSymTable()) + { + NewProcess->ELFSymbolTable->AddSymbol(sym.Address, + sym.FunctionName); + } + } + + NewProcess->PageTable = Parent->PageTable->Fork(); TCB *NewThread = TaskManager->CreateThread(NewProcess, @@ -92,50 +102,30 @@ int sys_fork(SysFrm *Frame) TaskManager->UpdateFrame(); - /* This if statement will overwrite - most of the registers except rcx - and r8-r15 */ - if (thisThread->ID == NewThread->ID) - { - /* We can't just return 0; because the - gsTCB->SyscallStack is no - longer valid */ -#if defined(a64) - asmv("movq $0, %rax\n"); /* Return 0 */ - asmv("movq %r8, %rsp\n"); /* Restore stack pointer */ - asmv("movq %r8, %rbp\n"); /* Restore base pointer */ - asmv("swapgs\n"); /* Swap GS back to the user GS */ - asmv("sti\n"); /* Enable interrupts */ - asmv("sysretq\n"); /* Return to rcx address in user mode */ -#elif defined(a32) -#warning "sys_fork not implemented for i386" -#endif - __builtin_unreachable(); - } - - memcpy(&NewThread->FPU, &Thread->FPU, sizeof(CPU::x64::FXState)); + NewThread->FPU = Thread->FPU; NewThread->Stack->Fork(Thread->Stack); NewThread->Info.Architecture = Thread->Info.Architecture; NewThread->Info.Compatibility = Thread->Info.Compatibility; + NewThread->Security.IsCritical = Thread->Security.IsCritical; NewThread->Registers = Thread->Registers; #if defined(a64) + NewThread->Registers.rip = (uintptr_t)sys_fork_return; /* For sysretq */ NewThread->Registers.rcx = Frame->ReturnAddress; NewThread->Registers.r8 = Frame->StackPointer; #endif - if (Thread->Security.IsCritical) - NewThread->SetCritical(true); - #ifdef a86 NewThread->GSBase = NewThread->ShadowGSBase; NewThread->ShadowGSBase = Thread->ShadowGSBase; NewThread->FSBase = Thread->FSBase; #endif + debug("ret addr: %#lx, stack: %#lx ip: %#lx", Frame->ReturnAddress, + Frame->StackPointer, (uintptr_t)sys_fork_return); debug("Forked thread \"%s\"(%d) to \"%s\"(%d)", Thread->Name, Thread->ID, NewThread->Name, NewThread->ID); - NewThread->State = Ready; + NewThread->SetState(Ready); return (int)NewProcess->ID; } diff --git a/syscalls/native/lseek.cpp b/syscalls/native/lseek.cpp index 9f04625..9380788 100644 --- a/syscalls/native/lseek.cpp +++ b/syscalls/native/lseek.cpp @@ -25,23 +25,8 @@ #include "../../syscalls.h" #include "../../kernel.h" -#include "../../ipc.h" -using InterProcessCommunication::IPC; -using InterProcessCommunication::IPCID; using Tasking::PCB; -using Tasking::TCB; -using Tasking::TaskState::Ready; -using Tasking::TaskState::Terminated; -using namespace Memory; - -#define SysFrm SyscallsFrame - -#if defined(a64) -typedef long arch_t; -#elif defined(a32) -typedef int arch_t; -#endif /* https://pubs.opengroup.org/onlinepubs/009604499/functions/lseek.html */ off_t sys_lseek(SysFrm *, int fildes, diff --git a/syscalls/native/mmap.cpp b/syscalls/native/mmap.cpp index 7ca6dfa..a4123f8 100644 --- a/syscalls/native/mmap.cpp +++ b/syscalls/native/mmap.cpp @@ -24,24 +24,10 @@ #include "../../syscalls.h" #include "../../kernel.h" -#include "../../ipc.h" -using InterProcessCommunication::IPC; -using InterProcessCommunication::IPCID; using Tasking::PCB; -using Tasking::TCB; -using Tasking::TaskState::Ready; -using Tasking::TaskState::Terminated; using namespace Memory; -#define SysFrm SyscallsFrame - -#if defined(a64) -typedef long arch_t; -#elif defined(a32) -typedef int arch_t; -#endif - /* https://pubs.opengroup.org/onlinepubs/009604499/functions/mmap.html */ void *sys_mmap(SysFrm *, void *addr, size_t len, @@ -103,8 +89,8 @@ void *sys_mmap(SysFrm *, (!m_Shared && !m_Private)) return (void *)-EINVAL; - Tasking::PCB *pcb = thisProcess; - Memory::VirtualMemoryArea *vma = pcb->vma; + PCB *pcb = thisProcess; + VirtualMemoryArea *vma = pcb->vma; intptr_t ret = (intptr_t)vma->CreateCoWRegion(addr, len, p_Read, p_Write, p_Exec, m_Fixed, m_Shared); diff --git a/syscalls/native/mprotect.cpp b/syscalls/native/mprotect.cpp index fb42d97..939ee71 100644 --- a/syscalls/native/mprotect.cpp +++ b/syscalls/native/mprotect.cpp @@ -25,24 +25,10 @@ #include "../../syscalls.h" #include "../../kernel.h" -#include "../../ipc.h" -using InterProcessCommunication::IPC; -using InterProcessCommunication::IPCID; using Tasking::PCB; -using Tasking::TCB; -using Tasking::TaskState::Ready; -using Tasking::TaskState::Terminated; using namespace Memory; -#define SysFrm SyscallsFrame - -#if defined(a64) -typedef long arch_t; -#elif defined(a32) -typedef int arch_t; -#endif - /* https://pubs.opengroup.org/onlinepubs/009604499/functions/mprotect.html */ int sys_mprotect(SysFrm *, void *addr, size_t len, int prot) @@ -58,16 +44,16 @@ int sys_mprotect(SysFrm *, bool p_Write = prot & sc_PROT_WRITE; // bool p_Exec = prot & sc_PROT_EXEC; - Tasking::PCB *pcb = thisProcess; - Memory::Virtual vmm = Memory::Virtual(pcb->PageTable); + PCB *pcb = thisProcess; + Virtual vmm = Virtual(pcb->PageTable); for (uintptr_t i = uintptr_t(addr); i < uintptr_t(addr) + len; i += PAGE_SIZE) { - if (likely(!vmm.Check((void *)i, Memory::G))) + if (likely(!vmm.Check((void *)i, G))) { - Memory::PageTableEntry *pte = vmm.GetPTE(addr); + PageTableEntry *pte = vmm.GetPTE(addr); if (!pte->Present || (!pte->UserSupervisor && p_Read) || (!pte->ReadWrite && p_Write)) diff --git a/syscalls/native/munmap.cpp b/syscalls/native/munmap.cpp index f5ab1d3..3c77155 100644 --- a/syscalls/native/munmap.cpp +++ b/syscalls/native/munmap.cpp @@ -25,24 +25,10 @@ #include "../../syscalls.h" #include "../../kernel.h" -#include "../../ipc.h" -using InterProcessCommunication::IPC; -using InterProcessCommunication::IPCID; using Tasking::PCB; -using Tasking::TCB; -using Tasking::TaskState::Ready; -using Tasking::TaskState::Terminated; using namespace Memory; -#define SysFrm SyscallsFrame - -#if defined(a64) -typedef long arch_t; -#elif defined(a32) -typedef int arch_t; -#endif - /* https://pubs.opengroup.org/onlinepubs/009604499/functions/munmap.html */ int sys_munmap(SysFrm *, void *addr, size_t len) @@ -53,16 +39,16 @@ int sys_munmap(SysFrm *, if (len == 0) return -EINVAL; - Tasking::PCB *pcb = thisProcess; - Memory::VirtualMemoryArea *vma = pcb->vma; - Memory::Virtual vmm = Memory::Virtual(pcb->PageTable); + PCB *pcb = thisProcess; + VirtualMemoryArea *vma = pcb->vma; + Virtual vmm = Virtual(pcb->PageTable); for (uintptr_t i = uintptr_t(addr); i < uintptr_t(addr) + len; i += PAGE_SIZE) { - if (likely(!vmm.Check((void *)i, Memory::G))) - vmm.Remap((void *)i, (void *)i, Memory::P | Memory::RW); + if (likely(!vmm.Check((void *)i, G))) + vmm.Remap((void *)i, (void *)i, P | RW); else warn("%p is a global page", (void *)i); } diff --git a/syscalls/native/open.cpp b/syscalls/native/open.cpp index 99d67f7..f38f6f3 100644 --- a/syscalls/native/open.cpp +++ b/syscalls/native/open.cpp @@ -25,37 +25,23 @@ #include "../../syscalls.h" #include "../../kernel.h" -#include "../../ipc.h" -using InterProcessCommunication::IPC; -using InterProcessCommunication::IPCID; using Tasking::PCB; -using Tasking::TCB; -using Tasking::TaskState::Ready; -using Tasking::TaskState::Terminated; using namespace Memory; -#define SysFrm SyscallsFrame - -#if defined(a64) -typedef long arch_t; -#elif defined(a32) -typedef int arch_t; -#endif - /* https://pubs.opengroup.org/onlinepubs/009604499/functions/open.html */ int sys_open(SysFrm *, const char *path, int oflag, mode_t mode) { const char *safe_path = nullptr; - Tasking::PCB *pcb = thisProcess; - Memory::SmartHeap sh(512, pcb->vma); + PCB *pcb = thisProcess; + SmartHeap sh(512, pcb->vma); safe_path = (const char *)sh.Get(); { - Memory::SwapPT swap(pcb->PageTable); + SwapPT swap(pcb->PageTable); size_t len = strlen(path); - memcpy((void *)safe_path, path, len); + memcpy((void *)safe_path, path, MAX(len, size_t(511))); } function("%s, %d, %d", safe_path, oflag, mode); diff --git a/syscalls/native/read.cpp b/syscalls/native/read.cpp index 109ef28..50c76a3 100644 --- a/syscalls/native/read.cpp +++ b/syscalls/native/read.cpp @@ -25,31 +25,17 @@ #include "../../syscalls.h" #include "../../kernel.h" -#include "../../ipc.h" -using InterProcessCommunication::IPC; -using InterProcessCommunication::IPCID; using Tasking::PCB; -using Tasking::TCB; -using Tasking::TaskState::Ready; -using Tasking::TaskState::Terminated; using namespace Memory; -#define SysFrm SyscallsFrame - -#if defined(a64) -typedef long arch_t; -#elif defined(a32) -typedef int arch_t; -#endif - /* https://pubs.opengroup.org/onlinepubs/009604499/functions/read.html */ ssize_t sys_read(SysFrm *, int fildes, void *buf, size_t nbyte) { void *safe_buf = nullptr; - Tasking::PCB *pcb = thisProcess; - Memory::SmartHeap sh(nbyte, pcb->vma); + PCB *pcb = thisProcess; + SmartHeap sh(nbyte, pcb->vma); safe_buf = sh.Get(); function("%d, %p, %d", fildes, buf, nbyte); @@ -61,7 +47,7 @@ ssize_t sys_read(SysFrm *, int fildes, return ret; { - Memory::SwapPT swap(pcb->PageTable); + SwapPT swap(pcb->PageTable); memcpy(buf, safe_buf, nbyte); } return ret; diff --git a/syscalls/native/readlink.cpp b/syscalls/native/readlink.cpp new file mode 100644 index 0000000..a3eb8c3 --- /dev/null +++ b/syscalls/native/readlink.cpp @@ -0,0 +1,81 @@ +/* + 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 "../../syscalls.h" +#include "../../kernel.h" + +using Tasking::PCB; +using namespace Memory; + +/* https://pubs.opengroup.org/onlinepubs/9699919799/functions/readlink.html */ +ssize_t sys_readlink(SysFrm *, const char *path, char *buf, + size_t bufsize) +{ + if (!path || !buf) + return -EINVAL; + + if (bufsize > PAGE_SIZE) + { + warn("bufsize is too large: %ld", bufsize); + return -EINVAL; + } + + PCB *pcb = thisProcess; + Memory::Virtual vmm(pcb->PageTable); + if (!vmm.Check((void *)buf, Memory::US)) + { + warn("Invalid address %#lx", buf); + return -EFAULT; + } + + const char *pPath = pcb->PageTable->Get(path); + char *pBuf = pcb->PageTable->Get(buf); + function("%s %#lx %ld", pPath, buf, bufsize); + vfs::FileDescriptorTable *fdt = pcb->FileDescriptors; + int fd = fdt->_open(pPath, O_RDONLY, 0); + if (fd < 0) + return -ENOENT; + + vfs::FileDescriptorTable::Fildes fildes = fdt->GetDescriptor(fd); + vfs::Node *node = fildes.Handle->node; + fdt->_close(fd); + + if (node->Type != vfs::NodeType::SYMLINK) + return -EINVAL; + + if (!node->Symlink) + { + warn("Symlink null for \"%s\"?", pPath); + return -EINVAL; + } + + size_t len = strlen(node->Symlink); + if (len > bufsize) + len = bufsize; + + strncpy(pBuf, node->Symlink, len); + return len; +} diff --git a/syscalls/native/uname.cpp b/syscalls/native/uname.cpp new file mode 100644 index 0000000..1caba73 --- /dev/null +++ b/syscalls/native/uname.cpp @@ -0,0 +1,69 @@ +/* + 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 "../../syscalls.h" +#include "../../kernel.h" + +using Tasking::PCB; +using namespace Memory; + +/* https://pubs.opengroup.org/onlinepubs/9699919799/functions/uname.html */ +int sys_uname(SysFrm *, struct utsname *buf) +{ + assert(sizeof(struct utsname) < PAGE_SIZE); + + Tasking::PCB *pcb = thisProcess; + Memory::Virtual vmm(pcb->PageTable); + + if (!vmm.Check(buf, Memory::US)) + { + warn("Invalid address %#lx", buf); + return -EFAULT; + } + + auto pBuf = pcb->PageTable->Get(buf); + + struct utsname uname = + { + /* TODO: This shouldn't be hardcoded */ + .sysname = KERNEL_NAME, + .nodename = "fennix", + .release = KERNEL_VERSION, + .version = KERNEL_VERSION, +#if defined(a64) + .machine = "x86_64", +#elif defined(a32) + .machine = "i386", +#elif defined(aa64) + .machine = "arm64", +#elif defined(aa32) + .machine = "arm", +#endif + }; + + memcpy(pBuf, &uname, sizeof(struct utsname)); + return 0; +} diff --git a/syscalls/native/write.cpp b/syscalls/native/write.cpp index 7c446aa..f531f4b 100644 --- a/syscalls/native/write.cpp +++ b/syscalls/native/write.cpp @@ -25,34 +25,20 @@ #include "../../syscalls.h" #include "../../kernel.h" -#include "../../ipc.h" -using InterProcessCommunication::IPC; -using InterProcessCommunication::IPCID; using Tasking::PCB; -using Tasking::TCB; -using Tasking::TaskState::Ready; -using Tasking::TaskState::Terminated; using namespace Memory; -#define SysFrm SyscallsFrame - -#if defined(a64) -typedef long arch_t; -#elif defined(a32) -typedef int arch_t; -#endif - /* https://pubs.opengroup.org/onlinepubs/009604499/functions/write.html */ ssize_t sys_write(SysFrm *, int fildes, const void *buf, size_t nbyte) { const void *safe_buf = nullptr; - Tasking::PCB *pcb = thisProcess; - Memory::SmartHeap sh(nbyte, pcb->vma); + PCB *pcb = thisProcess; + SmartHeap sh(nbyte, pcb->vma); safe_buf = sh.Get(); { - Memory::SwapPT swap(pcb->PageTable); + SwapPT swap(pcb->PageTable); memcpy((void *)safe_buf, buf, nbyte); } diff --git a/syscalls/syscalls.cpp b/syscalls/syscalls.cpp index d077a57..1aa57a9 100644 --- a/syscalls/syscalls.cpp +++ b/syscalls/syscalls.cpp @@ -24,7 +24,7 @@ class AutoSwitchPageTable { private: - uintptr_t Original; + void *Original; public: AutoSwitchPageTable() @@ -37,10 +37,14 @@ public: : : "r"(KernelPageTable)); #endif + debug(" + %#lx %s(%d)", Original, + thisProcess->Name, thisProcess->ID); } ~AutoSwitchPageTable() { + debug("- %#lx %s(%d)", Original, + thisProcess->Name, thisProcess->ID); #if defined(a86) asmv("mov %0, %%cr3" : diff --git a/tasking/ipc.cpp b/tasking/ipc.cpp deleted file mode 100644 index f00cd66..0000000 --- a/tasking/ipc.cpp +++ /dev/null @@ -1,277 +0,0 @@ -/* - This file is part of Fennix Kernel. - - Fennix Kernel is free software: you can redistribute it and/or - modify it under the terms of the GNU General Public License as - published by the Free Software Foundation, either version 3 of - the License, or (at your option) any later version. - - Fennix Kernel is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Fennix Kernel. If not, see . -*/ - -#include - -#include - -#include "../kernel.h" -#include "../ipc.h" - -namespace InterProcessCommunication -{ - void IPC::Fork(IPC *Parent) - { - std::vector ParentHandles = Parent->GetHandles(); - - foreach (auto Hnd in ParentHandles) - { - debug("Forking IPC with ID %d", Hnd->ID); - IPCHandle *NewHnd = (IPCHandle *)vma->RequestPages(TO_PAGES(sizeof(IPCHandle) + 1)); - memcpy(NewHnd, Hnd, sizeof(IPCHandle)); - NewHnd->Node = fs->Create(Hnd->Node->Name, vfs::NodeType::FILE, IPCNode); - Handles.push_back(NewHnd); - } - } - - IPCHandle *IPC::Create(IPCType Type, char UniqueToken[16]) - { - UNUSED(Type); - SmartLock(this->IPCLock); - IPCHandle *Hnd = (IPCHandle *)vma->RequestPages(TO_PAGES(sizeof(IPCHandle) + 1)); - - Hnd->ID = NextID++; - Hnd->Node = fs->Create(UniqueToken, vfs::NodeType::FILE, IPCNode); - Hnd->Buffer = nullptr; - Hnd->Length = 0; - Hnd->Listening = false; - - Handles.push_back(Hnd); - debug("Created IPC with ID %d", Hnd->ID); - return Hnd; - } - - IPCErrorCode IPC::Destroy(IPCID ID) - { - SmartLock(this->IPCLock); - forItr(itr, Handles) - { - if ((*itr)->ID == ID) - { - fs->Delete((*itr)->Node); - vma->FreePages((*itr), TO_PAGES(sizeof(IPCHandle) + 1)); - Handles.erase(itr); - debug("Destroyed IPC with ID %d", ID); - return IPCSuccess; - } - } - - debug("Failed to destroy IPC with ID %d", ID); - return IPCIDNotFound; - } - - IPCErrorCode IPC::Allocate(IPCID ID, long Size) - { - SmartLock(this->IPCLock); - if (Size < 0) - return IPCError; - - foreach (auto Hnd in Handles) - { - if (Hnd->ID == ID) - { - if (Hnd->Buffer != nullptr || Hnd->Length != 0) - return IPCAlreadyAllocated; - - Hnd->Buffer = (uint8_t *)vma->RequestPages(TO_PAGES(Size + 1)); - Hnd->Length = Size; - return IPCSuccess; - } - } - return IPCIDNotFound; - } - - IPCErrorCode IPC::Deallocate(IPCID ID) - { - SmartLock(this->IPCLock); - foreach (auto Hnd in Handles) - { - if (Hnd->ID == ID) - { - if (Hnd->Buffer == nullptr || Hnd->Length == 0) - return IPCNotAllocated; - - vma->FreePages(Hnd->Buffer, TO_PAGES(Hnd->Length + 1)); - Hnd->Buffer = nullptr; - Hnd->Length = 0; - return IPCSuccess; - } - } - return IPCIDNotFound; - } - - IPCErrorCode IPC::Read(IPCID ID, void *Buffer, long Size) - { - SmartLock(this->IPCLock); - if (Size < 0) - return IPCError; - - foreach (auto Hnd in Handles) - { - if (Hnd->ID == ID) - { - if (Hnd->Listening) - { - debug("IPC %d is listening", ID); - return IPCNotListening; - } - if (Hnd->Length < Size) - { - debug("IPC %d is too small", ID); - return IPCError; - } - debug("IPC %d reading %d bytes", ID, Size); - memcpy(Buffer, Hnd->Buffer, Size); - debug("IPC read %d bytes", Size); - return IPCSuccess; - } - } - debug("IPC %d not found", ID); - return IPCIDNotFound; - } - - IPCErrorCode IPC::Write(IPCID ID, void *Buffer, long Size) - { - SmartLock(this->IPCLock); - if (Size < 0) - { - debug("IPC %d is too small", ID); - return IPCError; - } - - foreach (auto Hnd in Handles) - { - if (Hnd->ID == ID) - { - if (!Hnd->Listening) - { - debug("IPC %d is NOT listening", ID); - return IPCNotListening; - } - if (Hnd->Length < Size) - { - debug("IPC %d is too small", ID); - return IPCError; - } - debug("IPC %d writing %d bytes", ID, Size); - memcpy(Hnd->Buffer, Buffer, Size); - Hnd->Listening = false; - debug("IPC %d wrote %d bytes and now is %s", ID, Size, Hnd->Listening ? "listening" : "ready"); - return IPCSuccess; - } - } - debug("IPC %d not found", ID); - return IPCIDNotFound; - } - - IPCErrorCode IPC::Listen(IPCID ID, bool Listen) - { - foreach (auto Hnd in Handles) - { - if (Hnd->ID == ID) - { - Hnd->Listening = Listen; - debug("IPC %d is now set to %s", ID, Listen ? "listening" : "ready"); - return IPCSuccess; - } - } - debug("IPC %d not found", ID); - return IPCIDNotFound; - } - - IPCErrorCode IPC::Wait(IPCID ID) - { - foreach (auto Hnd in Handles) - { - if (Hnd->ID == ID) - { - if (!CPU::Interrupts()) - warn("Interrupts are disabled. This may cause a kernel hang."); - debug("Waiting for IPC %d (now %s)", ID, Hnd->Listening ? "listening" : "ready"); - while (Hnd->Listening) - TaskManager->Yield(); - debug("IPC %d is ready", ID); - return IPCSuccess; - } - } - debug("IPC %d not found", ID); - return IPCIDNotFound; - } - - IPCHandle *IPC::SearchByToken(char UniqueToken[16]) - { - foreach (auto Hnd in Handles) - { - if (strcmp(Hnd->Node->Name, UniqueToken) == 0) - { - debug("Found IPC with token %s", UniqueToken); - return Hnd; - } - } - debug("Failed to find IPC with token %s", UniqueToken); - return nullptr; - } - - int IPC::HandleSyscall(long Command, long Type, int ID, int Flags, void *Buffer, size_t Size) - { - switch (Command) - { - case IPC_CREATE: - { - char UniqueToken[16]; - if (Buffer != nullptr) - strcpy(UniqueToken, (char *)Buffer); - else - snprintf(UniqueToken, 16, "IPC_%d", ID); - IPCHandle *Hnd = this->Create((IPCType)Type, UniqueToken); - this->Allocate(Hnd->ID, Size ? Size : PAGE_SIZE); - return Hnd->ID; - } - case IPC_READ: - return this->Read(ID, Buffer, Size); - case IPC_WRITE: - return TaskManager->GetProcessByID(Flags)->IPC->Write(ID, Buffer, Size); - case IPC_DELETE: - { - this->Deallocate(ID); - return this->Destroy(ID); - } - case IPC_WAIT: - return this->Wait(ID); - case IPC_LISTEN: - return this->Listen(ID, Flags); - default: - return IPCInvalidCommand; - } - return IPCError; - } - - IPC::IPC(void *Process) - { - Tasking::PCB *pcb = (Tasking::PCB *)Process; - this->Process = Process; - this->vma = new Memory::VirtualMemoryArea(pcb->PageTable); - IPCNode = fs->Create("ipc", vfs::NodeType::DIRECTORY, - pcb->ProcessDirectory); - } - - IPC::~IPC() - { - fs->Delete(IPCNode, true); - delete this->vma, this->vma = nullptr; - } -} diff --git a/tasking/process.cpp b/tasking/process.cpp index da0b513..2941d81 100644 --- a/tasking/process.cpp +++ b/tasking/process.cpp @@ -44,12 +44,29 @@ #define tskdbg(m, ...) #endif -using namespace InterProcessCommunication; using namespace vfs; -using vfs::NodeType; namespace Tasking { + int PCB::SendSignal(int sig) + { + return this->Signals->SendSignal(sig); + } + + void PCB::SetState(TaskState state) + { + this->State.store(state); + if (this->Threads.size() == 1) + this->Threads.front()->State.store(state); + } + + void PCB::SetExitCode(int code) + { + this->ExitCode.store(code); + if (this->Threads.size() == 1) + this->Threads.front()->ExitCode.store(code); + } + void PCB::Rename(const char *name) { assert(name != nullptr); @@ -74,6 +91,25 @@ namespace Tasking trace("Setting working directory of process %s to %#lx (%s)", this->Name, node, node->Name); CurrentWorkingDirectory = node; + Node *cwd = fs->GetNodeFromPath("cwd", this); + if (cwd) + delete cwd; + cwd = fs->CreateLink("cwd", node->FullPath, this); + if (cwd == nullptr) + error("Failed to create cwd link"); + } + + void PCB::SetExe(const char *path) + { + trace("Setting exe %s to %s", + this->Name, path); + Executable = fs->GetNodeFromPath(path); + Node *exe = fs->GetNodeFromPath("exe", this); + if (exe) + delete exe; + exe = fs->CreateLink("exe", Executable->FullPath, this); + if (exe == nullptr) + error("Failed to create exe link"); } size_t PCB::GetSize() @@ -92,11 +128,12 @@ namespace Tasking PCB::PCB(Task *ctx, PCB *Parent, const char *Name, TaskExecutionMode ExecutionMode, void *Image, - bool DoNotCreatePageTable, + bool UseKernelPageTable, uint16_t UserID, uint16_t GroupID) + : Node(ProcFS, std::to_string(ctx->NextPID), NodeType::DIRECTORY) { debug("+ %#lx", this); - + assert(ctx != nullptr); assert(Name != nullptr); assert(strlen(Name) > 0); @@ -154,36 +191,25 @@ namespace Tasking assert(false); } - char ProcFSName[12]; - sprintf(ProcFSName, "%d", this->ID); - this->ProcessDirectory = fs->Create(ProcFSName, DIRECTORY, ProcFS); this->FileDescriptors = new FileDescriptorTable(this); /* If create page table */ - if (DoNotCreatePageTable == false) + if (UseKernelPageTable == false) { OwnPageTable = true; - - size_t PTPgs = TO_PAGES(sizeof(Memory::PageTable) + 1); - this->PageTable = (Memory::PageTable *)KernelAllocator.RequestPages(PTPgs); - memcpy(this->PageTable, KernelPageTable, sizeof(Memory::PageTable)); - + this->PageTable = KernelPageTable->Fork(); debug("Process %s(%d) has page table at %#lx", this->Name, this->ID, this->PageTable); } + else + this->PageTable = KernelPageTable; this->vma = new Memory::VirtualMemoryArea(this->PageTable); this->ProgramBreak = new Memory::ProgramBreak(this->PageTable, this->vma); - this->IPC = new class IPC((void *)this); + this->Signals = new Signal(this); if (Image) - { this->ELFSymbolTable = new SymbolResolver::Symbols((uintptr_t)Image); - this->AllocatedMemory += sizeof(SymbolResolver::Symbols); - } - - if (Parent) - Parent->Children.push_back(this); debug("Process page table: %#lx", this->PageTable); debug("Created %s process \"%s\"(%d). Parent \"%s\"(%d)", @@ -198,9 +224,13 @@ namespace Tasking this->AllocatedMemory += FROM_PAGES(TO_PAGES(sizeof(Memory::PageTable) + 1)); this->AllocatedMemory += sizeof(Memory::VirtualMemoryArea); this->AllocatedMemory += sizeof(Memory::ProgramBreak); - this->AllocatedMemory += sizeof(class IPC); + this->AllocatedMemory += sizeof(SymbolResolver::Symbols); + this->AllocatedMemory += sizeof(Signal); this->Info.SpawnTime = TimeManager->GetCounter(); + + if (Parent) + Parent->Children.push_back(this); ctx->ProcessList.push_back(this); } @@ -221,8 +251,8 @@ namespace Tasking if (this->ELFSymbolTable) delete this->ELFSymbolTable; - debug("Freeing IPC"); - delete this->IPC; + debug("Freeing signals"); + delete this->Signals; debug("Freeing allocated memory"); delete this->ProgramBreak; @@ -242,14 +272,31 @@ namespace Tasking /* Exit all children processes */ foreach (auto pcb in this->Children) + { + if (pcb == nullptr) + { + warn("Process is null? Kernel bug"); + continue; + } + + debug("Destroying child process \"%s\"(%d)", + pcb->Name, pcb->ID); delete pcb; + } /* Exit all threads */ foreach (auto tcb in this->Threads) - delete tcb; + { + if (tcb == nullptr) + { + warn("Thread is null? Kernel bug"); + continue; + } - debug("Removing /proc/%d", this->ID); - fs->Delete(this->ProcessDirectory, true); + debug("Destroying thread \"%s\"(%d)", + tcb->Name, tcb->ID); + delete tcb; + } /* Free Name */ delete[] this->Name; @@ -257,11 +304,14 @@ namespace Tasking debug("Removing from parent process"); if (this->Parent) { - std::vector &pChild = this->Parent->Children; + std::list &pChild = this->Parent->Children; pChild.erase(std::find(pChild.begin(), pChild.end(), this)); } + + debug("Process \"%s\"(%d) destroyed", + this->Name, this->ID); } } diff --git a/tasking/scheduler.cpp b/tasking/scheduler.cpp index 1a990a2..a39db10 100644 --- a/tasking/scheduler.cpp +++ b/tasking/scheduler.cpp @@ -110,6 +110,12 @@ extern "C" SafeFunction NIF void TaskingScheduler_OneShot(int TimeSlice) { if (TimeSlice == 0) TimeSlice = Tasking::TaskPriority::Normal; + +#ifdef DEBUG + if (DebuggerIsAttached) + TimeSlice += 10; +#endif + #if defined(a86) ((APIC::Timer *)Interrupts::apicTimer[GetCurrentCPU()->ID])->OneShot(CPU::x86::IRQ16, TimeSlice); #elif defined(aa64) @@ -348,13 +354,16 @@ namespace Tasking if (process->Threads.size() == 1) { - process->State.exchange(process->Threads[0]->State.load()); + process->State.exchange(process->Threads.front()->State.load()); continue; } bool AllThreadsSleeping = true; foreach (auto thread in process->Threads) { + if (thread->State.load() == TaskState::Terminated) + continue; + if (thread->State.load() != TaskState::Sleeping) { AllThreadsSleeping = false; @@ -409,6 +418,24 @@ namespace Tasking } } + SafeFunction NIF void Task::CleanupTerminated() + { + foreach (auto pcb in ProcessList) + { + if (pcb->State.load() == TaskState::Terminated) + { + delete pcb; + continue; + } + + foreach (TCB *tcb in pcb->Threads) + { + if (tcb->State == Terminated) + delete tcb; + } + } + } + #ifdef ON_SCREEN_SCHEDULER_TASK_MANAGER int SuccessSource = 0; int sanity; @@ -434,6 +461,7 @@ namespace Tasking "Block", "Wait", + "Core", "Zombie", "Terminated", }; @@ -485,11 +513,7 @@ namespace Tasking } #endif -#ifdef a64 - SafeFunction NIF void Task::Schedule(CPU::x64::TrapFrame *Frame) -#else - SafeFunction NIF void Task::Schedule(CPU::x32::TrapFrame *Frame) -#endif + SafeFunction NIF void Task::Schedule(CPU::TrapFrame *Frame) { if (unlikely(StopScheduler)) { @@ -497,43 +521,15 @@ namespace Tasking return; } bool ProcessNotChanged = false; -/* Restore kernel page table for safety reasons. */ -#ifdef a64 - CPU::x64::writecr3({.raw = (uint64_t)KernelPageTable}); -#else - CPU::x32::writecr3({.raw = (uint32_t)KernelPageTable}); -#endif + /* Restore kernel page table for safety reasons. */ + if (!SchedulerUpdateTrapFrame) + KernelPageTable->Update(); uint64_t SchedTmpTicks = TimeManager->GetCounter(); this->LastTaskTicks.store(size_t(SchedTmpTicks - this->SchedulerTicks.load())); CPUData *CurrentCPU = GetCurrentCPU(); this->LastCore.store(CurrentCPU->ID); schedbg("Scheduler called on CPU %d.", CurrentCPU->ID); -#ifdef DEBUG_SCHEDULER - { - schedbg("================================================================"); - schedbg("State: 0-ukn | 1-rdy | 2-run | 3-wait | 4-term"); - schedbg("Technical Informations on regs %#lx", Frame->InterruptNumber); - size_t ds; - asmv("mov %%ds, %0" - : "=r"(ds)); - schedbg("FS=%#lx GS=%#lx SS=%#lx CS=%#lx DS=%#lx", - CPU::x64::rdmsr(CPU::x64::MSR_FS_BASE), CPU::x64::rdmsr(CPU::x64::MSR_GS_BASE), - Frame->ss, Frame->cs, ds); - schedbg("R8=%#lx R9=%#lx R10=%#lx R11=%#lx", - Frame->r8, Frame->r9, Frame->r10, Frame->r11); - schedbg("R12=%#lx R13=%#lx R14=%#lx R15=%#lx", - Frame->r12, Frame->r13, Frame->r14, Frame->r15); - schedbg("RAX=%#lx RBX=%#lx RCX=%#lx RDX=%#lx", - Frame->rax, Frame->rbx, Frame->rcx, Frame->rdx); - schedbg("RSI=%#lx RDI=%#lx RBP=%#lx RSP=%#lx", - Frame->rsi, Frame->rdi, Frame->rbp, Frame->rsp); - schedbg("RIP=%#lx RFL=%#lx INT=%#lx ERR=%#lx", - Frame->rip, Frame->rflags, Frame->InterruptNumber, Frame->ErrorCode); - schedbg("================================================================"); - } -#endif - if (unlikely(InvalidPCB(CurrentCPU->CurrentProcess.load()) || InvalidTCB(CurrentCPU->CurrentThread.load()))) { @@ -563,6 +559,9 @@ namespace Tasking if (CurrentCPU->CurrentThread->State.load() == TaskState::Running) CurrentCPU->CurrentThread->State.store(TaskState::Ready); + this->CleanupTerminated(); + schedbg("Passed CleanupTerminated"); + this->UpdateProcessState(); schedbg("Passed UpdateProcessState"); @@ -571,8 +570,13 @@ namespace Tasking if (this->SchedulerUpdateTrapFrame) { + debug("Updating trap frame"); this->SchedulerUpdateTrapFrame = false; - goto Success; + CurrentCPU->CurrentProcess->State.store(TaskState::Running); + CurrentCPU->CurrentThread->State.store(TaskState::Running); + *Frame = CurrentCPU->CurrentThread->Registers; + this->SchedulerTicks.store(size_t(TimeManager->GetCounter() - SchedTmpTicks)); + return; } if (this->GetNextAvailableThread(CurrentCPU)) @@ -637,20 +641,13 @@ namespace Tasking *Frame = CurrentCPU->CurrentThread->Registers; - for (size_t i = 0; i < (sizeof(CurrentCPU->CurrentThread->IPHistory) / sizeof(CurrentCPU->CurrentThread->IPHistory[0])) - 1; i++) - CurrentCPU->CurrentThread->IPHistory[i + 1] = CurrentCPU->CurrentThread->IPHistory[i]; - #ifdef a64 - CurrentCPU->CurrentThread->IPHistory[0] = Frame->rip; - GlobalDescriptorTable::SetKernelStack((void *)((uintptr_t)CurrentCPU->CurrentThread->Stack->GetStackTop())); CPU::x64::fxrstor(&CurrentCPU->CurrentThread->FPU); CPU::x64::wrmsr(CPU::x64::MSR_SHADOW_GS_BASE, CurrentCPU->CurrentThread->ShadowGSBase); CPU::x64::wrmsr(CPU::x64::MSR_GS_BASE, CurrentCPU->CurrentThread->GSBase); CPU::x64::wrmsr(CPU::x64::MSR_FS_BASE, CurrentCPU->CurrentThread->FSBase); #else - CurrentCPU->CurrentThread->IPHistory[0] = Frame->eip; - GlobalDescriptorTable::SetKernelStack((void *)((uintptr_t)CurrentCPU->CurrentThread->Stack->GetStackTop())); CPU::x32::fxrstor(&CurrentCPU->CurrentThread->FPU); CPU::x32::wrmsr(CPU::x32::MSR_SHADOW_GS_BASE, CurrentCPU->CurrentThread->ShadowGSBase); @@ -658,6 +655,8 @@ namespace Tasking CPU::x32::wrmsr(CPU::x32::MSR_FS_BASE, CurrentCPU->CurrentThread->FSBase); #endif + CurrentCPU->CurrentProcess->Signals->HandleSignal(Frame); + #ifdef ON_SCREEN_SCHEDULER_TASK_MANAGER OnScreenTaskManagerUpdate(); #endif @@ -682,7 +681,8 @@ namespace Tasking (&CurrentCPU->CurrentThread->Info)->LastUpdateTime = TimeManager->GetCounter(); TaskingScheduler_OneShot(CurrentCPU->CurrentThread->Info.Priority); - if (CurrentCPU->CurrentThread->Security.IsDebugEnabled && CurrentCPU->CurrentThread->Security.IsKernelDebugEnabled) + if (CurrentCPU->CurrentThread->Security.IsDebugEnabled && + CurrentCPU->CurrentThread->Security.IsKernelDebugEnabled) { #ifdef a64 trace("%s[%ld]: RIP=%#lx RBP=%#lx RSP=%#lx", @@ -722,18 +722,10 @@ namespace Tasking End: this->SchedulerTicks.store(size_t(TimeManager->GetCounter() - SchedTmpTicks)); -#ifdef a64 - CPU::x64::writecr3({.raw = (uint64_t)CurrentCPU->CurrentProcess->PageTable}); -#else - CPU::x32::writecr3({.raw = (uint64_t)CurrentCPU->CurrentProcess->PageTable}); -#endif + CurrentCPU->CurrentProcess->PageTable->Update(); } -#ifdef a64 - SafeFunction NIF void Task::OnInterruptReceived(CPU::x64::TrapFrame *Frame) -#else - SafeFunction NIF void Task::OnInterruptReceived(CPU::x32::TrapFrame *Frame) -#endif + SafeFunction NIF void Task::OnInterruptReceived(CPU::TrapFrame *Frame) { SmartCriticalSection(SchedulerLock); this->Schedule(Frame); @@ -759,11 +751,11 @@ namespace Tasking fixme("unimplemented"); } - SafeFunction void Task::Schedule(CPU::aarch64::TrapFrame *Frame) + SafeFunction void Task::Schedule(CPU::TrapFrame *Frame) { fixme("unimplemented"); } - SafeFunction void Task::OnInterruptReceived(CPU::aarch64::TrapFrame *Frame) { this->Schedule(Frame); } + SafeFunction void Task::OnInterruptReceived(CPU::TrapFrame *Frame) { this->Schedule(Frame); } #endif } diff --git a/tasking/signal.cpp b/tasking/signal.cpp new file mode 100644 index 0000000..cebe0a4 --- /dev/null +++ b/tasking/signal.cpp @@ -0,0 +1,732 @@ +/* + 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 + +#if defined(a64) +#include "../arch/amd64/cpu/gdt.hpp" +#elif defined(a32) +#include "../arch/i386/cpu/gdt.hpp" +#elif defined(aa64) +#endif + +#include "../kernel.h" + +#ifdef DEBUG +const char *lSigStr[] = { + "SIGHUP", + "SIGINT", + "SIGQUIT", + "SIGILL", + "SIGTRAP", + "SIGABRT", + "SIGBUS", + "SIGFPE", + "SIGKILL", + "SIGUSR1", + "SIGSEGV", + "SIGUSR2", + "SIGPIPE", + "SIGALRM", + "SIGTERM", + "SIGSTKFLT", + "SIGCHLD", + "SIGCONT", + "SIGSTOP", + "SIGTSTP", + "SIGTTIN", + "SIGTTOU", + "SIGURG", + "SIGXCPU", + "SIGXFSZ", + "SIGVTALRM", + "SIGPROF", + "SIGWINCH", + "SIGPOLL", + "SIGPWR", + "SIGSYS", + "SIGUNUSED", +}; + +const char *sigStr[] = { + "INVALID ", + "SIGABRT ", + "SIGALRM ", + "SIGBUS ", + "SIGCHLD ", + "SIGCONT ", + "SIGFPE ", + "SIGHUP ", + "SIGILL ", + "SIGINT ", + "SIGKILL ", + "SIGPIPE ", + "SIGQUIT ", + "SIGSEGV ", + "SIGSTOP ", + "SIGTERM ", + "SIGTSTP ", + "SIGTTIN ", + "SIGTTOU ", + "SIGUSR1 ", + "SIGUSR2 ", + "SIGPOLL ", + "SIGPROF ", + "SIGSYS ", + "SIGTRAP ", + "SIGURG ", + "SIGVTALRM", + "SIGXCPU ", + "SIGXFSZ ", + "SIGRSV1 ", + "SIGRSV2 ", +}; + +const char *dispStr[] = { + "SIG_TERM", + "SIG_IGN ", + "SIG_CORE", + "SIG_STOP", + "SIG_CONT", +}; +#endif + +extern "C" uintptr_t _sig_native_trampoline_start, _sig_native_trampoline_end; +extern "C" uintptr_t _sig_linux_trampoline_start, _sig_linux_trampoline_end; + +static const struct +{ + int linuxSignal; + int nativeSignal; +} signalMapping[] = { + {linux_SIGHUP, SIGHUP}, + {linux_SIGINT, SIGINT}, + {linux_SIGQUIT, SIGQUIT}, + {linux_SIGILL, SIGILL}, + {linux_SIGTRAP, SIGTRAP}, + {linux_SIGABRT, SIGABRT}, + {linux_SIGBUS, SIGBUS}, + {linux_SIGFPE, SIGFPE}, + {linux_SIGKILL, SIGKILL}, + {linux_SIGUSR1, SIGUSR1}, + {linux_SIGSEGV, SIGSEGV}, + {linux_SIGUSR2, SIGUSR2}, + {linux_SIGPIPE, SIGPIPE}, + {linux_SIGALRM, SIGALRM}, + {linux_SIGTERM, SIGTERM}, + {linux_SIGSTKFLT, SIGRSV1}, + {linux_SIGCHLD, SIGCHLD}, + {linux_SIGCONT, SIGCONT}, + {linux_SIGSTOP, SIGSTOP}, + {linux_SIGTSTP, SIGTSTP}, + {linux_SIGTTIN, SIGTTIN}, + {linux_SIGTTOU, SIGTTOU}, + {linux_SIGURG, SIGURG}, + {linux_SIGXCPU, SIGXCPU}, + {linux_SIGXFSZ, SIGXFSZ}, + {linux_SIGVTALRM, SIGVTALRM}, + {linux_SIGPROF, SIGPROF}, + {linux_SIGPOLL, SIGPOLL}, + {linux_SIGPWR, SIGRSV2}, + {linux_SIGSYS, SIGSYS}, + {linux_SIGUNUSED, SIGSYS}, +}; + +static_assert(linux_SIGUNUSED == SIGNAL_MAX); + +#define CTLif(x) ConvertToLinuxIfNecessary(x) +#define CTNif(x) ConvertToNativeIfNecessary(x) +#define CSigTLif(x) ConvertSigsetToLinuxIfNecessary(x) +#define CSigTNif(x) ConvertSigsetToNativeIfNecessary(x) + +/* TODO: CTLif & CTNif may need optimization */ + +namespace Tasking +{ + bool Signal::LinuxSig() + { + return ((PCB *)ctx)->Info.Compatibility == Linux; + } + + int Signal::ConvertToLinuxIfNecessary(int sig) + { + if (!LinuxSig()) + { + debug("Not linux sig: %d", sig); + return sig; + } + + foreach (auto &mapping in signalMapping) + { + if (mapping.nativeSignal == sig) + { + // debug("Converted %d to %d", sig, mapping.linuxSignal); + return mapping.linuxSignal; + } + } + + return -1; + } + + int Signal::ConvertToNativeIfNecessary(int sig) + { + if (!LinuxSig()) + { + debug("Not native sig: %d", sig); + return sig; + } + + foreach (auto &mapping in signalMapping) + { + if (mapping.linuxSignal == sig) + { + // debug("Converted %d to %d", sig, mapping.nativeSignal); + return mapping.nativeSignal; + } + } + + return -1; + } + + sigset_t Signal::ConvertSigsetToLinuxIfNecessary(sigset_t sig) + { + if (!LinuxSig()) + { + debug("Not linux sigset: %#lx", sig); + return 0; + } + + sigset_t ret = 0; + for (int i = 0; i < SIGNAL_MAX; i++) + { + if (sig & ToFlag(i)) + ret |= ToFlag(CTLif(i)); + } + + return ret; + } + + sigset_t Signal::ConvertSigsetToNativeIfNecessary(sigset_t sig) + { + if (!LinuxSig()) + { + debug("Not native sigset: %#lx", sig); + return 0; + } + + sigset_t ret = 0; + for (int i = 0; i < linux_SIGUNUSED; i++) + { + if (sig & ToFlag(i)) + ret |= ToFlag(CTNif(i)); + } + + return ret; + } + + int Signal::MakeExitCode(int sig) + { + if (this->LinuxSig()) + return 128 + sig; + else + return 100 + sig; + } + + /* ------------------------------------------------------ */ + + int Signal::AddWatcher(Signal *who, int sig) + { + SmartLock(SignalLock); + SignalInfo info; + info.sig = sig; + info.val.sival_ptr = who; + + Watchers.push_back(info); + return 0; + } + + int Signal::RemoveWatcher(Signal *who, int sig) + { + SmartLock(SignalLock); + forItr(itr, Watchers) + { + if (itr->sig == sig && + itr->val.sival_ptr == who) + { + Watchers.erase(itr); + return 0; + } + } + return -ENOENT; + } + + int Signal::AddSignal(int sig, union sigval val) + { + SmartLock(SignalLock); + SignalInfo info{.sig = sig, .val = val}; + SignalQueue.push_back(info); + return 0; + } + + int Signal::RemoveSignal(int sig) + { + SmartLock(SignalLock); + forItr(itr, SignalQueue) + { + if (itr->sig == sig) + { + SignalQueue.erase(itr); + return 0; + } + } + return -ENOENT; + } + + bool Signal::HandleSignal(CPU::TrapFrame *tf) + { + SmartLock(SignalLock); + if (SignalQueue.empty()) + return false; + + /* We don't want to do this in kernel mode */ + if (unlikely(tf->cs != GDT_USER_CODE && + tf->cs != GDT_USER_DATA)) + { + // debug("Not user-mode"); + return false; + } + + debug("We have %d signals to handle", SignalQueue.size()); + + SignalInfo sigI = SignalQueue.front(); + SignalQueue.erase(SignalQueue.begin()); + + uintptr_t _p_rsp = ((PCB *)ctx)->PageTable->Get(tf->rsp); + uint64_t paRsp = _p_rsp; + paRsp &= ~0xF; /* Align */ + paRsp -= 128; /* Red zone */ + + /* Calculate the virtual rsp */ + uintptr_t _v_rsp = tf->rsp; + _v_rsp &= ~0xF; /* Align */ + _v_rsp -= 128; /* Red zone */ + uint64_t *vRsp = (uint64_t *)(_v_rsp - sizeof(StackInfo)); + vRsp--; /* Alignment */ + vRsp--; /* Handler Address */ + assert(!((uintptr_t)vRsp & 0xF)); + + /* Add the stack info */ + StackInfo si{}; + CPU::x64::fxsave(&si.fx); + si.tf = *tf; + si.GSBase = CPU::x64::rdmsr(CPU::x64::MSR_GS_BASE); + si.FSBase = CPU::x64::rdmsr(CPU::x64::MSR_FS_BASE); + si.ShadowGSBase = CPU::x64::rdmsr(CPU::x64::MSR_SHADOW_GS_BASE); + debug("gs: %#lx fs: %#lx shadow: %#lx", + si.GSBase, si.FSBase, si.ShadowGSBase); + si.SignalMask = SignalMask.load(); + si.Compatibility = ((PCB *)ctx)->Info.Compatibility; + + /* Copy the stack info */ + uint64_t *pRsp = (uint64_t *)(paRsp - sizeof(StackInfo)); + memcpy(pRsp, &si, sizeof(StackInfo)); + + /* Set the handler address */ + pRsp--; /* Alignment */ + pRsp--; + *pRsp = uint64_t(SignalAction[sigI.sig].__sa_handler.sa_handler); + + assert(!((uintptr_t)pRsp & 0xF)); + +#ifdef DEBUG + DumpData("Stack Data", (void *)pRsp, + paRsp - uint64_t(pRsp)); + debug("initial stack tf->rsp: %#lx after: %#lx", + tf->rsp, uint64_t(vRsp)); + debug("sig: %d -> %d", sigI.sig, CTLif(sigI.sig)); +#endif + + tf->rsp = uint64_t(vRsp); + tf->rip = uint64_t(TrampAddr); + tf->rdi = CTLif(sigI.sig); + tf->rsi = uint64_t(sigI.val.sival_ptr); + return true; + } + + void Signal::RestoreHandleSignal(SyscallsFrame *sf) + { + SmartLock(SignalLock); + debug("Restoring signal handler"); + gsTCB *gs = (gsTCB *)CPU::x64::rdmsr(CPU::x64::MSR_GS_BASE); + uint64_t *sp = (uint64_t *)((PCB *)ctx)->PageTable->Get(gs->TempStack); + sp++; /* Alignment */ + sp++; /* Handler Address */ + + assert(!((uintptr_t)sp & 0xF)); + + StackInfo *si = (StackInfo *)sp; + assert(si != nullptr); + + sf->r15 = si->tf.r15; + sf->r14 = si->tf.r14; + sf->r13 = si->tf.r13; + sf->r12 = si->tf.r12; + sf->r11 = si->tf.r11; + sf->r10 = si->tf.r10; + sf->r9 = si->tf.r9; + sf->r8 = si->tf.r8; + sf->rbp = si->tf.rbp; + sf->rdi = si->tf.rdi; + sf->rsi = si->tf.rsi; + sf->rdx = si->tf.rdx; + sf->rcx = si->tf.rcx; + sf->rbx = si->tf.rbx; + sf->rax = si->tf.rax; + sf->Flags = si->tf.rflags.raw; + sf->ReturnAddress = si->tf.rip; + gs->TempStack = si->tf.rsp; + + SignalMask.store(si->SignalMask); + + CPU::x64::fxrstor(&si->fx); + CPU::x64::wrmsr(CPU::x64::MSR_GS_BASE, si->ShadowGSBase); + CPU::x64::wrmsr(CPU::x64::MSR_FS_BASE, si->FSBase); + CPU::x64::wrmsr(CPU::x64::MSR_SHADOW_GS_BASE, si->GSBase); + debug("gs: %#lx fs: %#lx shadow: %#lx", + si->GSBase, si->FSBase, si->ShadowGSBase); + + // ((PCB *)ctx)->GetContext()->Yield(); + // __builtin_unreachable(); + /* Return because we will restore at sysretq */ + } + + sigset_t Signal::Block(sigset_t sig) + { + SmartLock(SignalLock); + sig = CSigTNif(sig); + sigset_t oldMask = SignalMask.fetch_or(sig); + debug("%#lx -> %#lx", oldMask, SignalMask); + return CSigTLif(oldMask); + } + + sigset_t Signal::Unblock(sigset_t sig) + { + SmartLock(SignalLock); + sig = CSigTNif(sig); + sigset_t oldMask = SignalMask.fetch_and(~sig); + debug("%#lx -> %#lx", oldMask, SignalMask); + return CSigTLif(oldMask); + } + + sigset_t Signal::SetMask(sigset_t sig) + { + SmartLock(SignalLock); + sig = CSigTNif(sig); + sigset_t oldMask = SignalMask.exchange(sig); + debug("%#lx -> %#lx", oldMask, SignalMask); + return CSigTLif(oldMask); + } + + int Signal::SetAction(int sig, const sigaction act) + { + SmartLock(SignalLock); + if ((size_t)sig > sizeof(SignalAction) / sizeof(SignalAction[0])) + return -EINVAL; + + sig = CTNif(sig); + + SignalAction[sig].__sa_handler.sa_handler = act.__sa_handler.sa_handler; + SignalAction[sig].sa_mask = act.sa_mask; + SignalAction[sig].sa_flags = act.sa_flags; + debug("Set action for %s with handler %#lx, mask %#lx and flags %#lx", + LinuxSig() ? lSigStr[sig] : sigStr[sig], + SignalAction[sig].__sa_handler.sa_handler, + SignalAction[sig].sa_mask, + SignalAction[sig].sa_flags); + return 0; + } + + int Signal::GetAction(int sig, sigaction *act) + { + SmartLock(SignalLock); + + if ((size_t)sig > sizeof(SignalAction) / sizeof(SignalAction[0])) + return -EINVAL; + + sig = CTNif(sig); + + act->__sa_handler.sa_handler = SignalAction[sig].__sa_handler.sa_handler; + act->sa_mask = SignalAction[sig].sa_mask; + act->sa_flags = SignalAction[sig].sa_flags; + debug("Got action for %s with handler %#lx, mask %#lx and flags %#lx", + LinuxSig() ? lSigStr[sig] : sigStr[sig], + SignalAction[sig].__sa_handler.sa_handler, + SignalAction[sig].sa_mask, + SignalAction[sig].sa_flags); + return 0; + } + + int Signal::SendSignal(int sig, union sigval val) + { + PCB *pcb = (PCB *)ctx; + sig = CTNif(sig); + LastSignal = (Signals)sig; + + debug("Sending signal %s to %s(%d)", + sigStr[sig], pcb->Name, pcb->ID); + + if (SignalAction[sig].__sa_handler.sa_handler) + { + if (pcb->Security.ExecutionMode == Kernel) + { + info("Kernel processes cannot have signal handlers"); + return -EINVAL; + } + + debug("sa_handler: %#lx", + SignalAction[sig].__sa_handler.sa_handler); + debug("Adding signal %s to queue", sigStr[sig]); + goto CompleteSignal; + } + + debug("Signal disposition: %s", dispStr[sigDisp[sig]]); + switch (sigDisp[sig]) + { + case SIG_TERM: + { + if (unlikely(pcb->Security.IsCritical)) + { + debug("Critical process %s received signal %s(%d): Terminated", + pcb->Name, sigStr[sig], sig); + // int3; + } + + pcb->SetExitCode(MakeExitCode(sig)); + debug("We have %d watchers", this->Watchers.size()); + if (this->Watchers.size() > 0) + pcb->SetState(Zombie); + else + pcb->SetState(Terminated); + break; + } + case SIG_IGN: + { + debug("Ignoring signal %d", sig); + return 0; + } + case SIG_CORE: + { + fixme("core dump"); + + if (unlikely(pcb->Security.IsCritical)) + { + debug("Critical process %s received signal %s(%d): Core dumped", + pcb->Name, sigStr[sig], sig); + // int3; + } + + pcb->SetExitCode(MakeExitCode(sig)); + debug("We have %d watchers", this->Watchers.size()); + if (this->Watchers.size() > 0) + pcb->SetState(CoreDump); + else + pcb->SetState(Terminated); + break; + } + case SIG_STOP: + { + pcb->SetState(Stopped); + break; + } + case SIG_CONT: + { + pcb->SetState(Ready); + break; + } + default: + assert(!"Invalid signal disposition"); + return -EINVAL; + }; + + CompleteSignal: + if (pcb->Security.ExecutionMode == Kernel) + { + debug("Kernel process %s received signal %s(%d)! Ignoring... (with exceptions)", + pcb->Name, sigStr[sig], sig); + return 0; + } + + if (unlikely(TrampAddr == nullptr)) + { + debug("Trampoline not set up yet"); + switch (thisThread->Info.Compatibility) + { + case Native: + { + debug("%#lx - %#lx", + &_sig_native_trampoline_end, + &_sig_native_trampoline_start); + + TrampSz = (size_t)&_sig_native_trampoline_end - + (size_t)&_sig_native_trampoline_start; + TrampAddr = pcb->vma->RequestPages(TO_PAGES(TrampSz), true); + memcpy((void *)TrampAddr, + (void *)&_sig_native_trampoline_start, + TrampSz); + debug("Trampoline at %#lx with size %lld", + TrampAddr, TrampSz); + break; + } + case Linux: + { + debug("%#lx - %#lx", + &_sig_linux_trampoline_end, + &_sig_linux_trampoline_start); + + TrampSz = (size_t)&_sig_linux_trampoline_end - + (size_t)&_sig_linux_trampoline_start; + TrampAddr = pcb->vma->RequestPages(TO_PAGES(TrampSz), true); + memcpy((void *)TrampAddr, + (void *)&_sig_linux_trampoline_start, + TrampSz); + debug("Trampoline at %#lx with size %lld", + TrampAddr, TrampSz); + break; + } + default: + { + assert(!"Not implemented"); + break; + } + } + } + + debug("Signal %s(%d) completed", sigStr[sig], sig); + if (sigDisp[sig] != SIG_IGN) + { + foreach (auto info in Watchers) + { + Signal *who = (Signal *)info.val.sival_ptr; + assert(who != nullptr); + debug("Sending SIGCHLD to %s(%d)", + ((PCB *)who->GetContext())->Name, + ((PCB *)who->GetContext())->ID); + who->SendSignal(SIGCHLD, val); + } + } + + debug("Adding signal to queue"); + SignalQueue.push_back({.sig = sig, .val = val}); + return 0; + } + + int Signal::WaitAnySignal() + { + /* Sleep until a signal that terminated or invokes + the signal catch function */ + + debug("Waiting for any signal"); + + size_t oldSize = SignalQueue.size(); + Reset: + while (SignalQueue.size() == oldSize) + TaskManager->Yield(); + + if (SignalQueue.size() > oldSize) + { + debug("Added signal to queue %d > %d", + SignalQueue.size(), oldSize); + oldSize = SignalQueue.size(); + goto Reset; + } + + debug("Signal received"); + return -EINTR; + } + + int Signal::WaitSignal(int sig, union sigval *val) + { + return 0; + } + + int Signal::WaitSignalTimeout(int sig, union sigval *val, uint64_t timeout) + { + return 0; + } + + Signal::Signal(void *ctx) + { + assert(ctx != nullptr); + this->ctx = ctx; + + sigDisp[SIG_NULL] = SIG_IGN; + sigDisp[SIGABRT] = SIG_CORE; + sigDisp[SIGALRM] = SIG_TERM; + sigDisp[SIGBUS] = SIG_CORE; + sigDisp[SIGCHLD] = SIG_IGN; + sigDisp[SIGCONT] = SIG_CONT; + sigDisp[SIGFPE] = SIG_CORE; + sigDisp[SIGHUP] = SIG_TERM; + sigDisp[SIGILL] = SIG_CORE; + sigDisp[SIGINT] = SIG_TERM; + sigDisp[SIGKILL] = SIG_TERM; + sigDisp[SIGPIPE] = SIG_TERM; + sigDisp[SIGQUIT] = SIG_TERM; + sigDisp[SIGSEGV] = SIG_CORE; + sigDisp[SIGSTOP] = SIG_STOP; + sigDisp[SIGTERM] = SIG_TERM; + sigDisp[SIGTSTP] = SIG_STOP; + sigDisp[SIGTTIN] = SIG_STOP; + sigDisp[SIGTTOU] = SIG_STOP; + sigDisp[SIGUSR1] = SIG_TERM; + sigDisp[SIGUSR2] = SIG_TERM; + sigDisp[SIGPOLL] = SIG_TERM; + sigDisp[SIGPROF] = SIG_TERM; + sigDisp[SIGSYS] = SIG_CORE; + sigDisp[SIGTRAP] = SIG_CORE; + sigDisp[SIGURG] = SIG_IGN; + sigDisp[SIGVTALRM] = SIG_TERM; + sigDisp[SIGXCPU] = SIG_CORE; + sigDisp[SIGXFSZ] = SIG_CORE; + +#ifdef DEBUG + static int once = 0; + if (!once++) + { + if (LinuxSig()) + { + for (int i = 0; i <= linux_SIGUNUSED; i++) + debug("%s: %s", + lSigStr[i], + dispStr[sigDisp[i]]); + } + else + { + for (int i = 0; i < SIGNAL_MAX; i++) + debug("%s: %s", + sigStr[i], + dispStr[sigDisp[i]]); + } + } +#endif + } + + Signal::~Signal() {} +} diff --git a/tasking/task.cpp b/tasking/task.cpp index 434d2c0..8adb773 100644 --- a/tasking/task.cpp +++ b/tasking/task.cpp @@ -103,11 +103,6 @@ namespace Tasking SafeFunction bool Task::RemoveThread(TCB *Thread) { - if (Thread->KeepInMemory.load() == true) - return false; - if (Thread->KeepTime > TimeManager->GetCounter()) - return false; - debug("Thread \"%s\"(%d) removed from process \"%s\"(%d)", Thread->Name, Thread->ID, Thread->Parent->Name, Thread->Parent->ID); @@ -123,11 +118,6 @@ namespace Tasking if (Process->State == Terminated) { - if (Process->KeepInMemory.load() == true) - return false; - if (Process->KeepTime > TimeManager->GetCounter()) - return false; - delete Process; return true; } @@ -201,7 +191,8 @@ namespace Tasking pcb->Name, pcb->ID); while (pcb->State != TaskState::Terminated && - pcb->State != TaskState::Zombie) + pcb->State != TaskState::Zombie && + pcb->State != TaskState::CoreDump) this->Yield(); } @@ -217,7 +208,8 @@ namespace Tasking tcb->Name, tcb->ID); while (tcb->State != TaskState::Terminated && - tcb->State != TaskState::Zombie) + tcb->State != TaskState::Zombie && + tcb->State != TaskState::CoreDump) this->Yield(); } @@ -254,14 +246,14 @@ namespace Tasking void Task::Sleep(uint64_t Milliseconds, bool NoSwitch) { TCB *thread = this->GetCurrentThread(); - PCB *process = this->GetCurrentProcess(); + PCB *process = thread->Parent; - thread->State = TaskState::Sleeping; + thread->SetState(TaskState::Sleeping); { SmartLock(TaskingLock); if (process->Threads.size() == 1) - process->State = TaskState::Sleeping; + process->SetState(TaskState::Sleeping); thread->Info.SleepUntil = TimeManager->CalculateTarget(Milliseconds, @@ -281,28 +273,25 @@ namespace Tasking void Task::SignalShutdown() { - fixme("SignalShutdown()"); - // TODO: Implement this - // This should hang until all processes are terminated - } + debug("Current process is %s(%d) and thread is %s(%d)", + GetCurrentProcess()->Name, GetCurrentProcess()->ID, + GetCurrentThread()->Name, GetCurrentThread()->ID); - void Task::CleanupProcessesThread() - { - thisThread->Rename("Tasking Cleanup"); - while (true) + foreach (auto pcb in ProcessList) { - this->Sleep(2000); - { - SmartLock(TaskingLock); - foreach (auto Process in ProcessList) - { - if (unlikely(InvalidPCB(Process))) - continue; + if (pcb->State == TaskState::Terminated || + pcb->State == TaskState::Zombie) + continue; - RemoveProcess(Process); - } - } + if (pcb == GetCurrentProcess()) + continue; + + debug("Sending SIGTERM to process \"%s\"(%d)", + pcb->Name, pcb->ID); + pcb->SendSignal(SIGTERM); } + + // TODO: wait for processes to terminate with timeout. } __no_sanitize("undefined") @@ -325,16 +314,55 @@ namespace Tasking const char *Name, TaskExecutionMode ExecutionMode, void *Image, - bool DoNotCreatePageTable, + bool UseKernelPageTable, uint16_t UserID, uint16_t GroupID) { SmartLock(TaskingLock); return new PCB(this, Parent, Name, ExecutionMode, - Image, DoNotCreatePageTable, + Image, UseKernelPageTable, UserID, GroupID); } + void Task::StartScheduler() + { +#if defined(a86) + if (Interrupts::apicTimer[0]) + { + ((APIC::Timer *)Interrupts::apicTimer[0])->OneShot(CPU::x86::IRQ16, 100); + + /* FIXME: The kernel is not ready for multi-core tasking. */ + return; + + APIC::InterruptCommandRegister icr{}; + bool x2APIC = ((APIC::APIC *)Interrupts::apic[0])->x2APIC; + + if (likely(x2APIC)) + { + icr.x2.VEC = s_cst(uint8_t, CPU::x86::IRQ16); + icr.x2.MT = APIC::Fixed; + icr.x2.L = APIC::Assert; + icr.x2.DES = 0xFFFFFFFF; /* Broadcast IPI to all local APICs. */ + ((APIC::APIC *)Interrupts::apic[0])->ICR(icr); + } + else + { + icr.VEC = s_cst(uint8_t, CPU::x86::IRQ16); + icr.MT = APIC::Fixed; + icr.L = APIC::Assert; + + for (int i = 0; i < SMP::CPUCores; i++) + { + icr.DES = uint8_t(i); + ((APIC::APIC *)Interrupts::apic[i])->ICR(icr); + } + } + } +#elif defined(aa64) +#endif + debug("Tasking Started"); + } + Task::Task(const IP EntryPoint) : Interrupts::Handler(16) /* IRQ16 */ { #if defined(a64) @@ -343,8 +371,8 @@ namespace Tasking #elif defined(a32) #elif defined(aa64) #endif - KPrint("Starting Tasking With Instruction Pointer: %p (\e666666%s\eCCCCCC)", - EntryPoint, KernelSymbolTable->GetSymbolFromAddress(EntryPoint)); + KPrint("Starting tasking instance %#lx with ip: %p (\e666666%s\eCCCCCC)", + this, EntryPoint, KernelSymbolTable->GetSymbol(EntryPoint)); #if defined(a64) TaskArchitecture Arch = TaskArchitecture::x64; @@ -354,14 +382,17 @@ namespace Tasking TaskArchitecture Arch = TaskArchitecture::ARM64; #endif - PCB *kproc = CreateProcess(nullptr, "Kernel", TaskExecutionMode::Kernel); - kproc->ELFSymbolTable = KernelSymbolTable; - TCB *kthrd = CreateThread(kproc, EntryPoint, + KernelProcess = CreateProcess(nullptr, "Kernel", + TaskExecutionMode::Kernel, + nullptr, true); + KernelProcess->PageTable = KernelPageTable; + KernelProcess->ELFSymbolTable = KernelSymbolTable; + TCB *kthrd = CreateThread(KernelProcess, EntryPoint, nullptr, nullptr, std::vector(), Arch); kthrd->Rename("Main Thread"); debug("Created Kernel Process: %s and Thread: %s", - kproc->Name, kthrd->Name); + KernelProcess->Name, kthrd->Name); bool MONITORSupported = false; if (strcmp(CPU::Vendor(), x86_CPUID_VENDOR_AMD) == 0) @@ -388,37 +419,25 @@ namespace Tasking CPU::Interrupts(CPU::Enable); } - IdleProcess = CreateProcess(nullptr, (char *)"Idle", TaskExecutionMode::Kernel); + IdleProcess = CreateProcess(nullptr, (char *)"Idle", + TaskExecutionMode::Kernel, + nullptr, true); IdleProcess->ELFSymbolTable = KernelSymbolTable; for (int i = 0; i < SMP::CPUCores; i++) { - IdleThread = CreateThread(IdleProcess, IP(IdleProcessLoop)); + TCB *thd = CreateThread(IdleProcess, IP(IdleProcessLoop)); char IdleName[16]; sprintf(IdleName, "Idle Thread %d", i); - IdleThread->Rename(IdleName); - IdleThread->SetPriority(Idle); + thd->Rename(IdleName); + thd->SetPriority(Idle); for (int j = 0; j < MAX_CPU; j++) - IdleThread->Info.Affinity[j] = false; - IdleThread->Info.Affinity[i] = true; - } - debug("Tasking Started"); -#if defined(a86) - if (Interrupts::apicTimer[0]) - { - ((APIC::Timer *)Interrupts::apicTimer[0])->OneShot(CPU::x86::IRQ16, 100); + thd->Info.Affinity[j] = false; + thd->Info.Affinity[i] = true; - /* FIXME: The kernel is not ready for multi-core tasking. */ - // for (int i = 1; i < SMP::CPUCores; i++) - // { - // ((APIC::Timer *)Interrupts::apicTimer[i])->OneShot(CPU::x86::IRQ16, 100); - // APIC::InterruptCommandRegisterLow icr; - // icr.Vector = CPU::x86::IRQ16; - // icr.Level = APIC::APICLevel::Assert; - // ((APIC::APIC *)Interrupts::apic[0])->IPI(i, icr); - // } + if (unlikely(i == 0)) + IdleThread = thd; } -#elif defined(aa64) -#endif + debug("Tasking is ready"); } Task::~Task() @@ -430,8 +449,7 @@ namespace Tasking { foreach (TCB *Thread in Process->Threads) { - if (Thread == GetCurrentCPU()->CurrentThread.load() || - Thread == CleanupThread) + if (Thread == GetCurrentCPU()->CurrentThread.load()) continue; this->KillThread(Thread, KILL_SCHEDULER_DESTRUCTION); } @@ -442,20 +460,38 @@ namespace Tasking } } + debug("Waiting for processes to terminate"); + uint64_t timeout = TimeManager->CalculateTarget(20, Time::Units::Seconds); while (ProcessList.size() > 0) { trace("Waiting for %d processes to terminate", ProcessList.size()); int NotTerminated = 0; foreach (PCB *Process in ProcessList) { - debug("Process %s(%d) is still running (or waiting to be removed status %#lx)", + trace("Process %s(%d) is still running (or waiting to be removed state %#lx)", Process->Name, Process->ID, Process->State); + if (Process->State == TaskState::Terminated) + { + debug("Process %s(%d) terminated", Process->Name, Process->ID); continue; + } + NotTerminated++; } if (NotTerminated == 1) break; + + this->Sleep(1000); + debug("Current working process is %s(%d)", + GetCurrentProcess()->Name, GetCurrentProcess()->ID); + + if (TimeManager->GetCounter() > timeout) + { + error("Timeout waiting for processes to terminate"); + break; + } + TaskingScheduler_OneShot(100); } diff --git a/tasking/thread.cpp b/tasking/thread.cpp index 1a52f00..10e0ea7 100644 --- a/tasking/thread.cpp +++ b/tasking/thread.cpp @@ -51,7 +51,7 @@ void ThreadDoExit() { CPUData *CPUData = GetCurrentCPU(); Tasking::TCB *CurrentThread = CPUData->CurrentThread.load(); - CurrentThread->State = Tasking::TaskState::Terminated; + CurrentThread->SetState(Tasking::Terminated); debug("\"%s\"(%d) exited with code: %#lx", CurrentThread->Name, @@ -62,6 +62,25 @@ void ThreadDoExit() namespace Tasking { + int TCB::SendSignal(int sig) + { + return this->Parent->Signals->SendSignal(sig); + } + + void TCB::SetState(TaskState state) + { + this->State.store(state); + if (this->Parent->Threads.size() == 1) + this->Parent->State.store(state); + } + + void TCB::SetExitCode(int code) + { + this->ExitCode.store(code); + if (this->Parent->Threads.size() == 1) + this->Parent->ExitCode.store(code); + } + void TCB::Rename(const char *name) { assert(name != nullptr); @@ -98,6 +117,9 @@ namespace Tasking this->Name, Critical ? "true" : "false"); Security.IsCritical = Critical; + + if (this->Parent->Threads.size() == 1) + this->Parent->Security.IsCritical = Critical; } void TCB::SetDebugMode(bool Enable) @@ -106,6 +128,9 @@ namespace Tasking this->Name, Enable ? "true" : "false"); Security.IsDebugEnabled = Enable; + + if (this->Parent->Threads.size() == 1) + this->Parent->Security.IsDebugEnabled = Enable; } void TCB::SetKernelDebugMode(bool Enable) @@ -114,6 +139,9 @@ namespace Tasking this->Name, Enable ? "true" : "false"); Security.IsKernelDebugEnabled = Enable; + + if (this->Parent->Threads.size() == 1) + this->Parent->Security.IsKernelDebugEnabled = Enable; } size_t TCB::GetSize() @@ -171,13 +199,13 @@ namespace Tasking /* https://articles.manugarg.com/aboutelfauxiliaryvectors.html */ /* https://refspecs.linuxbase.org/elf/x86_64-abi-0.99.pdf#figure.3.9 */ - // rsp is the top of the stack + /* rsp is the top of the stack */ char *Stack = (char *)this->Stack->GetStackPhysicalTop(); - // Temporary stack pointer for strings + /* Temporary stack pointer for strings */ char *StackStrings = (char *)Stack; char *StackStringsVirtual = (char *)this->Stack->GetStackTop(); - // Store string pointers for later + /* Store string pointers for later */ uintptr_t *ArgvStrings = nullptr; uintptr_t *EnvpStrings = nullptr; if (ArgvSize > 0) @@ -187,63 +215,66 @@ namespace Tasking for (size_t i = 0; i < ArgvSize; i++) { - // Subtract the length of the string and the null terminator + /* Subtract the length of the string and the null terminator */ StackStrings -= strlen(argv[i]) + 1; StackStringsVirtual -= strlen(argv[i]) + 1; - // Store the pointer to the string + /* Store the pointer to the string */ ArgvStrings[i] = (uintptr_t)StackStringsVirtual; - // Copy the string to the stack + /* Copy the string to the stack */ strcpy(StackStrings, argv[i]); debug("argv[%d]: %s", i, argv[i]); } for (size_t i = 0; i < EnvpSize; i++) { - // Subtract the length of the string and the null terminator + /* Subtract the length of the string and the null terminator */ StackStrings -= strlen(envp[i]) + 1; StackStringsVirtual -= strlen(envp[i]) + 1; - // Store the pointer to the string + /* Store the pointer to the string */ EnvpStrings[i] = (uintptr_t)StackStringsVirtual; - // Copy the string to the stack + /* Copy the string to the stack */ strcpy(StackStrings, envp[i]); debug("envp[%d]: %s", i, envp[i]); } - // Align the stack to 16 bytes + /* Align the stack to 16 bytes */ StackStrings -= (uintptr_t)StackStrings & 0xF; - // Set "Stack" to the new stack pointer + /* Set "Stack" to the new stack pointer */ Stack = (char *)StackStrings; - // If argv and envp sizes are odd then we need to align the stack + /* If argv and envp sizes are odd then we need to align the stack */ Stack -= (ArgvSize + EnvpSize) % 2; + debug("odd align: %#lx | %#lx -> %#lx", + (ArgvSize + EnvpSize) % 2, + StackStrings, Stack); - // We need 8 bit pointers for the stack from here + /* We need 8 bit pointers for the stack from here */ uintptr_t *Stack64 = (uintptr_t *)Stack; + assert(Stack64 != nullptr); - // Store the null terminator - Stack64--; - *Stack64 = AT_NULL; + /* Store the null terminator */ + StackPush(Stack64, uintptr_t, AT_NULL); - // auxv_array is initialized with auxv elements. If the array is empty then we add a null terminator + /* auxv_array is initialized with auxv elements. + If the array is empty then we add a null terminator */ std::vector auxv_array = auxv; if (auxv_array.size() == 0) auxv_array.push_back({.archaux = {.a_type = AT_NULL, .a_un = {.a_val = 0}}}); - // Store auxillary vector + /* Store auxillary vector */ foreach (AuxiliaryVector av in auxv_array) { - // Subtract the size of the auxillary vector + /* Subtract the size of the auxillary vector */ Stack64 -= sizeof(Elf_auxv_t) / sizeof(uintptr_t); - // Store the auxillary vector + /* Store the auxillary vector */ POKE(Elf_auxv_t, Stack64) = av.archaux; - // TODO: Store strings to the stack + /* TODO: Store strings to the stack */ } - // Store the null terminator - Stack64--; - *Stack64 = AT_NULL; + /* Store the null terminator */ + StackPush(Stack64, uintptr_t, AT_NULL); - // Store EnvpStrings[] to the stack - Stack64 -= EnvpSize; // (1 Stack64 = 8 bits; Stack64 = 8 * EnvpSize) + /* Store EnvpStrings[] to the stack */ + Stack64 -= EnvpSize; /* (1 Stack64 = 8 bits; Stack64 = 8 * EnvpSize) */ for (size_t i = 0; i < EnvpSize; i++) { *(Stack64 + i) = (uintptr_t)EnvpStrings[i]; @@ -251,12 +282,11 @@ namespace Tasking i, EnvpStrings[i]); } - // Store the null terminator - Stack64--; - *Stack64 = AT_NULL; + /* Store the null terminator */ + StackPush(Stack64, uintptr_t, AT_NULL); - // Store ArgvStrings[] to the stack - Stack64 -= ArgvSize; // (1 Stack64 = 8 bits; Stack64 = 8 * ArgvSize) + /* Store ArgvStrings[] to the stack */ + Stack64 -= ArgvSize; /* (1 Stack64 = 8 bits; Stack64 = 8 * ArgvSize) */ for (size_t i = 0; i < ArgvSize; i++) { *(Stack64 + i) = (uintptr_t)ArgvStrings[i]; @@ -264,11 +294,10 @@ namespace Tasking i, ArgvStrings[i]); } - // Store the argc - Stack64--; - *Stack64 = ArgvSize; + /* Store the argc */ + StackPush(Stack64, uintptr_t, ArgvSize); - // Set "Stack" to the new stack pointer + /* Set "Stack" to the new stack pointer */ Stack = (char *)Stack64; /* We need the virtual address but because we are in the kernel we can't use the process page table. @@ -276,8 +305,10 @@ namespace Tasking uintptr_t SubtractStack = (uintptr_t)this->Stack->GetStackPhysicalTop() - (uintptr_t)Stack; debug("SubtractStack: %#lx", SubtractStack); - // Set the stack pointer to the new stack + /* Set the stack pointer to the new stack */ uintptr_t StackPointerReg = ((uintptr_t)this->Stack->GetStackTop() - SubtractStack); + // assert(!(StackPointerReg & 0xF)); + #if defined(a64) this->Registers.rsp = StackPointerReg; #elif defined(a32) @@ -292,7 +323,9 @@ namespace Tasking delete[] EnvpStrings; #ifdef DEBUG - DumpData("Stack Data", (void *)((uintptr_t)this->Stack->GetStackPhysicalTop() - (uintptr_t)SubtractStack), SubtractStack); + DumpData("Stack Data", + (void *)((uintptr_t)this->Stack->GetStackPhysicalTop() - (uintptr_t)SubtractStack), + SubtractStack); #endif #if defined(a64) @@ -327,6 +360,48 @@ namespace Tasking fixme("Not implemented"); } + void TCB::SetupThreadLocalStorage() + { + if (Parent->TLS.pBase == 0x0) + return; + this->TLS = Parent->TLS; + + debug("msz: %ld fsz: %ld", + this->TLS.Size, this->TLS.fSize); + + // size_t pOffset = this->TLS.vBase - std::tolower(this->TLS.vBase); + size_t tlsFullSize = sizeof(uintptr_t) + this->TLS.Size; + /* 2 guard pages */ + size_t tlsPages = 1 + TO_PAGES(tlsFullSize) + 1; + + void *opTLS = this->vma->RequestPages(tlsPages); + void *pTLS = (void *)(PAGE_SIZE + uintptr_t(opTLS)); + this->TLS.pBase = uintptr_t(pTLS); + + memcpy(pTLS, (void *)this->TLS.pBase, + this->TLS.Size); + + size_t restBytes = this->TLS.Size - this->TLS.fSize; + if (restBytes) + { + memset((void *)(uintptr_t(pTLS) + this->TLS.Size), + 0, restBytes); + } + + Memory::Virtual vmm(this->Parent->PageTable); + /* Map guard pages */ + vmm.Remap((void *)(uintptr_t(pTLS) - PAGE_SIZE), opTLS, Memory::P); + vmm.Remap((void *)(uintptr_t(pTLS) + this->TLS.Size), opTLS, Memory::P); + /* Map TLS */ + vmm.Map(pTLS, pTLS, this->TLS.Size, Memory::RW | Memory::US); + + uintptr_t *pTLSPointer = (uintptr_t *)this->TLS.pBase + this->TLS.Size; + *pTLSPointer = this->TLS.pBase + this->TLS.Size; + + this->GSBase = r_cst(uintptr_t, pTLSPointer); + this->FSBase = r_cst(uintptr_t, pTLSPointer); + } + TCB::TCB(Task *ctx, PCB *Parent, IP EntryPoint, const char **argv, const char **envp, const std::vector &auxv, @@ -363,9 +438,9 @@ namespace Tasking this->ExitCode = KILL_CRASH; if (ThreadNotReady) - this->State = TaskState::Waiting; + this->SetState(Waiting); else - this->State = TaskState::Ready; + this->SetState(Ready); this->vma = new Memory::VirtualMemoryArea(this->Parent->PageTable); @@ -467,11 +542,19 @@ namespace Tasking assert(false); } + SetupThreadLocalStorage(); + this->Info.Architecture = Architecture; this->Info.Compatibility = Compatibility; this->Security.ExecutionMode = this->Parent->Security.ExecutionMode; + if (this->Parent->Threads.size() == 0) + { + this->Parent->Info.Architecture = this->Info.Architecture; + this->Parent->Info.Compatibility = this->Info.Compatibility; + } + // TODO: Is really a good idea to use the FPU in kernel mode? this->FPU.mxcsr = 0b0001111110000000; this->FPU.mxcsrmask = 0b1111111110111111; @@ -519,7 +602,7 @@ namespace Tasking this->Parent->State == Waiting && ThreadNotReady == false) { - this->Parent->State = Ready; + this->Parent->SetState(Ready); debug("Setting process \"%s\"(%d) to ready", this->Parent->Name, this->Parent->ID); } @@ -531,7 +614,7 @@ namespace Tasking /* Remove us from the process list so we don't get scheduled anymore */ - std::vector &Threads = this->Parent->Threads; + std::list &Threads = this->Parent->Threads; Threads.erase(std::find(Threads.begin(), Threads.end(), this)); @@ -544,5 +627,8 @@ namespace Tasking /* Free Name */ delete[] this->Name; + + debug("Thread \"%s\"(%d) destroyed", + this->Name, this->ID); } } diff --git a/tests/lsof.cpp b/tests/lsof.cpp index f4c902a..9618eb9 100644 --- a/tests/lsof.cpp +++ b/tests/lsof.cpp @@ -73,7 +73,7 @@ void lsof() fd.Handle->node->FullPath); } Display->SetBufferCursor(0, tmpX, tmpY); - if (!Config.BootAnimation) + if (!Config.Quiet) Display->SetBuffer(0); } } diff --git a/tests/macros.cpp b/tests/macros.cpp index 2959667..e6cbaab 100644 --- a/tests/macros.cpp +++ b/tests/macros.cpp @@ -18,6 +18,7 @@ #ifdef DEBUG #include +#include #include #include #include @@ -46,12 +47,11 @@ #endif // UINTPTR_MAX != UINT64_MAX #endif // aa64 -void TestSeekMacros() -{ - static_assert(sc_SEEK_SET == SEEK_SET); - static_assert(sc_SEEK_CUR == SEEK_CUR); - static_assert(sc_SEEK_END == SEEK_END); -} +static_assert(sc_SEEK_SET == SEEK_SET); +static_assert(sc_SEEK_CUR == SEEK_CUR); +static_assert(sc_SEEK_END == SEEK_END); +static_assert(TIOCGPTN == 0x80045430); +static_assert(TIOCSPTLCK == 0x40045431); __constructor void TestMacros() { @@ -154,6 +154,17 @@ __constructor void TestMacros() inf_loop; } } + + { + constexpr int x = 5; + constexpr int y = 10; + + constexpr int max_result = MAX(x, y); + constexpr int min_result = MIN(x, y); + + static_assert(max_result == 10); + static_assert(min_result == 5); + } } #endif // DEBUG diff --git a/tests/mem_allocs.cpp b/tests/mem_allocs.cpp index 4c1fd76..ab3815a 100644 --- a/tests/mem_allocs.cpp +++ b/tests/mem_allocs.cpp @@ -21,33 +21,111 @@ #include #include +#include "../kernel.h" + /* Originally from: https://github.com/EnderIce2/FennixProject/blob/main/kernel/test.cpp */ #define MEMTEST_ITERATIONS 1024 +#define MAX_SIZE 1024 + +void testMemoryIntegrity() +{ + debug("Testing memory integrity..."); + + for (size_t i = 1; i <= MAX_SIZE; i *= 2) + { + void *ptr1 = malloc(i); + if (ptr1 == NULL) + { + error("malloc failed for size %zu", i); + inf_loop; + } + + memset(ptr1, 0xAA, i); + + for (size_t j = 0; j < i; ++j) + { + if (*((unsigned char *)ptr1 + j) != 0xAA) + { + error("Memory corruption detected before free (size %zu)", i); + inf_loop; + } + } + + void *ptr2 = malloc(i * 2); + if (ptr2 == NULL) + { + error("malloc failed for size %zu", i * 2); + inf_loop; + } + + memset(ptr2, 0xBB, i * 2); + + for (size_t j = 0; j < i; ++j) + { + if (*((unsigned char *)ptr1 + j) != 0xAA) + { + error("Memory corruption detected in previous allocation (size %zu)", i); + inf_loop; + } + } + + free(ptr1); + + for (size_t j = 0; j < i; ++j) + { + if (*((unsigned char *)ptr2 + j) != 0xBB) + { + error("Memory corruption detected in current allocation (size %zu)", i * 2); + inf_loop; + } + } + + void *ptr3 = realloc(ptr2, i * 3); + if (ptr3 == NULL) + { + error("realloc failed for size %zu", i * 3); + inf_loop; + } + + memset(ptr3, 0xCC, i * 3); + + for (size_t j = 0; j < i; ++j) + { + if (*((unsigned char *)ptr3 + j) != 0xCC) + { + error("Memory corruption detected after realloc (size %zu)", i * 3); + inf_loop; + } + } + + free(ptr3); + } + + debug("Memory integrity test passed."); +} class test_mem_new_delete { public: - test_mem_new_delete(); - ~test_mem_new_delete(); + test_mem_new_delete() + { + for (char i = 0; i < 2; i++) + ; + } + + ~test_mem_new_delete() + { + for (char i = 0; i < 2; i++) + ; + } }; -test_mem_new_delete::test_mem_new_delete() -{ - for (char i = 0; i < 2; i++) - ; -} - -test_mem_new_delete::~test_mem_new_delete() -{ - for (char i = 0; i < 2; i++) - ; -} - extern bool DebuggerIsAttached; void TestMemoryAllocation() { + return; /* Bit annoying to have to wait for this to finish */ #ifdef a32 return; /* Not ready for now. */ #endif @@ -57,6 +135,8 @@ void TestMemoryAllocation() return; } + testMemoryIntegrity(); + void *tmpAlloc1 = kmalloc(176); void *tmpAlloc2 = kmalloc(511); void *tmpAlloc3 = kmalloc(1027); @@ -113,7 +193,8 @@ void TestMemoryAllocation() kfree((void *)prq2); debug(" Result:\t\t1-[%#lx]; 2-[%#lx]", (void *)prq1, (void *)prq2); - assert(prq1 == prq2); + if (Config.AllocatorType != Memory::MemoryAllocatorType::rpmalloc_) + assert(prq1 == prq2); } debug("Multiple Dynamic Malloc Test"); @@ -128,7 +209,8 @@ void TestMemoryAllocation() kfree((void *)prq2); debug(" Result:\t1-[%#lx]; 2-[%#lx]", (void *)prq1, (void *)prq2); - assert(prq1 == prq2); + if (Config.AllocatorType != Memory::MemoryAllocatorType::rpmalloc_) + assert(prq1 == prq2); } debug("New/Delete Test"); @@ -146,7 +228,8 @@ void TestMemoryAllocation() kfree((void *)prq2); debug(" Result: \t1-[%#lx]; 2-[%#lx]", (void *)prq1, (void *)prq2); - assert(prq1 == prq2); + if (Config.AllocatorType != Memory::MemoryAllocatorType::rpmalloc_) + assert(prq1 == prq2); } debug("New/Delete Fixed Array Test"); @@ -164,7 +247,8 @@ void TestMemoryAllocation() kfree((void *)prq2); debug(" Result: \t1-[%#lx]; 2-[%#lx]", (void *)prq1, (void *)prq2); - assert(prq1 == prq2); + if (Config.AllocatorType != Memory::MemoryAllocatorType::rpmalloc_) + assert(prq1 == prq2); } debug("New/Delete Dynamic Array Test"); @@ -184,7 +268,8 @@ void TestMemoryAllocation() kfree((void *)prq2); debug(" Result:\t1-[%#lx]; 2-[%#lx]", (void *)prq1, (void *)prq2); - assert(prq1 == prq2); + if (Config.AllocatorType != Memory::MemoryAllocatorType::rpmalloc_) + assert(prq1 == prq2); } debug("calloc Test"); @@ -202,7 +287,8 @@ void TestMemoryAllocation() kfree((void *)prq2); debug(" Result:\t1-[%#lx]; 2-[%#lx]", (void *)prq1, (void *)prq2); - assert(prq1 == prq2); + if (Config.AllocatorType != Memory::MemoryAllocatorType::rpmalloc_) + assert(prq1 == prq2); } debug("realloc Test"); @@ -221,7 +307,8 @@ void TestMemoryAllocation() kfree((void *)prq2); debug(" Result:\t1-[%#lx]; 2-[%#lx]", (void *)prq1, (void *)prq2); - assert(prq1 == prq2); + if (Config.AllocatorType != Memory::MemoryAllocatorType::rpmalloc_) + assert(prq1 == prq2); } } diff --git a/tests/std.cpp b/tests/std.cpp index 90d09f0..b8a04c2 100644 --- a/tests/std.cpp +++ b/tests/std.cpp @@ -18,8 +18,10 @@ #ifdef DEBUG #include +#include #include #include +#include void Test_std() { @@ -63,6 +65,76 @@ void Test_std() debug("3: %#lx", intVector[3]); debug("4: %#lx", intVector[4]); + /* ---------------------------- */ + + std::list intList; + intList.push_back(10); + intList.push_back(20); + intList.push_back(30); + assert(intList.size() == 3); + + assert(intList.front() == 10); + assert(intList.back() == 30); + + intList.pop_back(); + assert(intList.size() == 2); + + intList.clear(); + assert(intList.empty()); + + /* ---------------------------- */ + + std::unordered_map intMap; + intMap[1] = 10; + intMap[2] = 20; + intMap[3] = 30; + assert(intMap.size() == 3); + + assert(intMap[1] == 10); + assert(intMap[2] == 20); + assert(intMap[3] == 30); + + intMap.erase(1); + assert(intMap.size() == 2); + + intMap.clear(); + assert(intMap.empty()); + + std::unordered_map strMap; + strMap["hello"] = 10; + strMap["world"] = 20; + strMap["foo"] = 30; + assert(strMap.size() == 3); + + assert(strMap["hello"] == 10); + assert(strMap["world"] == 20); + assert(strMap["foo"] == 30); + + strMap.erase("hello"); + assert(strMap.size() == 2); + + strMap.clear(); + assert(strMap.empty()); + + /* ---------------------------- */ + + std::hash intHash; + + size_t a0 = intHash(0xdeadbeef); + size_t a1 = intHash(0xdeadbeef); + size_t a2 = intHash(1); + size_t a3 = intHash(2); + + debug("a0: %#lx", a0); + debug("a1: %#lx", a1); + debug("a2: %#lx", a2); + debug("a3: %#lx", a3); + + assert(a0 == a1); + assert(a2 != a3); + + /* ---------------------------- */ + debug("std: OK"); } diff --git a/tests/std_string.cpp b/tests/std_string.cpp index af506c7..8b2df53 100644 --- a/tests/std_string.cpp +++ b/tests/std_string.cpp @@ -137,7 +137,7 @@ void TestString() else { error("String addition doesn't work! \"%s\"", c.c_str()); - inf_loop; + // inf_loop; } for (int i = 0; i < 1024; i++) diff --git a/tests/stress.cpp b/tests/stress.cpp new file mode 100644 index 0000000..0d4e493 --- /dev/null +++ b/tests/stress.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 . +*/ + +#ifdef DEBUG + +#include "t.h" + +#include "../kernel.h" + +void killChildren(Tasking::PCB *pcb) +{ + if (pcb->Children.empty()) + { + KPrint("Process %s(%d) has no children", pcb->Name, pcb->ID); + return; + } + + std::list children = pcb->Children; + + foreach (auto child in children) + { + if (child->State.load() == Tasking::Terminated) + { + KPrint("Process %s(%d) is already dead", child->Name, child->ID); + continue; + } + + KPrint("Killing %s(%d)", child->Name, child->ID); + killChildren(child); + child->SetState(Tasking::Terminated); + debug("killed %s(%d)", child->Name, child->ID); + } +} + +constexpr size_t chunk = 10 * 1024 * 1024; /* 10 MiB */ +std::atomic_size_t totalAllocated = 0; +std::atomic_size_t highestScore = 0; +std::atomic_bool halt_fork = false; +std::list allocatedChunks; +Tasking::PCB *baseProc = nullptr; +Tasking::PCB *lastProc = nullptr; +std::atomic_bool hold = false; +void StressKernel() +{ + return; + + static int once = 0; + if (!once++) + { + debug("We have %d GiB of free memory", + TO_GiB(KernelAllocator.GetFreeMemory())); + assert(TO_GiB(KernelAllocator.GetFreeMemory()) >= 1); + } + + while (true) + { + while (hold.exchange(true, std::memory_order_acquire)) + ; + + if (!halt_fork.load() && TaskManager->GetProcessList().size() > 100) + halt_fork.store(true); + + void *ptr; + Tasking::PCB *pcb = nullptr; + if (TO_MiB(KernelAllocator.GetFreeMemory()) < 20) + { + KPrint("\eE85230Not enough memory left!"); + goto End; + } + + ptr = KernelAllocator.RequestPages(TO_PAGES(chunk)); + if (ptr == nullptr) + { + KPrint("\eE85230Failed to allocate memory!"); + KPrint("Score is: %d MiB (current is %d MiB)", + TO_MiB(highestScore.load()), TO_MiB(totalAllocated.load())); + continue; + } + KPrint("Allocated %d bytes at %#lx", chunk, ptr); + allocatedChunks.push_back(ptr); + totalAllocated.fetch_add(chunk); + if (totalAllocated.load() > highestScore.load()) + highestScore.store(totalAllocated.load()); + KPrint("Total allocated: %d MiB [KERNEL: %d MiB free]", + TO_MiB(totalAllocated.load()), TO_MiB(KernelAllocator.GetFreeMemory())); + + if (lastProc == nullptr) + lastProc = thisProcess; + + if (halt_fork.load() == false) + { + KPrint("Forking..."); + pcb = TaskManager->CreateProcess(lastProc, "STRESS TEST", Tasking::Kernel); + lastProc = pcb; + if (baseProc == nullptr) + baseProc = pcb; + TaskManager->CreateThread(pcb, Tasking::IP(StressKernel)); + KPrint("There are %d processes", TaskManager->GetProcessList().size()); + } + + End: + hold.store(true); + if (TO_GiB(totalAllocated.load()) >= 1) + { + KPrint("Freeing memory..."); + forItr(itr, allocatedChunks) + { + KPrint("Freeing %#lx", *itr); + KernelAllocator.FreePages(*itr, TO_PAGES(chunk)); + allocatedChunks.erase(itr); + } + totalAllocated.store(0); + } + + // if (TaskManager->GetProcessList().size() >= 100) + // { + // KPrint("Killing processes..."); + // killChildren(baseProc->Children.front()); + // KPrint("All processes killed."); + // baseProc = nullptr; + // } + hold.store(false); + } +} + +#endif // DEBUG diff --git a/tests/t.h b/tests/t.h index 59322fe..7926c25 100644 --- a/tests/t.h +++ b/tests/t.h @@ -30,6 +30,8 @@ void tasking_test_mutex(); void lsof(); void TaskMgr(); void TreeFS(vfs::Node *node, int Depth); +void TaskHeartbeat(); +void StressKernel(); #endif // DEBUG #endif // !__FENNIX_KERNEL_non_constructor_tests_H__ diff --git a/modules/ATA/ata.hpp b/tests/task_heartbeat.cpp similarity index 70% rename from modules/ATA/ata.hpp rename to tests/task_heartbeat.cpp index 6406f80..13c4470 100644 --- a/modules/ATA/ata.hpp +++ b/tests/task_heartbeat.cpp @@ -15,17 +15,22 @@ along with Fennix Kernel. If not, see . */ -#ifndef __FENNIX_KERNEL_ATA_H__ -#define __FENNIX_KERNEL_ATA_H__ +#ifdef DEBUG -#include -#include "../../mapi.hpp" +#include "t.h" -namespace AdvancedTechnologyAttachment +#include "../kernel.h" + +void TaskHeartbeat() { - int DriverEntry(void *); - int CallbackHandler(KernelCallback *); - int InterruptCallback(CPURegisters *); + thisThread->Rename("Task Heartbeat"); + thisThread->SetPriority(Tasking::Idle); + + while (true) + { + debug("Task Heartbeat"); + TaskManager->Sleep(5000); + } } -#endif // !__FENNIX_KERNEL_ATA_H__ +#endif // DEBUG diff --git a/tests/taskmgr.cpp b/tests/taskmgr.cpp index 5117239..8d54ce9 100644 --- a/tests/taskmgr.cpp +++ b/tests/taskmgr.cpp @@ -153,12 +153,12 @@ void TaskMgr() printf(" \e%s-> \eAABBCC%s \e00AAAA%s %ld%% (KT: %ld UT: %ld, IP: \e24FF2B%#lx \eEDFF24%s\e00AAAA)\n\eAABBCC", Statuses[State], Thd->Name, StatusesSign[State], ThreadCpuUsage, Thd->Info.KernelTime, Thd->Info.UserTime, Thd->Registers.rip, - Thd->Parent->ELFSymbolTable ? Thd->Parent->ELFSymbolTable->GetSymbolFromAddress(Thd->Registers.rip) : "unknown"); + Thd->Parent->ELFSymbolTable ? Thd->Parent->ELFSymbolTable->GetSymbol(Thd->Registers.rip) : "unknown"); #elif defined(a32) printf(" \e%s-> \eAABBCC%s \e00AAAA%s %lld%% (KT: %lld UT: %lld, IP: \e24FF2B%#x \eEDFF24%s\e00AAAA)\n\eAABBCC", Statuses[State], Thd->Name, StatusesSign[State], ThreadCpuUsage, Thd->Info.KernelTime, Thd->Info.UserTime, Thd->Registers.eip, - Thd->Parent->ELFSymbolTable ? Thd->Parent->ELFSymbolTable->GetSymbolFromAddress(Thd->Registers.eip) : "unknown"); + Thd->Parent->ELFSymbolTable ? Thd->Parent->ELFSymbolTable->GetSymbol(Thd->Registers.eip) : "unknown"); #elif defined(aa64) #endif } @@ -177,7 +177,7 @@ void TaskMgr() if (sanity > 1000) sanity = 0; Display->SetBufferCursor(0, tmpX, tmpY); - if (!Config.BootAnimation) + if (!Config.Quiet) Display->SetBuffer(0); TaskManager->Sleep(100); diff --git a/tests/treefs.cpp b/tests/treefs.cpp index b4851cb..bfbc9d5 100644 --- a/tests/treefs.cpp +++ b/tests/treefs.cpp @@ -28,7 +28,7 @@ void TreeFS(vfs::Node *node, int Depth) { printf("%*c %s\eFFFFFF\n", Depth, ' ', Chld->Name); - if (!Config.BootAnimation) + if (!Config.Quiet) Display->SetBuffer(0); TaskManager->Sleep(100); TreeFS(Chld, Depth + 1); diff --git a/tests/types_sizes.cpp b/tests/types_sizes.cpp index ee59048..b0b0d5d 100644 --- a/tests/types_sizes.cpp +++ b/tests/types_sizes.cpp @@ -21,6 +21,7 @@ __constructor void TestTypeSize() { + return; debug("--- INT TYPES ---"); debug("sizeof(__INT8_TYPE__) = %lld", sizeof(__INT8_TYPE__)); debug("sizeof(__INT16_TYPE__) = %lld", sizeof(__INT16_TYPE__)); diff --git a/virtualization/vm_detect.cpp b/virtualization/detect.cpp similarity index 100% rename from virtualization/vm_detect.cpp rename to virtualization/detect.cpp