Update kernel

This commit is contained in:
EnderIce2 2024-01-19 06:47:42 +02:00
parent fd15592608
commit 96daa43d38
Signed by untrusted user who does not match committer: enderice2
GPG Key ID: EACC3AD603BAB4DD
282 changed files with 25486 additions and 15700 deletions

91
.gdbinit Normal file
View File

@ -0,0 +1,91 @@
# Usage: add-symbol-file-all <filename> [<offset>]
# remove-symbol-file-all <filename> [<offset>]
#
# 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

2
.gitignore vendored
View File

@ -2,5 +2,5 @@
*.su *.su
*.gcno *.gcno
*.map *.map
*.fsys fennix.elf
*.log *.log

View File

@ -21,14 +21,14 @@
"\talong with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.", "\talong with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.",
"*/", "*/",
"", "",
"#ifndef __FENNIX_KERNEL_${2:header}_H__", "#ifndef __FENNIX_KERNEL_${1:header}_H__",
"#define __FENNIX_KERNEL_${2:header}_H__", "#define __FENNIX_KERNEL_${1:header}_H__",
"", "",
"#include <types.h>", "#include <types.h>",
"", "",
"$0", "$0",
"", "",
"#endif // !__FENNIX_KERNEL_${2:header}_H__", "#endif // !__FENNIX_KERNEL_${1:header}_H__",
"" ""
], ],
"description": "Create kernel header." "description": "Create kernel header."
@ -42,7 +42,7 @@
], ],
"description": "Create kernel documentation brief." "description": "Create kernel documentation brief."
}, },
"For Iteratoion": { "For Iteration": {
"prefix": [ "prefix": [
"foritr", "foritr",
], ],
@ -77,5 +77,134 @@
"*/" "*/"
], ],
"description": "Create kernel license." "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 <https://www.gnu.org/licenses/>.",
"*/",
"",
"#include \"${1:driver}.hpp\"",
"",
"#include <debug.h>",
"",
"#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 <https://www.gnu.org/licenses/>.",
"*/",
"",
"#pragma once",
"#include <driver.hpp>",
"",
"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."
} }
} }

View File

@ -19,6 +19,9 @@
"a86", "a86",
"DEBUG=\"1\"" "DEBUG=\"1\""
], ],
"forcedInclude": [
"${workspaceFolder}/.vscode/preinclude.h"
],
"compilerPath": "${workspaceFolder}/../tools/cross/bin/x86_64-fennix-gcc", "compilerPath": "${workspaceFolder}/../tools/cross/bin/x86_64-fennix-gcc",
"cStandard": "c17", "cStandard": "c17",
"cppStandard": "c++20", "cppStandard": "c++20",
@ -34,7 +37,6 @@
"-mcmodel=kernel", "-mcmodel=kernel",
"-fno-builtin", "-fno-builtin",
"-m64", "-m64",
// Warnings // Warnings
"-Wall", "-Wall",
"-Wextra", "-Wextra",
@ -46,11 +48,9 @@
"-Wswitch-default", "-Wswitch-default",
"-Wstrict-overflow=5", "-Wstrict-overflow=5",
"-Wconversion", "-Wconversion",
// C++ flags // C++ flags
"-fno-rtti", "-fno-rtti",
"-fno-exceptions", "-fno-exceptions",
// Linker flags // Linker flags
"-T${workspaceFolder}/arch/amd64/linker.ld", "-T${workspaceFolder}/arch/amd64/linker.ld",
"-Wl,-static,--no-dynamic-linker,-ztext", "-Wl,-static,--no-dynamic-linker,-ztext",
@ -59,7 +59,6 @@
"-nolibc", "-nolibc",
"-zmax-page-size=0x1000", "-zmax-page-size=0x1000",
"-shared", "-shared",
// Debug flags // Debug flags
"-ggdb3", "-ggdb3",
"-O0", "-O0",
@ -68,7 +67,6 @@
"-fstack-usage", "-fstack-usage",
"-fstack-check", "-fstack-check",
"-fsanitize=undefined", "-fsanitize=undefined",
// VSCode flags // VSCode flags
"-ffreestanding", "-ffreestanding",
"-nostdinc", "-nostdinc",
@ -112,7 +110,6 @@
"-msoft-float", "-msoft-float",
"-fno-builtin", "-fno-builtin",
"-m32", "-m32",
// Warnings // Warnings
"-Wall", "-Wall",
"-Wextra", "-Wextra",
@ -124,11 +121,9 @@
"-Wswitch-default", "-Wswitch-default",
"-Wstrict-overflow=5", "-Wstrict-overflow=5",
"-Wconversion", "-Wconversion",
// C++ flags // C++ flags
"-fno-rtti", "-fno-rtti",
"-fno-exceptions", "-fno-exceptions",
// Linker flags // Linker flags
"-T${workspaceFolder}/arch/i386/linker.ld", "-T${workspaceFolder}/arch/i386/linker.ld",
"-Wl,-static,--no-dynamic-linker,-ztext", "-Wl,-static,--no-dynamic-linker,-ztext",
@ -137,7 +132,6 @@
"-nolibc", "-nolibc",
"-zmax-page-size=0x1000", "-zmax-page-size=0x1000",
"-shared", "-shared",
// Debug flags // Debug flags
"-ggdb3", "-ggdb3",
"-O0", "-O0",
@ -146,7 +140,6 @@
"-fstack-usage", "-fstack-usage",
"-fstack-check", "-fstack-check",
"-fsanitize=undefined", "-fsanitize=undefined",
// VSCode flags // VSCode flags
"-ffreestanding", "-ffreestanding",
"-nostdinc", "-nostdinc",
@ -183,7 +176,6 @@
"-msoft-float", "-msoft-float",
"-fPIC", "-fPIC",
"-Wstack-protector", "-Wstack-protector",
// Warnings // Warnings
"-Wall", "-Wall",
"-Wextra", "-Wextra",
@ -195,15 +187,12 @@
"-Wswitch-default", "-Wswitch-default",
"-Wstrict-overflow=5", "-Wstrict-overflow=5",
"-Wconversion", "-Wconversion",
// C++ flags // C++ flags
"-fno-rtti", "-fno-rtti",
"-fno-exceptions", "-fno-exceptions",
// Linker flags // Linker flags
"-T${workspaceFolder}/arch/aarch64/linker.ld", "-T${workspaceFolder}/arch/aarch64/linker.ld",
"-fPIC", "-fPIC",
// Debug flags // Debug flags
"-ggdb3", "-ggdb3",
"-O0", "-O0",
@ -212,7 +201,6 @@
"-fstack-usage", "-fstack-usage",
"-fstack-check", "-fstack-check",
"-fsanitize=undefined", "-fsanitize=undefined",
// VSCode flags // VSCode flags
"-ffreestanding", "-ffreestanding",
"-nostdinc", "-nostdinc",

90
.vscode/launch.json vendored
View File

@ -5,7 +5,7 @@
"name": "Attach to a running VM instance", "name": "Attach to a running VM instance",
"type": "cppdbg", "type": "cppdbg",
"request": "launch", "request": "launch",
"program": "${workspaceFolder}/kernel.fsys", "program": "${workspaceFolder}/fennix.elf",
"cwd": "${workspaceFolder}", "cwd": "${workspaceFolder}",
"args": [], "args": [],
"targetArchitecture": "x64", "targetArchitecture": "x64",
@ -31,63 +31,20 @@
"description": "Make breakpoint pending on future shared library load." "description": "Make breakpoint pending on future shared library load."
}, },
{ {
"text": "file ${workspaceFolder}/kernel.fsys", "text": "file ${workspaceFolder}/fennix.elf",
"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",
"description": "Load binary." "description": "Load binary."
}, },
{ {
"text": "add-symbol-file ${workspaceFolder}/../initrd_tmp_data/bin/init", "text": "source ${workspaceFolder}/.gdbinit"
"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."
},
], ],
"preLaunchTask": "launch-qemu"
}, },
{ {
"name": "Attach to VM w/utest", "name": "Attach to VM w/utest",
"type": "cppdbg", "type": "cppdbg",
"request": "launch", "request": "launch",
"program": "${workspaceFolder}/kernel.fsys", "program": "${workspaceFolder}/fennix.elf",
"cwd": "${workspaceFolder}", "cwd": "${workspaceFolder}",
"args": [], "args": [],
"targetArchitecture": "x64", "targetArchitecture": "x64",
@ -113,20 +70,25 @@
"description": "Make breakpoint pending on future shared library load." "description": "Make breakpoint pending on future shared library load."
}, },
{ {
"text": "file ${workspaceFolder}/kernel.fsys", "text": "file ${workspaceFolder}/fennix.elf",
"description": "Load binary." "description": "Load binary."
}, },
{ {
"text": "add-symbol-file ${workspaceFolder}/../initrd_tmp_data/bin/utest", "text": "add-symbol-file ${workspaceFolder}/../initrd_tmp_data/bin/utest",
"description": "Load /bin/utest." "description": "Load /bin/utest.",
}, "ignoreFailures": true
],
}, },
{ {
"name": "Attach to VM w/doom", "text": "source ${workspaceFolder}/.gdbinit"
}
],
"preLaunchTask": "launch-qemu",
},
{
"name": "Attach to VM w/utest_linux",
"type": "cppdbg", "type": "cppdbg",
"request": "launch", "request": "launch",
"program": "${workspaceFolder}/kernel.fsys", "program": "${workspaceFolder}/fennix.elf",
"cwd": "${workspaceFolder}", "cwd": "${workspaceFolder}",
"args": [], "args": [],
"targetArchitecture": "x64", "targetArchitecture": "x64",
@ -152,14 +114,24 @@
"description": "Make breakpoint pending on future shared library load." "description": "Make breakpoint pending on future shared library load."
}, },
{ {
"text": "file ${workspaceFolder}/kernel.fsys", "text": "file ${workspaceFolder}/fennix.elf",
"description": "Load binary." "description": "Load binary."
}, },
{ {
"text": "add-symbol-file ${workspaceFolder}/../initrd_tmp_data/usr/bin/doom", "text": "set debug-file-directory /usr/lib/debug",
"description": "Load /usr/bin/doom." "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",
},
] ]
} }

7
.vscode/preinclude.h vendored Normal file
View File

@ -0,0 +1,7 @@
#undef __linux__
#undef __WIN32__
#undef __WIN64__
#undef _WIN32
#undef _WIN64
#undef __APPLE__
#undef __clang__

26
.vscode/tasks.json vendored Normal file
View File

@ -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"]
}
}
}
]
}

View File

@ -8,6 +8,9 @@ License information can be found in the [LICENSES.md](LICENSES.md) file.
- [OSDev Wiki](https://wiki.osdev.org/Main_Page) - [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 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) - [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 ## Font
- [Tamsyn Font](http://www.fial.com/~scott/tamsyn-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 ## Audio
- [FFmpeg Audio Types](https://trac.ffmpeg.org/wiki/audio%20types) - [FFmpeg Audio Types](https://trac.ffmpeg.org/wiki/audio%20types)
- [AC97 on OSDev](https://wiki.osdev.org/AC97) - [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) - [AC97 Revision 2.3 Specification](https://inst.eecs.berkeley.edu//~cs150/Documents/ac97_r23.pdf)
## Intrinsics (x86) ## 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) - [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) - [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 ## signal.h
- [POSIX signal.h](https://pubs.opengroup.org/onlinepubs/009695399/basedefs/signal.h.html) - [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) - [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! Special thanks to all contributors and the creators of the referenced projects and resources!

View File

@ -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 # 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. # 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 # 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 # 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 # spaces. See also FILE_PATTERNS and EXTENSION_MAPPING
# Note: If this tag is empty the current directory is searched. # 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 # 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 # 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 # (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. # 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 # Configuration options related to source browsing

161
Fex.hpp
View File

@ -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__

View File

@ -39,6 +39,16 @@ Make sure to read and comply with these licenses before using or redistributing
- **License:** Public Domain - **License:** Public Domain
- **Location:** [https://raw.githubusercontent.com/blanham/liballoc/master/LICENSE](https://raw.githubusercontent.com/blanham/liballoc/master/LICENSE) - **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. Please refer to the respective license files for the full text of each license.

View File

@ -1,7 +1,7 @@
# Config file # Config file
include ../Makefile.conf include ../Makefile.conf
KERNEL_FILENAME = kernel.fsys KERNEL_FILENAME = fennix.elf
CC = ../$(COMPILER_PATH)/$(COMPILER_ARCH)gcc CC = ../$(COMPILER_PATH)/$(COMPILER_ARCH)gcc
CPP = ../$(COMPILER_PATH)/$(COMPILER_ARCH)g++ CPP = ../$(COMPILER_PATH)/$(COMPILER_ARCH)g++

40
TODO.md
View File

@ -1,20 +1,24 @@
# TODO
---
- [x] Optimize SMP. - [x] Optimize SMP.
- [ ] Support IPv6. - [ ] 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). - [ ] 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. - [ ] Implementation of logging (beside serial) with log rotation.
- [x] Implement a better task manager. (replace struct P/TCB with classes) - [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. - [ ] 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. - [ ] 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. - [ ] Implement a better Display::SetBrightness() function.
- [ ] Fix memcpy, memset and memcmp functions (they are not working properly with SIMD). - [ ] Fix memcpy, memset and memcmp functions (they are not working properly with SIMD).
- [x] Fully support i386. - [ ] Fully support i386.
- [ ] Support Aarch64. - [ ] 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. - [ ] Rework the stack guard.
- [x] Mutex implementation. - [x] Mutex implementation.
- [ ] Update SMBIOS functions to support newer versions and actually use it. - [ ] Update SMBIOS functions to support newer versions and actually use it.
@ -22,7 +26,23 @@
- [ ] Implement lazy allocation. (page faults) - [ ] Implement lazy allocation. (page faults)
- [ ] Bootstrap should have a separate bss section + PHDR. - [ ] Bootstrap should have a separate bss section + PHDR.
- [ ] Reimplement the driver conflict detection. - [ ] 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. - [ ] Use NX-bit.
- [ ] Fix std::string - [ ] Fix std::string.
- [ ] Rewrite PS/2 drivers. - [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.

View File

@ -33,7 +33,7 @@ using namespace CPU::x64;
using namespace CPU::x86; using namespace CPU::x86;
/* /*
In constructor APIC::APIC::APIC(int): In constructor 'APIC::APIC::APIC(int)':
warning: left shift count >= width of type warning: left shift count >= width of type
| APICBaseAddress = BaseStruct.ApicBaseLo << 12u | BaseStruct.ApicBaseHi << 32u; | APICBaseAddress = BaseStruct.ApicBaseLo << 12u | BaseStruct.ApicBaseHi << 32u;
| ~~~~~~~~~~~~~~~~~~~~~~^~~~~~ | ~~~~~~~~~~~~~~~~~~~~~~^~~~~~
@ -55,8 +55,8 @@ namespace APIC
debug("APIC::Read(%#lx) [x2=%d]", debug("APIC::Read(%#lx) [x2=%d]",
Register, x2APICSupported ? 1 : 0); Register, x2APICSupported ? 1 : 0);
#endif #endif
if (x2APICSupported) if (unlikely(x2APICSupported))
assert(false); assert(!"x2APIC is not supported");
CPU::MemBar::Barrier(); CPU::MemBar::Barrier();
uint32_t ret = *((volatile uint32_t *)((uintptr_t)APICBaseAddress + Register)); uint32_t ret = *((volatile uint32_t *)((uintptr_t)APICBaseAddress + Register));
@ -76,8 +76,8 @@ namespace APIC
debug("APIC::Write(%#lx, %#lx) [x2=%d]", debug("APIC::Write(%#lx, %#lx) [x2=%d]",
Register, Value, x2APICSupported ? 1 : 0); Register, Value, x2APICSupported ? 1 : 0);
#endif #endif
if (x2APICSupported) if (unlikely(x2APICSupported))
assert(false); assert(!"x2APIC is not supported");
CPU::MemBar::Barrier(); CPU::MemBar::Barrier();
*((volatile uint32_t *)(((uintptr_t)APICBaseAddress) + Register)) = Value; *((volatile uint32_t *)(((uintptr_t)APICBaseAddress) + Register)) = Value;
@ -107,6 +107,8 @@ namespace APIC
void APIC::EOI() void APIC::EOI()
{ {
Memory::SwapPT swap =
Memory::SwapPT(KernelPageTable, thisPageTable);
if (this->x2APICSupported) if (this->x2APICSupported)
wrmsr(MSR_X2APIC_EOI, 0); wrmsr(MSR_X2APIC_EOI, 0);
else else
@ -396,20 +398,18 @@ namespace APIC
APIC::~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) void Timer::OneShot(uint32_t Vector, uint64_t Miliseconds)
{ {
SmartCriticalSection(APICLock); /* FIXME: Sometimes APIC stops firing when debugging, why? */
LVTTimer timer{}; LVTTimer timer{};
timer.VEC = uint8_t(Vector); timer.VEC = uint8_t(Vector);
timer.TMM = LVTTimerMode::OneShot; timer.TMM = LVTTimerMode::OneShot;
LVTTimerDivide Divider = DivideBy8; LVTTimerDivide Divider = DivideBy8;
if (unlikely(strcmp(CPU::Hypervisor(), x86_CPUID_VENDOR_TCG) != 0)) SmartCriticalSection(APICLock);
Divider = DivideBy128;
if (this->lapic->x2APIC) if (this->lapic->x2APIC)
{ {
// wrmsr(MSR_X2APIC_DIV_CONF, Divider); <- gpf on real hardware // wrmsr(MSR_X2APIC_DIV_CONF, Divider); <- gpf on real hardware

View File

@ -373,7 +373,7 @@ namespace APIC
private: private:
APIC *lapic; APIC *lapic;
uint64_t Ticks = 0; uint64_t Ticks = 0;
void OnInterruptReceived(CPU::x64::TrapFrame *Frame); void OnInterruptReceived(CPU::TrapFrame *Frame);
public: public:
uint64_t GetTicks() { return Ticks; } uint64_t GetTicks() { return Ticks; }

View File

@ -122,7 +122,7 @@ namespace GlobalDescriptorTable
SafeFunction void Init(int Core) SafeFunction void Init(int Core)
{ {
memcpy(&GDTEntries[Core], &GDTEntriesTemplate, sizeof(GlobalDescriptorTableEntries)); GDTEntries[Core] = GDTEntriesTemplate;
gdt[Core] = gdt[Core] =
{ {
.Limit = sizeof(GlobalDescriptorTableEntries) - 1, .Limit = sizeof(GlobalDescriptorTableEntries) - 1,

View File

@ -25,7 +25,7 @@
#include "gdt.hpp" #include "gdt.hpp"
#include "../../../kernel.h" #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" #pragma GCC diagnostic ignored "-Wconversion"
extern "C" void MainInterruptHandler(void *Data); extern "C" void MainInterruptHandler(void *Data);
@ -532,11 +532,11 @@ namespace InterruptDescriptorTable
} }
bool EnableISRs = true; bool EnableISRs = true;
#ifdef DEBUG // #ifdef DEBUG
EnableISRs = !DebuggerIsAttached; EnableISRs = !DebuggerIsAttached;
if (!EnableISRs) if (!EnableISRs)
KPrint("\eFFA500The debugger is attached, disabling all ISRs."); KPrint("\eFFA500The debugger is attached, disabling all ISRs.");
#endif // #endif
/* ISR */ /* ISR */
SetEntry(0x0, InterruptHandler_0x0, IST1, TRAP_GATE_64BIT, RING0, EnableISRs, GDT_KERNEL_CODE); 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(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(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(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(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(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); SetEntry(0x11, InterruptHandler_0x11, IST1, TRAP_GATE_64BIT, RING0, EnableISRs, GDT_KERNEL_CODE);

View File

@ -57,6 +57,9 @@ SafeFunction CPUData *GetCurrentCPU()
int CoreID = 0; int CoreID = 0;
if (CPUEnabled.load(std::memory_order_acquire) == true) if (CPUEnabled.load(std::memory_order_acquire) == true)
{ {
Memory::SwapPT swap =
Memory::SwapPT(KernelPageTable, thisPageTable);
if (apic->x2APIC) if (apic->x2APIC)
CoreID = int(CPU::x64::rdmsr(CPU::x64::MSR_X2APIC_APICID)); CoreID = int(CPU::x64::rdmsr(CPU::x64::MSR_X2APIC_APICID));
else else
@ -125,7 +128,8 @@ namespace SMP
(uintptr_t)&_trampoline_start; (uintptr_t)&_trampoline_start;
Memory::Virtual().Map(0x0, 0x0, Memory::PTFlag::RW); Memory::Virtual().Map(0x0, 0x0, Memory::PTFlag::RW);
/* We reserved the TRAMPOLINE_START address inside Physical class. */ /* 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); TrampolineLength, Memory::PTFlag::RW);
memcpy((void *)TRAMPOLINE_START, &_trampoline_start, TrampolineLength); memcpy((void *)TRAMPOLINE_START, &_trampoline_start, TrampolineLength);
debug("Trampoline address: %#lx-%#lx", debug("Trampoline address: %#lx-%#lx",

View File

@ -29,7 +29,7 @@ namespace Memory
Address &= 0xFFFFFFFFFFFFF000; Address &= 0xFFFFFFFFFFFFF000;
PageMapIndexer Index = PageMapIndexer(Address); PageMapIndexer Index = PageMapIndexer(Address);
PageMapLevel4 *PML4 = &this->Table->Entries[Index.PMLIndex]; PageMapLevel4 *PML4 = &this->pTable->Entries[Index.PMLIndex];
PageDirectoryPointerTableEntryPtr *PDPTE = nullptr; PageDirectoryPointerTableEntryPtr *PDPTE = nullptr;
PageDirectoryEntryPtr *PDE = nullptr; PageDirectoryEntryPtr *PDE = nullptr;
@ -74,7 +74,7 @@ namespace Memory
Address &= 0xFFFFFFFFFFFFF000; Address &= 0xFFFFFFFFFFFFF000;
PageMapIndexer Index = PageMapIndexer(Address); PageMapIndexer Index = PageMapIndexer(Address);
PageMapLevel4 *PML4 = &this->Table->Entries[Index.PMLIndex]; PageMapLevel4 *PML4 = &this->pTable->Entries[Index.PMLIndex];
PageDirectoryPointerTableEntryPtr *PDPTE = nullptr; PageDirectoryPointerTableEntryPtr *PDPTE = nullptr;
PageDirectoryEntryPtr *PDE = nullptr; PageDirectoryEntryPtr *PDE = nullptr;
@ -119,7 +119,7 @@ namespace Memory
Address &= 0xFFFFFFFFFFFFF000; Address &= 0xFFFFFFFFFFFFF000;
PageMapIndexer Index = PageMapIndexer(Address); PageMapIndexer Index = PageMapIndexer(Address);
PageMapLevel4 *PML4 = &this->Table->Entries[Index.PMLIndex]; PageMapLevel4 *PML4 = &this->pTable->Entries[Index.PMLIndex];
PageDirectoryPointerTableEntryPtr *PDPTE = nullptr; PageDirectoryPointerTableEntryPtr *PDPTE = nullptr;
PageDirectoryEntryPtr *PDE = nullptr; PageDirectoryEntryPtr *PDE = nullptr;
@ -172,9 +172,11 @@ namespace Memory
Address &= 0xFFFFFFFFFFFFF000; Address &= 0xFFFFFFFFFFFFF000;
PageMapIndexer Index = PageMapIndexer(Address); PageMapIndexer Index = PageMapIndexer(Address);
PageMapLevel4 *PML4 = &this->Table->Entries[Index.PMLIndex]; PageMapLevel4 *PML4 = &this->pTable->Entries[Index.PMLIndex];
if (PML4->Present) if (PML4->Present)
return PML4; return PML4;
debug("PML4 not present for %#lx", VirtualAddress);
return nullptr; return nullptr;
} }
@ -185,14 +187,19 @@ namespace Memory
Address &= 0xFFFFFFFFFFFFF000; Address &= 0xFFFFFFFFFFFFF000;
PageMapIndexer Index = PageMapIndexer(Address); PageMapIndexer Index = PageMapIndexer(Address);
PageMapLevel4 *PML4 = &this->Table->Entries[Index.PMLIndex]; PageMapLevel4 *PML4 = &this->pTable->Entries[Index.PMLIndex];
if (!PML4->Present) if (!PML4->Present)
{
debug("PML4 not present for %#lx", VirtualAddress);
return nullptr; return nullptr;
}
PageDirectoryPointerTableEntryPtr *PDPTEPtr = (PageDirectoryPointerTableEntryPtr *)((uintptr_t)PML4->Address << 12); PageDirectoryPointerTableEntryPtr *PDPTEPtr = (PageDirectoryPointerTableEntryPtr *)((uintptr_t)PML4->Address << 12);
PageDirectoryPointerTableEntry *PDPTE = &PDPTEPtr->Entries[Index.PDPTEIndex]; PageDirectoryPointerTableEntry *PDPTE = &PDPTEPtr->Entries[Index.PDPTEIndex];
if (PDPTE->Present) if (PDPTE->Present)
return PDPTE; return PDPTE;
debug("PDPTE not present for %#lx", VirtualAddress);
return nullptr; return nullptr;
} }
@ -203,19 +210,27 @@ namespace Memory
Address &= 0xFFFFFFFFFFFFF000; Address &= 0xFFFFFFFFFFFFF000;
PageMapIndexer Index = PageMapIndexer(Address); PageMapIndexer Index = PageMapIndexer(Address);
PageMapLevel4 *PML4 = &this->Table->Entries[Index.PMLIndex]; PageMapLevel4 *PML4 = &this->pTable->Entries[Index.PMLIndex];
if (!PML4->Present) if (!PML4->Present)
{
debug("PML4 not present for %#lx", VirtualAddress);
return nullptr; return nullptr;
}
PageDirectoryPointerTableEntryPtr *PDPTEPtr = (PageDirectoryPointerTableEntryPtr *)((uintptr_t)PML4->Address << 12); PageDirectoryPointerTableEntryPtr *PDPTEPtr = (PageDirectoryPointerTableEntryPtr *)((uintptr_t)PML4->Address << 12);
PageDirectoryPointerTableEntry *PDPTE = &PDPTEPtr->Entries[Index.PDPTEIndex]; PageDirectoryPointerTableEntry *PDPTE = &PDPTEPtr->Entries[Index.PDPTEIndex];
if (!PDPTE->Present) if (!PDPTE->Present)
{
debug("PDPTE not present for %#lx", VirtualAddress);
return nullptr; return nullptr;
}
PageDirectoryEntryPtr *PDEPtr = (PageDirectoryEntryPtr *)(PDPTE->GetAddress() << 12); PageDirectoryEntryPtr *PDEPtr = (PageDirectoryEntryPtr *)(PDPTE->GetAddress() << 12);
PageDirectoryEntry *PDE = &PDEPtr->Entries[Index.PDEIndex]; PageDirectoryEntry *PDE = &PDEPtr->Entries[Index.PDEIndex];
if (PDE->Present) if (PDE->Present)
return PDE; return PDE;
debug("PDE not present for %#lx", VirtualAddress);
return nullptr; return nullptr;
} }
@ -226,31 +241,42 @@ namespace Memory
Address &= 0xFFFFFFFFFFFFF000; Address &= 0xFFFFFFFFFFFFF000;
PageMapIndexer Index = PageMapIndexer(Address); PageMapIndexer Index = PageMapIndexer(Address);
PageMapLevel4 *PML4 = &this->Table->Entries[Index.PMLIndex]; PageMapLevel4 *PML4 = &this->pTable->Entries[Index.PMLIndex];
if (!PML4->Present) if (!PML4->Present)
{
debug("PML4 not present for %#lx", VirtualAddress);
return nullptr; return nullptr;
}
PageDirectoryPointerTableEntryPtr *PDPTEPtr = (PageDirectoryPointerTableEntryPtr *)((uintptr_t)PML4->Address << 12); PageDirectoryPointerTableEntryPtr *PDPTEPtr = (PageDirectoryPointerTableEntryPtr *)((uintptr_t)PML4->Address << 12);
PageDirectoryPointerTableEntry *PDPTE = &PDPTEPtr->Entries[Index.PDPTEIndex]; PageDirectoryPointerTableEntry *PDPTE = &PDPTEPtr->Entries[Index.PDPTEIndex];
if (!PDPTE->Present) if (!PDPTE->Present)
{
debug("PDPTE not present for %#lx", VirtualAddress);
return nullptr; return nullptr;
}
PageDirectoryEntryPtr *PDEPtr = (PageDirectoryEntryPtr *)(PDPTE->GetAddress() << 12); PageDirectoryEntryPtr *PDEPtr = (PageDirectoryEntryPtr *)(PDPTE->GetAddress() << 12);
PageDirectoryEntry *PDE = &PDEPtr->Entries[Index.PDEIndex]; PageDirectoryEntry *PDE = &PDEPtr->Entries[Index.PDEIndex];
if (!PDE->Present) if (!PDE->Present)
{
debug("PDE not present for %#lx", VirtualAddress);
return nullptr; return nullptr;
}
PageTableEntryPtr *PTEPtr = (PageTableEntryPtr *)(PDE->GetAddress() << 12); PageTableEntryPtr *PTEPtr = (PageTableEntryPtr *)(PDE->GetAddress() << 12);
PageTableEntry *PTE = &PTEPtr->Entries[Index.PTEIndex]; PageTableEntry *PTE = &PTEPtr->Entries[Index.PTEIndex];
if (PTE->Present) if (PTE->Present)
return PTE; return PTE;
debug("PTE not present for %#lx", VirtualAddress);
return nullptr; return nullptr;
} }
void Virtual::Map(void *VirtualAddress, void *PhysicalAddress, uint64_t Flags, MapType Type) void Virtual::Map(void *VirtualAddress, void *PhysicalAddress, uint64_t Flags, MapType Type)
{ {
SmartLock(this->MemoryLock); SmartLock(this->MemoryLock);
if (unlikely(!this->Table)) if (unlikely(!this->pTable))
{ {
error("No page table"); error("No page table");
return; 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 // 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; uint64_t DirectoryFlags = Flags & 0x3F;
PageMapLevel4 *PML4 = &this->Table->Entries[Index.PMLIndex]; PageMapLevel4 *PML4 = &this->pTable->Entries[Index.PMLIndex];
PageDirectoryPointerTableEntryPtr *PDPTEPtr = nullptr; PageDirectoryPointerTableEntryPtr *PDPTEPtr = nullptr;
if (!PML4->Present) if (!PML4->Present)
{ {
@ -323,7 +349,7 @@ namespace Memory
PTE->Present = true; PTE->Present = true;
PTE->raw |= Flags; PTE->raw |= Flags;
PTE->SetAddress((uintptr_t)PhysicalAddress >> 12); PTE->SetAddress((uintptr_t)PhysicalAddress >> 12);
CPU::x32::invlpg(VirtualAddress); CPU::x64::invlpg(VirtualAddress);
#ifdef DEBUG #ifdef DEBUG
/* https://stackoverflow.com/a/3208376/9352057 */ /* https://stackoverflow.com/a/3208376/9352057 */
@ -346,14 +372,14 @@ namespace Memory
void Virtual::Unmap(void *VirtualAddress, MapType Type) void Virtual::Unmap(void *VirtualAddress, MapType Type)
{ {
SmartLock(this->MemoryLock); SmartLock(this->MemoryLock);
if (!this->Table) if (!this->pTable)
{ {
error("No page table"); error("No page table");
return; return;
} }
PageMapIndexer Index = PageMapIndexer((uintptr_t)VirtualAddress); PageMapIndexer Index = PageMapIndexer((uintptr_t)VirtualAddress);
PageMapLevel4 *PML4 = &this->Table->Entries[Index.PMLIndex]; PageMapLevel4 *PML4 = &this->pTable->Entries[Index.PMLIndex];
if (!PML4->Present) if (!PML4->Present)
{ {
warn("Page %#lx not present", PML4->GetAddress()); warn("Page %#lx not present", PML4->GetAddress());
@ -398,6 +424,6 @@ namespace Memory
PTE.Present = false; PTE.Present = false;
PTEPtr->Entries[Index.PTEIndex] = PTE; PTEPtr->Entries[Index.PTEIndex] = PTE;
CPU::x32::invlpg(VirtualAddress); CPU::x64::invlpg(VirtualAddress);
} }
} }

View File

@ -15,24 +15,24 @@
along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>. along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
*/ */
#ifndef __FENNIX_KERNEL_AMD_PCNET_H__ .code64
#define __FENNIX_KERNEL_AMD_PCNET_H__
#include <types.h> .global _sig_native_trampoline_start
#include "../../mapi.hpp" _sig_native_trampoline_start:
int $0x3
namespace PCNET .global _sig_native_trampoline_end
{ _sig_native_trampoline_end:
struct BARData
{
uint8_t Type;
uint16_t IOBase;
uint64_t MemoryBase;
};
int DriverEntry(void *); .global _sig_linux_trampoline_start
int CallbackHandler(KernelCallback *); _sig_linux_trampoline_start:
int InterruptCallback(CPURegisters *); 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:

View File

@ -33,7 +33,7 @@ using namespace CPU::x32;
using namespace CPU::x86; using namespace CPU::x86;
/* /*
In constructor APIC::APIC::APIC(int): In constructor 'APIC::APIC::APIC(int)':
warning: left shift count >= width of type warning: left shift count >= width of type
| APICBaseAddress = BaseStruct.ApicBaseLo << 12u | BaseStruct.ApicBaseHi << 32u; | APICBaseAddress = BaseStruct.ApicBaseLo << 12u | BaseStruct.ApicBaseHi << 32u;
| ~~~~~~~~~~~~~~~~~~~~~~^~~~~~ | ~~~~~~~~~~~~~~~~~~~~~~^~~~~~
@ -358,7 +358,7 @@ namespace APIC
APIC::~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) void Timer::OneShot(uint32_t Vector, uint64_t Miliseconds)
{ {

View File

@ -343,7 +343,7 @@ namespace APIC
private: private:
APIC *lapic; APIC *lapic;
uint64_t Ticks = 0; uint64_t Ticks = 0;
void OnInterruptReceived(CPU::x32::TrapFrame *Frame); void OnInterruptReceived(CPU::TrapFrame *Frame);
public: public:
uint64_t GetTicks() { return Ticks; } uint64_t GetTicks() { return Ticks; }

View File

@ -25,7 +25,7 @@
#include "gdt.hpp" #include "gdt.hpp"
#include "../../../kernel.h" #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" #pragma GCC diagnostic ignored "-Wconversion"
extern "C" void MainInterruptHandler(void *Data); extern "C" void MainInterruptHandler(void *Data);
@ -461,11 +461,11 @@ namespace InterruptDescriptorTable
/* ISR */ /* ISR */
bool EnableISRs = true; bool EnableISRs = true;
#ifdef DEBUG // #ifdef DEBUG
EnableISRs = !DebuggerIsAttached; EnableISRs = !DebuggerIsAttached;
if (!EnableISRs) if (!EnableISRs)
KPrint("\eFFA500The debugger is attached, disabling all ISRs."); KPrint("\eFFA500The debugger is attached, disabling all ISRs.");
#endif // #endif
SetEntry(0x0, InterruptHandler_0x0, TRAP_GATE_32BIT, RING0, EnableISRs, GDT_KERNEL_CODE); SetEntry(0x0, InterruptHandler_0x0, TRAP_GATE_32BIT, RING0, EnableISRs, GDT_KERNEL_CODE);
SetEntry(0x1, InterruptHandler_0x1, TRAP_GATE_32BIT, RING0, EnableISRs, GDT_KERNEL_CODE); SetEntry(0x1, InterruptHandler_0x1, TRAP_GATE_32BIT, RING0, EnableISRs, GDT_KERNEL_CODE);

View File

@ -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 <https://www.gnu.org/licenses/>.
*/
#include "kernel.h"
#include <filesystem/ustar.hpp>
#include <kshell.hpp>
#include <power.hpp>
#include <lock.hpp>
#include <printf.h>
#include <exec.hpp>
#include <cwalk.h>
#include <vm.hpp>
#include <vector>
#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 <stb/image.h>
#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);
}
}

View File

@ -40,13 +40,23 @@ namespace ACPI
#pragma GCC diagnostic pop #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]) if (SDTHdr->Signature[i] != Signature[i])
break; break;
if (i == 3) 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; return SDTHdr;
} }
} }
@ -70,6 +80,9 @@ namespace ACPI
WAET = (WAETHeader *)FindTable(Header, (char *)"WAET"); WAET = (WAETHeader *)FindTable(Header, (char *)"WAET");
MADT = (MADTHeader *)FindTable(Header, (char *)"APIC"); MADT = (MADTHeader *)FindTable(Header, (char *)"APIC");
HEST = (HESTHeader *)FindTable(Header, (char *)"HEST"); 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 *)"BERT");
FindTable(Header, (char *)"CPEP"); FindTable(Header, (char *)"CPEP");
FindTable(Header, (char *)"DSDT"); FindTable(Header, (char *)"DSDT");
@ -86,7 +99,6 @@ namespace ACPI
FindTable(Header, (char *)"RSDT"); FindTable(Header, (char *)"RSDT");
FindTable(Header, (char *)"SBST"); FindTable(Header, (char *)"SBST");
FindTable(Header, (char *)"SLIT"); FindTable(Header, (char *)"SLIT");
FindTable(Header, (char *)"SSDT");
FindTable(Header, (char *)"XSDT"); FindTable(Header, (char *)"XSDT");
FindTable(Header, (char *)"DRTM"); FindTable(Header, (char *)"DRTM");
FindTable(Header, (char *)"FPDT"); FindTable(Header, (char *)"FPDT");
@ -102,8 +114,8 @@ namespace ACPI
FindTable(Header, (char *)"ASF!"); FindTable(Header, (char *)"ASF!");
FindTable(Header, (char *)"BOOT"); FindTable(Header, (char *)"BOOT");
FindTable(Header, (char *)"CSRT"); FindTable(Header, (char *)"CSRT");
FindTable(Header, (char *)"DBG2"); FindTable(Header, (char *)"BDAT");
FindTable(Header, (char *)"DBGP"); FindTable(Header, (char *)"CDAT");
FindTable(Header, (char *)"DMAR"); FindTable(Header, (char *)"DMAR");
FindTable(Header, (char *)"IBFT"); FindTable(Header, (char *)"IBFT");
FindTable(Header, (char *)"IORT"); FindTable(Header, (char *)"IORT");
@ -125,6 +137,28 @@ namespace ACPI
FindTable(Header, (char *)"HMAT"); FindTable(Header, (char *)"HMAT");
FindTable(Header, (char *)"CEDT"); FindTable(Header, (char *)"CEDT");
FindTable(Header, (char *)"AEST"); 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() ACPI::ACPI()
@ -161,8 +195,9 @@ namespace ACPI
if (FADT) if (FADT)
{ {
outb(s_cst(uint16_t, FADT->SMI_CommandPort), FADT->AcpiEnable); 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)) while (!(inw(s_cst(uint16_t, FADT->PM1aControlBlock)) & 1))
; CPU::Pause();
} }
} }

View File

@ -167,9 +167,9 @@ namespace CPU
: "=r"(Flags)); : "=r"(Flags));
return Flags & (1 << 9); return Flags & (1 << 9);
#elif defined(aa64) #elif defined(aa64)
asmv("mrs %0, daif" asmv("mrs %0, cpsr"
: "=r"(Flags)); : "=r"(Flags));
return !(Flags & (1 << 2)); return !(Flags & (1 << 7));
#endif #endif
} }
case Enable: case Enable:
@ -177,7 +177,7 @@ namespace CPU
#if defined(a86) #if defined(a86)
asmv("sti"); asmv("sti");
#elif defined(aa64) #elif defined(aa64)
asmv("msr daifclr, #2"); asmv("cpsie i");
#endif #endif
return true; return true;
} }
@ -186,7 +186,7 @@ namespace CPU
#if defined(a86) #if defined(a86)
asmv("cli"); asmv("cli");
#elif defined(aa64) #elif defined(aa64)
asmv("msr daifset, #2"); asmv("cpsid i");
#endif #endif
return true; return true;
} }
@ -198,32 +198,39 @@ namespace CPU
void *PageTable(void *PT) void *PageTable(void *PT)
{ {
void *ret;
#if defined(a64) #if defined(a64)
asmv("movq %%cr3, %0"
: "=r"(ret));
if (PT) if (PT)
{
asmv("movq %0, %%cr3" asmv("movq %0, %%cr3"
: :
: "r"(PT)); : "r"(PT));
else }
asmv("movq %%cr3, %0"
: "=r"(PT));
#elif defined(a32) #elif defined(a32)
asmv("movl %%cr3, %0"
: "=r"(ret));
if (PT) if (PT)
{
asmv("movl %0, %%cr3" asmv("movl %0, %%cr3"
: :
: "r"(PT)); : "r"(PT));
else }
asmv("movl %%cr3, %0"
: "=r"(PT));
#elif defined(aa64) #elif defined(aa64)
asmv("mrs %0, ttbr0_el1"
: "=r"(ret));
if (PT) if (PT)
{
asmv("msr ttbr0_el1, %0" asmv("msr ttbr0_el1, %0"
: :
: "r"(PT)); : "r"(PT));
else }
asmv("mrs %0, ttbr0_el1"
: "=r"(PT));
#endif #endif
return PT; return ret;
} }
struct SupportedFeat struct SupportedFeat
@ -378,7 +385,10 @@ namespace CPU
if (!BSP++) if (!BSP++)
trace("Features for BSP initialized."); trace("Features for BSP initialized.");
if (SSEEnableAfter) if (SSEEnableAfter)
{
SSEEnabled = true; SSEEnabled = true;
debug("SSE support enabled.");
}
} }
uint64_t Counter() uint64_t Counter()
@ -403,7 +413,8 @@ namespace CPU
if (unlikely(!SSEEnabled)) if (unlikely(!SSEEnabled))
return SIMD_NONE; return SIMD_NONE;
// return SIMD_SSE; #warning "TODO: Proper SIMD support"
return SIMD_NONE;
#if defined(a86) #if defined(a86)
static uint64_t SIMDType = SIMD_NONE; static uint64_t SIMDType = SIMD_NONE;
@ -415,13 +426,16 @@ namespace CPU
{ {
CPU::x86::AMD::CPUID0x00000001 cpuid; CPU::x86::AMD::CPUID0x00000001 cpuid;
asmv("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)); : "a"(0x1));
if (cpuid.ECX.SSE42) if (cpuid.ECX.SSE42)
SIMDType |= SIMD_SSE42; SIMDType |= SIMD_SSE42;
else if (cpuid.ECX.SSE41) else if (cpuid.ECX.SSE41)
SIMDType |= SIMD_SSE41; SIMDType |= SIMD_SSE41;
else if (cpuid.ECX.SSSE3)
SIMDType |= SIMD_SSSE3;
else if (cpuid.ECX.SSE3) else if (cpuid.ECX.SSE3)
SIMDType |= SIMD_SSE3; SIMDType |= SIMD_SSE3;
else if (cpuid.EDX.SSE2) else if (cpuid.EDX.SSE2)
@ -434,6 +448,8 @@ namespace CPU
debug("SSE4.2 is supported."); debug("SSE4.2 is supported.");
if (cpuid.ECX.SSE41) if (cpuid.ECX.SSE41)
debug("SSE4.1 is supported."); debug("SSE4.1 is supported.");
if (cpuid.ECX.SSSE3)
debug("SSSE3 is supported.");
if (cpuid.ECX.SSE3) if (cpuid.ECX.SSE3)
debug("SSE3 is supported."); debug("SSE3 is supported.");
if (cpuid.EDX.SSE2) if (cpuid.EDX.SSE2)
@ -455,6 +471,8 @@ namespace CPU
SIMDType |= SIMD_SSE42; SIMDType |= SIMD_SSE42;
else if (cpuid.ECX.SSE4_1) else if (cpuid.ECX.SSE4_1)
SIMDType |= SIMD_SSE41; SIMDType |= SIMD_SSE41;
else if (cpuid.ECX.SSSE3)
SIMDType |= SIMD_SSSE3;
else if (cpuid.ECX.SSE3) else if (cpuid.ECX.SSE3)
SIMDType |= SIMD_SSE3; SIMDType |= SIMD_SSE3;
else if (cpuid.EDX.SSE2) else if (cpuid.EDX.SSE2)
@ -467,6 +485,8 @@ namespace CPU
debug("SSE4.2 is supported."); debug("SSE4.2 is supported.");
if (cpuid.ECX.SSE4_1) if (cpuid.ECX.SSE4_1)
debug("SSE4.1 is supported."); debug("SSE4.1 is supported.");
if (cpuid.ECX.SSSE3)
debug("SSSE3 is supported.");
if (cpuid.ECX.SSE3) if (cpuid.ECX.SSE3)
debug("SSE3 is supported."); debug("SSE3 is supported.");
if (cpuid.EDX.SSE2) if (cpuid.EDX.SSE2)
@ -499,6 +519,8 @@ namespace CPU
return cpuid.ECX.SSE42; return cpuid.ECX.SSE42;
else if (Type == SIMD_SSE41) else if (Type == SIMD_SSE41)
return cpuid.ECX.SSE41; return cpuid.ECX.SSE41;
else if (Type == SIMD_SSSE3)
return cpuid.ECX.SSSE3;
else if (Type == SIMD_SSE3) else if (Type == SIMD_SSE3)
return cpuid.ECX.SSE3; return cpuid.ECX.SSE3;
else if (Type == SIMD_SSE2) else if (Type == SIMD_SSE2)
@ -517,6 +539,8 @@ namespace CPU
return cpuid.ECX.SSE4_2; return cpuid.ECX.SSE4_2;
else if (Type == SIMD_SSE41) else if (Type == SIMD_SSE41)
return cpuid.ECX.SSE4_1; return cpuid.ECX.SSE4_1;
else if (Type == SIMD_SSSE3)
return cpuid.ECX.SSSE3;
else if (Type == SIMD_SSE3) else if (Type == SIMD_SSE3)
return cpuid.ECX.SSE3; return cpuid.ECX.SSE3;
else if (Type == SIMD_SSE2) else if (Type == SIMD_SSE2)

View File

@ -274,14 +274,8 @@ namespace CrashHandler
{ {
private: private:
void PS2Wait(bool Read); 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: public:
CrashKeyboardDriver(); CrashKeyboardDriver();
~CrashKeyboardDriver(); ~CrashKeyboardDriver();

View File

@ -191,11 +191,11 @@ SafeFunction void PageFaultExceptionHandler(CHArchTrapFrame *Frame)
#endif #endif
#if defined(a64) #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) #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) #elif defined(aa64)
Memory::Virtual vmm = Memory::Virtual(); Memory::Virtual vmm();
#warning "TODO: aa64" #warning "TODO: aa64"
#endif #endif

View File

@ -40,7 +40,6 @@
#endif #endif
#include "../../kernel.h" #include "../../kernel.h"
#include "../../mapi.hpp"
NewLock(UserInputLock); NewLock(UserInputLock);
@ -411,7 +410,7 @@ namespace CrashHandler
#elif defined(aa64) #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 #endif
EHPrint("\e25CCC9%s", KernelSymbolTable->GetSymbolFromAddress((uintptr_t)EHIntFrames[i])); EHPrint("\e25CCC9%s", KernelSymbolTable->GetSymbol((uintptr_t)EHIntFrames[i]));
else else
EHPrint("\eFF4CA9Outside Kernel"); EHPrint("\eFF4CA9Outside Kernel");
#if defined(a86) #if defined(a86)
@ -726,7 +725,7 @@ namespace CrashHandler
uint64_t ProgressLength = TotalMemLength; uint64_t ProgressLength = TotalMemLength;
UniversalAsynchronousReceiverTransmitter::UART uart(port); UniversalAsynchronousReceiverTransmitter::UART uart(port);
Memory::Virtual vmm; Memory::Virtual vmm;
uint8_t *Address = reinterpret_cast<uint8_t *>(0x0); uint8_t *Address = 0x0;
int Progress = 0; int Progress = 0;
for (size_t i = 0; i < TotalMemLength; i++) 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. * Also it makes every core to stay at 100% usage for some reason.
*/ */
// if (SMP::CPUCores > 1) return;
// { if (SMP::CPUCores > 1)
// for (int i = 1; i < SMP::CPUCores; i++) {
// { APIC::InterruptCommandRegister icr{};
// APIC::InterruptCommandRegisterLow icr; bool x2APIC = ((APIC::APIC *)Interrupts::apic[0])->x2APIC;
// icr.Vector = CPU::x86::IRQ29;
// icr.Level = APIC::APICLevel::Assert; if (likely(x2APIC))
// ((APIC::APIC *)Interrupts::apic[i])->IPI(i, icr); {
// __sync; icr.x2.VEC = s_cst(uint8_t, CPU::x86::IRQ31);
// } icr.x2.MT = APIC::Fixed;
// } icr.x2.L = APIC::Assert;
// APIC::InterruptCommandRegisterLow icr;
// icr.Vector = CPU::x86::IRQ29; for (int i = 1; i < SMP::CPUCores; i++)
// icr.Level = APIC::APICLevel::Assert; {
// icr.DestinationShorthand = APIC::APICDestinationShorthand::AllExcludingSelf; icr.x2.DES = uint8_t(i);
// ((APIC::APIC *)Interrupts::apic[0])->IPI(0, icr); ((APIC::APIC *)Interrupts::apic[i])->ICR(icr);
// CPU::Interrupts(CPU::Enable); }
__sync; }
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); CPU::Interrupts(CPU::Disable);
// } }
#elif defined(aa64) #elif defined(aa64)
#endif #endif
} }
SafeFunction inline void Handle_x86_64(CHArchTrapFrame *Frame) SafeFunction inline bool Handle_x86_64(CHArchTrapFrame *Frame)
{ {
#ifdef a64 #ifdef a64
trace("Exception at %s",
KernelSymbolTable
? KernelSymbolTable->GetSymbol(Frame->rip)
: "No symbol");
for (size_t i = 0; i < INT_FRAMES_MAX; i++) for (size_t i = 0; i < INT_FRAMES_MAX; i++)
EHIntFrames[i] = Interrupts::InterruptFrames[i]; EHIntFrames[i] = Interrupts::InterruptFrames[i];
PageFaultAddress = CPU::x64::readcr2().PFLA; PageFaultAddress = CPU::x64::readcr2().PFLA;
@ -844,14 +860,14 @@ namespace CrashHandler
{ {
debug("Exception in kernel mode (ip: %#lx cr2: %#lx (%s))", debug("Exception in kernel mode (ip: %#lx cr2: %#lx (%s))",
Frame->rip, PageFaultAddress, Frame->rip, PageFaultAddress,
KernelSymbolTable ? KernelSymbolTable->GetSymbolFromAddress(Frame->rip) KernelSymbolTable ? KernelSymbolTable->GetSymbol(Frame->rip)
: "No symbol"); : "No symbol");
} }
else else
{ {
debug("Exception in kernel mode (ip: %#lx (%s))", debug("Exception in kernel mode (ip: %#lx (%s))",
Frame->rip, Frame->rip,
KernelSymbolTable ? KernelSymbolTable->GetSymbolFromAddress(Frame->rip) KernelSymbolTable ? KernelSymbolTable->GetSymbol(Frame->rip)
: "No symbol"); : "No symbol");
} }
@ -881,7 +897,7 @@ namespace CrashHandler
debug("Exception in user mode (ip: %#lx cr2: %#lx (%s))", debug("Exception in user mode (ip: %#lx cr2: %#lx (%s))",
Frame->rip, PageFaultAddress, Frame->rip, PageFaultAddress,
data->CurrentProcess->ELFSymbolTable data->CurrentProcess->ELFSymbolTable
? data->CurrentProcess->ELFSymbolTable->GetSymbolFromAddress(Frame->rip) ? data->CurrentProcess->ELFSymbolTable->GetSymbol(Frame->rip)
: "No symbol"); : "No symbol");
} }
else else
@ -889,16 +905,18 @@ namespace CrashHandler
debug("Exception in user mode (ip: %#lx (%s))", debug("Exception in user mode (ip: %#lx (%s))",
Frame->rip, Frame->rip,
data->CurrentProcess->ELFSymbolTable data->CurrentProcess->ELFSymbolTable
? data->CurrentProcess->ELFSymbolTable->GetSymbolFromAddress(Frame->rip) ? data->CurrentProcess->ELFSymbolTable->GetSymbol(Frame->rip)
: "No symbol"); : "No symbol");
} }
if (UserModeExceptionHandler(Frame)) if (UserModeExceptionHandler(Frame))
return; return true;
else if (DebuggerIsAttached)
asmv("int $0x8");
if (unlikely(data->CurrentThread->Security.IsCritical)) if (unlikely(data->CurrentThread->Security.IsCritical))
{ {
debug("Critical thread \"%s\"(%d) died", error("Critical thread \"%s\"(%d) died",
data->CurrentThread->Name, data->CurrentThread->Name,
data->CurrentThread->ID); data->CurrentThread->ID);
if (TaskManager) if (TaskManager)
@ -906,26 +924,29 @@ namespace CrashHandler
ForceUnlock = true; ForceUnlock = true;
Display->CreateBuffer(0, 0, SBIdx); Display->CreateBuffer(0, 0, SBIdx);
StopAllCores(); StopAllCores();
return; return false;
} }
Tasking::TCB *tcb = data->CurrentThread; Tasking::TCB *tcb = data->CurrentThread;
Tasking::Task *ctx = tcb->GetContext();
tcb->State = Tasking::Terminated;
tcb->ExitCode = Tasking::KILL_CRASH;
CPU::Interrupts(CPU::Enable); CPU::Interrupts(CPU::Enable);
while (true) while (true)
{ {
ctx->Yield(); tcb->GetContext()->Yield();
CPU::Halt(TaskManager->IsPanic()); CPU::Halt(TaskManager->IsPanic());
} }
} }
#endif #endif
return false;
} }
SafeFunction inline void Handle_x86_32(CHArchTrapFrame *Frame) SafeFunction inline bool Handle_x86_32(CHArchTrapFrame *Frame)
{ {
#ifdef a32 #ifdef a32
trace("Exception at %s",
KernelSymbolTable
? KernelSymbolTable->GetSymbol(Frame->eip)
: "No symbol");
for (size_t i = 0; i < INT_FRAMES_MAX; i++) for (size_t i = 0; i < INT_FRAMES_MAX; i++)
EHIntFrames[i] = Interrupts::InterruptFrames[i]; EHIntFrames[i] = Interrupts::InterruptFrames[i];
PageFaultAddress = CPU::x32::readcr2().PFLA; PageFaultAddress = CPU::x32::readcr2().PFLA;
@ -938,7 +959,7 @@ namespace CrashHandler
debug("Exception in kernel mode (ip: %#lx cr2: %#lx (%s))", debug("Exception in kernel mode (ip: %#lx cr2: %#lx (%s))",
Frame->eip, PageFaultAddress, Frame->eip, PageFaultAddress,
data->CurrentProcess->ELFSymbolTable data->CurrentProcess->ELFSymbolTable
? data->CurrentProcess->ELFSymbolTable->GetSymbolFromAddress(Frame->eip) ? data->CurrentProcess->ELFSymbolTable->GetSymbol(Frame->eip)
: "No symbol"); : "No symbol");
} }
else else
@ -946,12 +967,14 @@ namespace CrashHandler
debug("Exception in kernel mode (ip: %#lx (%s))", debug("Exception in kernel mode (ip: %#lx (%s))",
Frame->eip, Frame->eip,
data->CurrentProcess->ELFSymbolTable data->CurrentProcess->ELFSymbolTable
? data->CurrentProcess->ELFSymbolTable->GetSymbolFromAddress(Frame->eip) ? data->CurrentProcess->ELFSymbolTable->GetSymbol(Frame->eip)
: "No symbol"); : "No symbol");
} }
if (UserModeExceptionHandler(Frame)) if (UserModeExceptionHandler(Frame))
return; return true;
else if (DebuggerIsAttached)
asmv("int $0x8");
if (data->CurrentThread) if (data->CurrentThread)
{ {
@ -974,23 +997,25 @@ namespace CrashHandler
{ {
debug("Exception in user mode (ip: %#lx cr2: %#lx (%s))", debug("Exception in user mode (ip: %#lx cr2: %#lx (%s))",
Frame->eip, PageFaultAddress, Frame->eip, PageFaultAddress,
KernelSymbolTable ? KernelSymbolTable->GetSymbolFromAddress(Frame->eip) KernelSymbolTable ? KernelSymbolTable->GetSymbol(Frame->eip)
: "No symbol"); : "No symbol");
} }
else else
{ {
debug("Exception in user mode (ip: %#lx (%s))", debug("Exception in user mode (ip: %#lx (%s))",
Frame->eip, Frame->eip,
KernelSymbolTable ? KernelSymbolTable->GetSymbolFromAddress(Frame->eip) KernelSymbolTable ? KernelSymbolTable->GetSymbol(Frame->eip)
: "No symbol"); : "No symbol");
} }
if (UserModeExceptionHandler(Frame)) if (UserModeExceptionHandler(Frame))
return; return true;
else if (DebuggerIsAttached)
asmv("int $0x8");
if (unlikely(data->CurrentThread->Security.IsCritical)) if (unlikely(data->CurrentThread->Security.IsCritical))
{ {
debug("Critical thread \"%s\"(%d) died", error("Critical thread \"%s\"(%d) died",
data->CurrentThread->Name, data->CurrentThread->Name,
data->CurrentThread->ID); data->CurrentThread->ID);
if (TaskManager) if (TaskManager)
@ -998,21 +1023,19 @@ namespace CrashHandler
ForceUnlock = true; ForceUnlock = true;
Display->CreateBuffer(0, 0, SBIdx); Display->CreateBuffer(0, 0, SBIdx);
StopAllCores(); StopAllCores();
return; return false;
} }
Tasking::TCB *tcb = data->CurrentThread; Tasking::TCB *tcb = data->CurrentThread;
Tasking::Task *ctx = tcb->GetContext();
tcb->State = Tasking::Terminated;
tcb->ExitCode = Tasking::KILL_CRASH;
CPU::Interrupts(CPU::Enable); CPU::Interrupts(CPU::Enable);
while (true) while (true)
{ {
ctx->Yield(); tcb->GetContext()->Yield();
CPU::Halt(TaskManager->IsPanic()); CPU::Halt(TaskManager->IsPanic());
} }
} }
#endif #endif
return false;
} }
SafeFunction inline void Print_x86_64(CHArchTrapFrame *Frame) SafeFunction inline void Print_x86_64(CHArchTrapFrame *Frame)
@ -1155,12 +1178,17 @@ namespace CrashHandler
CHArchTrapFrame *Frame = (CHArchTrapFrame *)Data; CHArchTrapFrame *Frame = (CHArchTrapFrame *)Data;
SBIdx = 255; SBIdx = 255;
debug("-----------------------------------------------------------------------------------"); 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); error("Exception: %#x", Frame->InterruptNumber);
#if defined(a64) #if defined(a64)
Handle_x86_64(Frame); if (Handle_x86_64(Frame))
#elif defined(a32) #elif defined(a32)
Handle_x86_32(Frame); if (Handle_x86_32(Frame))
#endif #endif
return;
if (ExceptionOccurred) if (ExceptionOccurred)
{ {
@ -1180,8 +1208,8 @@ namespace CrashHandler
ExceptionOccurred = true; ExceptionOccurred = true;
if (ModuleManager) if (DriverManager)
ModuleManager->Panic(); DriverManager->Panic();
debug("Reading control registers..."); debug("Reading control registers...");
crashdata.Frame = Frame; crashdata.Frame = Frame;
@ -1397,6 +1425,7 @@ namespace CrashHandler
DisplayTopOverlay(); DisplayTopOverlay();
DisplayMainScreen(crashdata); DisplayMainScreen(crashdata);
Display->SetBuffer(255); Display->SetBuffer(255);
Interrupts::RemoveAll();
kbd = new CrashKeyboardDriver; kbd = new CrashKeyboardDriver;
DisplayBottomOverlay(); DisplayBottomOverlay();
Display->SetBuffer(255); Display->SetBuffer(255);

View File

@ -120,125 +120,109 @@ namespace CrashHandler
#define WaitWrite PS2Wait(false) #define WaitWrite PS2Wait(false)
CPU::Interrupts(CPU::Disable); CPU::Interrupts(CPU::Disable);
#if defined(a86) #if defined(a86)
// Disable devices
/* Disable Port 1 */
WaitWrite; WaitWrite;
outb(0x64, 0xAD); outb(0x64, 0xAD);
/* Disable Port 2 */
WaitWrite; WaitWrite;
outb(0x64, 0xA7); outb(0x64, 0xA7);
// Flush buffer /* Flush */
WaitRead; WaitRead;
inb(0x60); inb(0x60);
// outb(0x64, 0xAE); /* Test PS/2 controller */
// 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);
WaitWrite; WaitWrite;
outb(0x64, 0xAA); outb(0x64, 0xAA);
WaitRead; WaitRead;
uint8_t test = inb(0x60); uint8_t test = inb(0x60);
if (test != 0x55) if (test != 0x55)
{ {
error("PS/2 controller self test failed! (%#x)", test); if (test == 0xFA)
printf("PS/2 controller self test failed! (%#x)\n", test); warn("PS/2 controller acknowledged? (expected TEST_PASSED = 0x55)");
CPU::Stop(); 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; WaitWrite;
outb(0x64, 0x60); outb(0x64, 0x60);
WaitWrite; WaitWrite;
outb(0x60, cfg); outb(0x60, cfg);
bool DCExists = false; /* Enable Port 1 */
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); outb(0x64, 0xAE);
if (DCExists) /* Set scan code set 1 */
{
WaitWrite; WaitWrite;
outb(0x64, 0xA8); outb(0x60, 0xF0);
} WaitWrite;
outb(0x60, 0x02);
/* Check if we have scan code set 1 */
WaitWrite; WaitWrite;
outb(0x60, 0xFF); outb(0x60, 0xF0);
WaitWrite;
outb(0x60, 0x00);
/* Read scan code set */
WaitRead; WaitRead;
test = inb(0x60); uint8_t scs = inb(0x60);
if (test == 0xFC) if (scs != 0x41)
{ {
error("PS/2 keyboard reset failed! (%#x)", test); warn("PS/2 keyboard scan code set 1 not supported (%#x)", scs);
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();
}
// outb(0x60, 0xF4);
// outb(0x21, 0xFD);
// outb(0xA1, 0xFF);
#endif // defined(a86) #endif // defined(a86)
CPU::Interrupts(CPU::Enable); CPU::Interrupts(CPU::Enable);
@ -246,19 +230,13 @@ namespace CrashHandler
CrashKeyboardDriver::~CrashKeyboardDriver() CrashKeyboardDriver::~CrashKeyboardDriver()
{ {
error("CrashKeyboardDriver::~CrashKeyboardDriver() called!"); error("CrashKeyboardDriver::~CrashKeyboardDriver() called");
} }
int BackSpaceLimit = 0; int BackSpaceLimit = 0;
static char UserInputBuffer[1024]; static char UserInputBuffer[1024];
#if defined(a64) SafeFunction void CrashKeyboardDriver::OnInterruptReceived(CPU::TrapFrame *Frame)
SafeFunction void CrashKeyboardDriver::OnInterruptReceived(CPU::x64::TrapFrame *Frame)
#elif defined(a32)
SafeFunction void CrashKeyboardDriver::OnInterruptReceived(CPU::x32::TrapFrame *Frame)
#elif defined(aa64)
SafeFunction void CrashKeyboardDriver::OnInterruptReceived(CPU::aarch64::TrapFrame *Frame)
#endif
{ {
#if defined(a86) #if defined(a86)
UNUSED(Frame); UNUSED(Frame);

View File

@ -42,11 +42,12 @@ namespace CrashHandler
if (data.Process) if (data.Process)
{ {
EHPrint("\n\eFAFAFATracing 10 process frames..."); EHPrint("\n\eFAFAFATracing 10 process frames...");
SymbolResolver::Symbols *sh = data.Process->ELFSymbolTable; SymbolResolver::Symbols *pSt = data.Process->ELFSymbolTable;
if (!sh) debug("pSt = %#lx", pSt);
if (!pSt || !pSt->SymTableExists)
EHPrint("\n\eFF0000< No symbol table available. >\n"); EHPrint("\n\eFF0000< No symbol table available. >\n");
else else
TraceFrames(data, 10, sh, false); TraceFrames(data, 10, pSt, false);
} }
EHPrint("\n\eFAFAFATracing interrupt frames..."); EHPrint("\n\eFAFAFATracing interrupt frames...");
for (short i = 0; i < 8; i++) for (short i = 0; i < 8; i++)
@ -58,42 +59,20 @@ namespace CrashHandler
EHPrint("\n\e2565CC%p", EHIntFrames[i]); EHPrint("\n\e2565CC%p", EHIntFrames[i]);
EHPrint("\e7925CC-"); EHPrint("\e7925CC-");
#if defined(a64) #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) #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) #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 #endif
EHPrint("\e25CCC9%s", KernelSymbolTable->GetSymbolFromAddress((uintptr_t)EHIntFrames[i])); EHPrint("\e25CCC9%s",
KernelSymbolTable->GetSymbol((uintptr_t)EHIntFrames[i]));
else else
EHPrint("\eFF4CA9Outside Kernel"); 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");
}
} }
} }

View File

@ -36,7 +36,7 @@ namespace CrashHandler
{ {
SafeFunction void DisplayTasksScreen(CRData data) SafeFunction void DisplayTasksScreen(CRData data)
{ {
const char *StatusColor[9] = { const char *StatusColor[] = {
"FF0000", // Unknown "FF0000", // Unknown
"AAFF00", // Ready "AAFF00", // Ready
"00AA00", // Running "00AA00", // Running
@ -45,11 +45,12 @@ namespace CrashHandler
"FFAA00", // Stopped "FFAA00", // Stopped
"FFAA00", // Waiting "FFAA00", // Waiting
"FF00FF", // Core dump
"FF0088", // Zombie "FF0088", // Zombie
"FF0000", // Terminated "FF0000", // Terminated
}; };
const char *StatusString[9] = { const char *StatusString[] = {
"Unknown", // Unknown "Unknown", // Unknown
"Ready", // Ready "Ready", // Ready
"Running", // Running "Running", // Running
@ -58,13 +59,14 @@ namespace CrashHandler
"Stopped", // Stopped "Stopped", // Stopped
"Waiting", // Waiting "Waiting", // Waiting
"CoreDump", // Core dump
"Zombie", // Zombie "Zombie", // Zombie
"Terminated", // Terminated "Terminated", // Terminated
}; };
if (TaskManager) if (TaskManager)
{ {
std::vector<Tasking::PCB *> Plist = TaskManager->GetProcessList(); std::list<Tasking::PCB *> Plist = TaskManager->GetProcessList();
if (data.Thread) if (data.Thread)
#if defined(a64) #if defined(a64)

View File

@ -32,6 +32,8 @@
#include "../../kernel.h" #include "../../kernel.h"
#define AddrToStr(addr) SymHandle->GetSymbol(addr)
namespace CrashHandler namespace CrashHandler
{ {
struct StackFrame struct StackFrame
@ -40,15 +42,19 @@ namespace CrashHandler
uintptr_t rip; uintptr_t rip;
}; };
SafeFunction void TraceFrames(CRData data, int Count, SymbolResolver::Symbols *SymHandle, bool Kernel) SafeFunction void TraceFrames(CRData data, int Count,
SymbolResolver::Symbols *SymHandle,
bool Kernel)
{ {
if (!Memory::Virtual().Check(data.Frame)) Memory::Virtual vmm;
if (!vmm.Check(data.Frame))
{ {
EHPrint("Invalid frame pointer: %p\n", data.Frame); EHPrint("Invalid frame pointer: %p\n", data.Frame);
return; return;
} }
if (!Memory::Virtual().Check(SymHandle)) if (!vmm.Check(SymHandle))
{ {
EHPrint("Invalid symbol handle: %p\n", SymHandle); EHPrint("Invalid symbol handle: %p\n", SymHandle);
return; return;
@ -65,11 +71,14 @@ namespace CrashHandler
frames = (struct StackFrame *)data.Frame->ebp; frames = (struct StackFrame *)data.Frame->ebp;
#elif defined(aa64) #elif defined(aa64)
#endif #endif
if (!Memory::Virtual().Check((void *)frames)) if (!vmm.Check((void *)frames))
{ {
if (TriedRetryBP == false) if (TriedRetryBP == false)
{ {
frames = (struct StackFrame *)Memory::Virtual(data.Process->PageTable).GetPhysical((void *)frames); 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; TriedRetryBP = true;
goto RetryBP; goto RetryBP;
} }
@ -82,7 +91,8 @@ namespace CrashHandler
return; return;
} }
debug("\nStack tracing... %p %d %p %d", data.Frame, Count, frames, Kernel); debug("Stack tracing... %p %d %p %d",
data.Frame, Count, frames, Kernel);
EHPrint("\e7981FC\nStack Trace:\n"); EHPrint("\e7981FC\nStack Trace:\n");
if (!frames || !frames->rip || !frames->rbp) if (!frames || !frames->rip || !frames->rbp)
{ {
@ -94,9 +104,9 @@ namespace CrashHandler
#endif #endif
EHPrint("\e7925CC-"); EHPrint("\e7925CC-");
#if defined(a64) #if defined(a64)
EHPrint("\eAA25CC%s", SymHandle->GetSymbolFromAddress(data.Frame->rip)); EHPrint("\eAA25CC%s", AddrToStr(data.Frame->rip));
#elif defined(a32) #elif defined(a32)
EHPrint("\eAA25CC%s", SymHandle->GetSymbolFromAddress(data.Frame->eip)); EHPrint("\eAA25CC%s", AddrToStr(data.Frame->eip));
#elif defined(aa64) #elif defined(aa64)
#endif #endif
EHPrint("\e7981FC <- Exception"); EHPrint("\e7981FC <- Exception");
@ -105,17 +115,28 @@ namespace CrashHandler
else else
{ {
#if defined(a64) #if defined(a64)
debug("Exception in function %s(%p)",
AddrToStr(data.Frame->rip),
data.Frame->rip);
EHPrint("\e2565CC%p", (void *)data.Frame->rip); EHPrint("\e2565CC%p", (void *)data.Frame->rip);
EHPrint("\e7925CC-"); EHPrint("\e7925CC-");
if ((data.Frame->rip >= 0xFFFFFFFF80000000 && data.Frame->rip <= (uintptr_t)&_kernel_end) || !Kernel) if ((data.Frame->rip >= 0xFFFFFFFF80000000 &&
EHPrint("\eAA25CC%s", SymHandle->GetSymbolFromAddress(data.Frame->rip)); data.Frame->rip <= (uintptr_t)&_kernel_end) ||
Kernel == false)
{
EHPrint("\eAA25CC%s", AddrToStr(data.Frame->rip));
}
else else
EHPrint("Outside Kernel"); EHPrint("Outside Kernel");
#elif defined(a32) #elif defined(a32)
EHPrint("\e2565CC%p", (void *)data.Frame->eip); EHPrint("\e2565CC%p", (void *)data.Frame->eip);
EHPrint("\e7925CC-"); EHPrint("\e7925CC-");
if ((data.Frame->eip >= 0xC0000000 && data.Frame->eip <= (uintptr_t)&_kernel_end) || !Kernel) if ((data.Frame->eip >= 0xC0000000 &&
EHPrint("\eAA25CC%s", SymHandle->GetSymbolFromAddress(data.Frame->eip)); data.Frame->eip <= (uintptr_t)&_kernel_end) ||
Kernel == false)
{
EHPrint("\eAA25CC%s", AddrToStr(data.Frame->eip));
}
else else
EHPrint("Outside Kernel"); EHPrint("Outside Kernel");
#elif defined(aa64) #elif defined(aa64)
@ -128,17 +149,23 @@ namespace CrashHandler
EHPrint("\n\e2565CC%p", (void *)frames->rip); EHPrint("\n\e2565CC%p", (void *)frames->rip);
EHPrint("\e7925CC-"); EHPrint("\e7925CC-");
#if defined(a64) #if defined(a64)
if ((frames->rip >= 0xFFFFFFFF80000000 && frames->rip <= (uintptr_t)&_kernel_end) || !Kernel) if ((frames->rip >= 0xFFFFFFFF80000000 &&
frames->rip <= (uintptr_t)&_kernel_end) ||
Kernel == false)
#elif defined(a32) #elif defined(a32)
if ((frames->rip >= 0xC0000000 && frames->rip <= (uintptr_t)&_kernel_end) || !Kernel) if ((frames->rip >= 0xC0000000 &&
frames->rip <= (uintptr_t)&_kernel_end) ||
Kernel == false)
#elif defined(aa64) #elif defined(aa64)
if ((frames->rip >= 0xFFFFFFFF80000000 && frames->rip <= (uintptr_t)&_kernel_end) || !Kernel) if ((frames->rip >= 0xFFFFFFFF80000000 &&
frames->rip <= (uintptr_t)&_kernel_end) ||
Kernel == false)
#endif #endif
EHPrint("\e25CCC9%s", SymHandle->GetSymbolFromAddress(frames->rip)); EHPrint("\e25CCC9%s", AddrToStr(frames->rip));
else else
EHPrint("\eFF4CA9Outside Kernel"); EHPrint("\eFF4CA9Outside Kernel");
if (!Memory::Virtual().Check(frames->rbp)) if (!vmm.Check(frames->rbp))
return; return;
frames = frames->rbp; frames = frames->rbp;
} }

View File

@ -34,8 +34,12 @@
SafeFunction bool UserModeExceptionHandler(CHArchTrapFrame *Frame) SafeFunction bool UserModeExceptionHandler(CHArchTrapFrame *Frame)
{ {
thisThread->State = Tasking::TaskState::Waiting;
CPUData *CurCPU = GetCurrentCPU(); 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 #ifdef DEBUG
{ {
@ -153,37 +157,59 @@ SafeFunction bool UserModeExceptionHandler(CHArchTrapFrame *Frame)
{ {
bool Handled = false; bool Handled = false;
Handled = CurCPU->CurrentProcess->vma->HandleCoW(CrashHandler::PageFaultAddress); Handled = CurProc->vma->HandleCoW(CrashHandler::PageFaultAddress);
if (!Handled) if (!Handled)
Handled = CurCPU->CurrentThread->Stack->Expand(CrashHandler::PageFaultAddress); Handled = CurThread->Stack->Expand(CrashHandler::PageFaultAddress);
if (Handled) if (Handled)
{ {
debug("Page fault handled"); debug("Page fault handled");
thisThread->State = Tasking::TaskState::Ready; CurThread->SetState(Tasking::Ready);
return true; 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; break;
} }
case CPU::x86::DivideByZero: case CPU::x86::DivideByZero:
case CPU::x86::Debug:
case CPU::x86::NonMaskableInterrupt:
case CPU::x86::Breakpoint:
case CPU::x86::Overflow: case CPU::x86::Overflow:
case CPU::x86::BoundRange: 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::InvalidOpcode:
case CPU::x86::GeneralProtectionFault:
{
CurProc->Signals->SendSignal(SIGILL,
{Tasking::KILL_CRASH});
break;
}
case CPU::x86::DeviceNotAvailable: case CPU::x86::DeviceNotAvailable:
{
CurProc->Signals->SendSignal(SIGBUS,
{Tasking::KILL_CRASH});
break;
}
case CPU::x86::NonMaskableInterrupt:
case CPU::x86::DoubleFault: case CPU::x86::DoubleFault:
case CPU::x86::CoprocessorSegmentOverrun: case CPU::x86::CoprocessorSegmentOverrun:
case CPU::x86::InvalidTSS: case CPU::x86::InvalidTSS:
case CPU::x86::SegmentNotPresent: case CPU::x86::SegmentNotPresent:
case CPU::x86::StackSegmentFault: case CPU::x86::StackSegmentFault:
case CPU::x86::GeneralProtectionFault:
case CPU::x86::x87FloatingPoint:
case CPU::x86::AlignmentCheck: case CPU::x86::AlignmentCheck:
case CPU::x86::MachineCheck: case CPU::x86::MachineCheck:
case CPU::x86::SIMDFloatingPoint:
case CPU::x86::Virtualization: case CPU::x86::Virtualization:
case CPU::x86::Security: case CPU::x86::Security:
default: default:

View File

@ -21,11 +21,13 @@
#include <lock.hpp> #include <lock.hpp>
#include <io.h> #include <io.h>
#include "../kernel.h"
NewLock(DebuggerLock); NewLock(DebuggerLock);
extern bool serialports[8]; 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; static int once = 0;
if (unlikely(!once++)) if (unlikely(!once++))

View File

@ -21,18 +21,17 @@
#include <printf.h> #include <printf.h>
#include "../kernel.h" #include "../kernel.h"
#include "../mapi.hpp"
#include "../Fex.hpp"
namespace Disk namespace Disk
{ {
void Manager::FetchDisks(unsigned long modUniqueID) void Manager::FetchDisks(unsigned long modUniqueID)
{ {
KernelCallback callback{}; /* KernelCallback */
callback.Reason = QueryReason; // KernelCallback callback{};
ModuleManager->IOCB(modUniqueID, &callback); // callback.Reason = QueryReason;
this->AvailablePorts = callback.DiskCallback.Fetch.Ports; // DriverManager->IOCB(modUniqueID, &callback);
this->BytesPerSector = callback.DiskCallback.Fetch.BytesPerSector; // this->AvailablePorts = callback.DiskCallback.Fetch.Ports;
// this->BytesPerSector = callback.DiskCallback.Fetch.BytesPerSector;
debug("AvailablePorts:%ld BytesPerSector:%ld", this->AvailablePorts, this->BytesPerSector); debug("AvailablePorts:%ld BytesPerSector:%ld", this->AvailablePorts, this->BytesPerSector);
if (this->AvailablePorts <= 0) if (this->AvailablePorts <= 0)
@ -49,15 +48,16 @@ namespace Disk
drive->MechanicalDisk = true; drive->MechanicalDisk = true;
memset(RWBuffer, 0, this->BytesPerSector); memset(RWBuffer, 0, this->BytesPerSector);
callback.Reason = ReceiveReason; /* KernelCallback */
callback.DiskCallback.RW = { // callback.Reason = ReceiveReason;
.Sector = 0, // callback.DiskCallback.RW = {
.SectorCount = 2, // .Sector = 0,
.Port = ItrPort, // .SectorCount = 2,
.Buffer = RWBuffer, // .Port = ItrPort,
.Write = false, // .Buffer = RWBuffer,
}; // .Write = false,
ModuleManager->IOCB(modUniqueID, &callback); // };
// DriverManager->IOCB(modUniqueID, &callback);
memcpy(&drive->Table, RWBuffer, sizeof(PartitionTable)); memcpy(&drive->Table, RWBuffer, sizeof(PartitionTable));
/* /*
@ -72,15 +72,16 @@ namespace Disk
for (uint32_t Block = 0; Block < Sectors; Block++) for (uint32_t Block = 0; Block < Sectors; Block++)
{ {
memset(RWBuffer, 0, this->BytesPerSector); memset(RWBuffer, 0, this->BytesPerSector);
callback.Reason = ReceiveReason; /* KernelCallback */
callback.DiskCallback.RW = { // callback.Reason = ReceiveReason;
.Sector = 2 + Block, // callback.DiskCallback.RW = {
.SectorCount = 1, // .Sector = 2 + Block,
.Port = ItrPort, // .SectorCount = 1,
.Buffer = RWBuffer, // .Port = ItrPort,
.Write = false, // .Buffer = RWBuffer,
}; // .Write = false,
ModuleManager->IOCB(modUniqueID, &callback); // };
// DriverManager->IOCB(modUniqueID, &callback);
for (uint32_t e = 0; e < Entries; e++) for (uint32_t e = 0; e < Entries; e++)
{ {

939
core/driver/api.cpp Normal file
View File

@ -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 <https://www.gnu.org/licenses/>.
*/
#include <driver.hpp>
#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<dev_t, DriverObject> &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<dev_t, DriverObject> &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<dev_t, DriverObject> &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<uint8_t, void *>(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<dev_t, DriverObject> &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<dev_t, DriverObject> &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<dev_t, DriverObject> &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<dev_t, DriverObject> &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<dev_t, DriverObject> &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<dev_t, DriverObject> &Drivers =
DriverManager->GetDrivers();
auto itr = Drivers.find(MajorID);
if (itr == Drivers.end())
return nullptr;
std::list<uint16_t> VendorIDs;
for (int i = 0; _Vendors[i] != 0x0; i++)
VendorIDs.push_back(_Vendors[i]);
std::list<uint16_t> DeviceIDs;
for (int i = 0; _Devices[i] != 0x0; i++)
DeviceIDs.push_back(_Devices[i]);
std::list<PCI::PCIDevice> 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;
}
}

View File

@ -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 <https://www.gnu.org/licenses/>.
*/
#include <driver.hpp>
#include <memory.hpp>
#include <ints.hpp>
#include <task.hpp>
#include <printf.h>
#include <exec.hpp>
#include <cwalk.h>
#include <md5.h>
#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<min_t, SlaveDeviceFile *> *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<min_t, SlaveDeviceFile *>();
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<min_t, SlaveDeviceFile *> *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();
}
}

View File

@ -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 <https://www.gnu.org/licenses/>.
*/
#include <driver.hpp>
#include <memory.hpp>
#include <ints.hpp>
#include <task.hpp>
#include <printf.h>
#include <exec.hpp>
#include <cwalk.h>
#include <md5.h>
#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()
{
}
}

582
core/driver/driver.cpp Normal file
View File

@ -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 <https://www.gnu.org/licenses/>.
*/
#include <driver.hpp>
#include <memory.hpp>
#include <ints.hpp>
#include <task.hpp>
#include <printf.h>
#include <exec.hpp>
#include <cwalk.h>
#include <md5.h>
#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<Elf64_Dyn> SymTab = Execute::ELFGetDynamicTag_x86_64(fd, DT_SYMTAB);
std::vector<Elf64_Dyn> 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<Elf64_Dyn> SymTab = Execute::ELFGetDynamicTag_x86_64(fd, DT_SYMTAB);
std::vector<Elf64_Dyn> 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<uint8_t, void *>};
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;
}
}

369
core/driver/scancode.cpp Normal file
View File

@ -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 <https://www.gnu.org/licenses/>.
*/
#include <driver.hpp>
#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;
}
}

View File

@ -54,11 +54,7 @@ namespace ACPI
#define ACPI_GAS_IO 1 #define ACPI_GAS_IO 1
#define ACPI_GAS_PCI 2 #define ACPI_GAS_PCI 2
#if defined(a64) void DSDT::OnInterruptReceived(CPU::TrapFrame *)
void DSDT::OnInterruptReceived(CPU::x64::TrapFrame *)
#elif defined(a32)
void DSDT::OnInterruptReceived(CPU::x32::TrapFrame *)
#endif
{ {
debug("SCI Handle Triggered"); debug("SCI Handle Triggered");
uint16_t Event = 0; uint16_t Event = 0;
@ -77,7 +73,27 @@ namespace ACPI
Event = a | b; 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) if (Event & ACPI_BUSMASTER)
{ {
fixme("ACPI Busmaster"); fixme("ACPI Busmaster");
@ -88,12 +104,13 @@ namespace ACPI
} }
else if (Event & ACPI_POWER_BUTTON) else if (Event & ACPI_POWER_BUTTON)
{ {
if (TaskManager && !TaskManager->IsPanic()) Tasking::PCB *pcb = thisProcess;
if (pcb && !pcb->GetContext()->IsPanic())
{ {
TaskManager->CreateThread(TaskManager->CreateProcess(nullptr, Tasking::Task *ctx = pcb->GetContext();
"Shutdown", ctx->CreateThread(ctx->GetKernelProcess(),
Tasking::TaskExecutionMode::Kernel), Tasking::IP(KST_Shutdown))
Tasking::IP(KST_Shutdown)); ->Rename("Shutdown");
} }
else else
KernelShutdownThread(false); KernelShutdownThread(false);
@ -120,36 +137,57 @@ namespace ACPI
} }
else else
{ {
error("ACPI unknown event %#lx on CPU %d", Event, GetCurrentCPU()->ID); error("ACPI unknown event %#lx on CPU %d",
CPU::Stop(); Event, GetCurrentCPU()->ID);
KPrint("ACPI unknown event %#lx on CPU %d",
Event, GetCurrentCPU()->ID);
} }
} }
void DSDT::Shutdown() void DSDT::Shutdown()
{ {
trace("Shutting down..."); trace("Shutting down...");
if (SCI_EN == 1) if (SCI_EN != 1)
{ {
outw(s_cst(uint16_t, acpi->FADT->PM1aControlBlock), error("ACPI Shutdown not supported");
s_cst(uint16_t, return;
(inw(s_cst(uint16_t, }
acpi->FADT->PM1aControlBlock)) &
0xE3FF) |
((SLP_TYPa << 10) | ACPI_SLEEP)));
if (acpi->FADT->PM1bControlBlock) if (inw(s_cst(uint16_t, PM1a_CNT) & SCI_EN) == 0)
outw(s_cst(uint16_t, acpi->FADT->PM1bControlBlock), {
s_cst(uint16_t, KPrint("ACPI was disabled, enabling...");
(inw( if (SMI_CMD == 0 || ACPI_ENABLE == 0)
s_cst(uint16_t, acpi->FADT->PM1bControlBlock)) & {
0xE3FF) | error("ACPI Shutdown not supported");
((SLP_TYPb << 10) | ACPI_SLEEP))); 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); outw(s_cst(uint16_t, PM1a_CNT), SLP_TYPa | SLP_EN);
if (PM1b_CNT) if (PM1b_CNT)
outw(s_cst(uint16_t, PM1b_CNT), SLP_TYPb | SLP_EN); outw(s_cst(uint16_t, PM1b_CNT), SLP_TYPb | SLP_EN);
} }
}
void DSDT::Reboot() 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; this->acpi = acpi;
uint64_t Address = ((IsCanonical(acpi->FADT->X_Dsdt) && acpi->XSDTSupported) ? acpi->FADT->X_Dsdt : acpi->FADT->Dsdt); uint64_t Address = ((IsCanonical(acpi->FADT->X_Dsdt) && acpi->XSDTSupported) ? acpi->FADT->X_Dsdt : acpi->FADT->Dsdt);
uint8_t *S5Address = (uint8_t *)(Address) + 36; uint8_t *S5Address = (uint8_t *)(Address) + 36;
ACPI::ACPI::ACPIHeader *Header = (ACPI::ACPI::ACPIHeader *)Address; 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"); warn("DSDT is not mapped");
debug("DSDT: %#lx", Address); debug("DSDT: %#lx", Address);
Memory::Virtual().Map(Header, Header, Memory::RW); vmm.Map(Header, Header, Memory::RW);
} }
size_t Length = Header->Length; size_t Length = Header->Length;
Memory::Virtual().Map(Header, Header, Length, Memory::RW); vmm.Map(Header, Header, Length, Memory::RW);
while (Length-- > 0) while (Length-- > 0)
{ {
@ -212,20 +253,27 @@ namespace ACPI
if (Length <= 0) if (Length <= 0)
{ {
warn("_S5 not present in ACPI"); warn("_S5_ not present in ACPI");
return; 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 += 5;
S5Address += ((*S5Address & 0xC0) >> 6) + 2; S5Address += ((*S5Address & 0xC0) >> 6) + 2;
if (*S5Address == 0x0A) if (*S5Address == 0x0A)
S5Address++; S5Address++;
SLP_TYPa = s_cst(uint16_t, *(S5Address) << 10); SLP_TYPa = s_cst(uint16_t, *(S5Address) << 10);
S5Address++; S5Address++;
if (*S5Address == 0x0A) if (*S5Address == 0x0A)
S5Address++; S5Address++;
SLP_TYPb = s_cst(uint16_t, *(S5Address) << 10); SLP_TYPb = s_cst(uint16_t, *(S5Address) << 10);
SMI_CMD = acpi->FADT->SMI_CommandPort; SMI_CMD = acpi->FADT->SMI_CommandPort;
ACPI_ENABLE = acpi->FADT->AcpiEnable; ACPI_ENABLE = acpi->FADT->AcpiEnable;
@ -235,11 +283,13 @@ namespace ACPI
PM1_CNT_LEN = acpi->FADT->PM1ControlLength; PM1_CNT_LEN = acpi->FADT->PM1ControlLength;
SLP_EN = 1 << 13; SLP_EN = 1 << 13;
SCI_EN = 1; SCI_EN = 1;
trace("ACPI Shutdown is supported"); KPrint("ACPI Shutdown is supported");
ACPIShutdownSupported = true; 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 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)); 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); 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); ((APIC::APIC *)Interrupts::apic[0])->RedirectIRQ(0, uint8_t(acpi->FADT->SCI_Interrupt), 1);
return; return;
} }
warn("Failed to parse _S5 in ACPI"); warn("Failed to parse _S5_ in ACPI");
SCI_EN = 0; SCI_EN = 0;
} }

View File

@ -46,10 +46,64 @@ namespace Interrupts
{ {
struct Event struct Event
{ {
int ID; /** Interrupt number */
int IRQ;
/** Raw pointer to the Handler */
void *Data; 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<Event> RegisteredEvents; std::list<Event> 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) #if defined(a86)
/* APIC::APIC */ void *apic[MAX_CPU]; /* APIC::APIC */ void *apic[MAX_CPU];
@ -120,6 +174,7 @@ namespace Interrupts
#elif defined(aa64) #elif defined(aa64)
warn("aarch64 is not supported yet"); warn("aarch64 is not supported yet");
#endif #endif
CPU::Interrupts(CPU::Enable);
} }
void InitializeTimer(int Core) void InitializeTimer(int Core)
@ -139,7 +194,90 @@ namespace Interrupts
SafeFunction void RemoveAll() 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) extern "C" SafeFunction void MainInterruptHandler(void *Data)
@ -170,37 +308,73 @@ namespace Interrupts
Core = CoreData->ID; Core = CoreData->ID;
/* If this is false, we have a big problem. */ /* If this is false, we have a big problem. */
if (likely(Frame->InterruptNumber < CPU::x86::IRQ223 && if (unlikely(Frame->InterruptNumber >= CPU::x86::IRQ223 ||
Frame->InterruptNumber > CPU::x86::ISR0)) Frame->InterruptNumber <= CPU::x86::ISR0))
{ {
error("Interrupt number %d is out of range.",
Frame->InterruptNumber);
assert(!"Interrupt number is out of range.");
}
/* Halt core interrupt */ /* Halt core interrupt */
if (unlikely(Frame->InterruptNumber == CPU::x86::IRQ29)) if (unlikely(Frame->InterruptNumber == CPU::x86::IRQ31))
CPU::Stop(); CPU::Stop();
bool InterruptHandled = false; bool InterruptHandled = false;
foreach (auto ev in RegisteredEvents) foreach (auto &ev in RegisteredEvents)
{ {
#if defined(a86) #if defined(a86)
if ((ev.ID + CPU::x86::IRQ0) == s_cst(int, Frame->InterruptNumber)) int iEvNum = ev.IRQ + CPU::x86::IRQ0;
#elif defined(aa64) #elif defined(aa64)
if (ev.ID == s_cst(int, Frame->InterruptNumber)) int iEvNum = ev.IRQ;
#endif #endif
if (iEvNum == s_cst(int, Frame->InterruptNumber))
{
if (ev.IsHandler)
{ {
Handler *hnd = (Handler *)ev.Data; Handler *hnd = (Handler *)ev.Data;
hnd->OnInterruptReceived(Frame); hnd->OnInterruptReceived(Frame);
}
else
{
if (ev.Context != nullptr)
ev.Callback((CPU::TrapFrame *)ev.Context);
else
ev.Callback(Frame);
}
ev.Priority++;
InterruptHandled = true; InterruptHandled = true;
} }
} }
if (!InterruptHandled) if (unlikely(!InterruptHandled))
{ {
error("IRQ%d is unhandled on CPU %d.", error("IRQ%d is unhandled on CPU %d.",
Frame->InterruptNumber - 32, Core); Frame->InterruptNumber - 32, Core);
if (Frame->InterruptNumber == CPU::x86::IRQ1)
{
uint8_t scancode = inb(0x60);
warn("IRQ1 is the keyboard interrupt. Scancode: %#x", scancode);
} }
/* 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])) if (likely(apic[Core]))
@ -213,34 +387,47 @@ namespace Interrupts
else else
fixme("APIC not found for core %d", Core); fixme("APIC not found for core %d", Core);
// TODO: PIC // TODO: PIC
}
else
{
error("Interrupt number %d is out of range.",
Frame->InterruptNumber);
}
error("HALT HALT HALT HALT HALT HALT HALT HALT HALT [IRQ%d]", assert(!"Interrupt EOI not handled.");
Frame->InterruptNumber - 32);
CPU::Stop(); CPU::Stop();
} }
Handler::Handler(int InterruptNumber) Handler::Handler(int InterruptNumber, bool Critical)
{ {
foreach (auto ev in RegisteredEvents) foreach (auto ev in RegisteredEvents)
{ {
if (ev.ID == InterruptNumber) if (ev.IRQ == InterruptNumber)
{ {
warn("IRQ%d is already registered.", warn("IRQ%d is already registered.",
InterruptNumber); InterruptNumber);
} }
} }
debug("Registering interrupt handler for IRQ%d.",
InterruptNumber);
this->InterruptNumber = 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() Handler::~Handler()
@ -250,7 +437,7 @@ namespace Interrupts
forItr(itr, RegisteredEvents) forItr(itr, RegisteredEvents)
{ {
if (itr->ID == this->InterruptNumber) if (itr->IRQ == this->InterruptNumber)
{ {
RegisteredEvents.erase(itr); RegisteredEvents.erase(itr);
return; return;
@ -259,21 +446,9 @@ namespace Interrupts
warn("Event %d not found.", this->InterruptNumber); warn("Event %d not found.", this->InterruptNumber);
} }
#if defined(a64) void Handler::OnInterruptReceived(CPU::TrapFrame *Frame)
void Handler::OnInterruptReceived(CPU::x64::TrapFrame *Frame)
{ {
trace("Unhandled interrupt IRQ%d", trace("Unhandled interrupt %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",
Frame->InterruptNumber); Frame->InterruptNumber);
#endif
} }
} }

View File

@ -22,22 +22,22 @@
#include "../kernel.h" #include "../kernel.h"
#ifdef DEBUG
/* This might end up in a deadlock in the deadlock handler. /* This might end up in a deadlock in the deadlock handler.
Nobody can escape the deadlock, not even the Nobody can escape the deadlock, not even the
deadlock handler itself. */ deadlock handler itself. */
// #define PRINT_BACKTRACE 1
// #define PRINT_BACKTRACE
#endif
#ifdef PRINT_BACKTRACE #ifdef PRINT_BACKTRACE
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wframe-address" #pragma GCC diagnostic ignored "-Wframe-address"
void PrintStacktrace(LockClass::SpinLockData *Lock) void PrintStacktrace(LockClass::SpinLockData *Lock)
{ {
if (KernelSymbolTable) if (!KernelSymbolTable)
{ {
warn("Symbol table not available.");
return;
}
struct StackFrame struct StackFrame
{ {
uintptr_t BasePointer; uintptr_t BasePointer;
@ -46,7 +46,6 @@ void PrintStacktrace(LockClass::SpinLockData *Lock)
// char DbgAttempt[1024] = "\0"; // char DbgAttempt[1024] = "\0";
// char DbgHolder[1024] = "\0"; // char DbgHolder[1024] = "\0";
std::string DbgAttempt = "\0"; std::string DbgAttempt = "\0";
std::string DbgHolder = "\0"; std::string DbgHolder = "\0";
@ -55,43 +54,39 @@ void PrintStacktrace(LockClass::SpinLockData *Lock)
while (Memory::Virtual().Check(FrameAttempt)) while (Memory::Virtual().Check(FrameAttempt))
{ {
DbgAttempt.concat(KernelSymbolTable->GetSymbolFromAddress(FrameAttempt->ReturnAddress)); DbgAttempt.concat(KernelSymbolTable->GetSymbol(FrameAttempt->ReturnAddress));
DbgAttempt.concat("<-"); DbgAttempt.concat("<-");
FrameAttempt = (StackFrame *)FrameAttempt->BasePointer; FrameAttempt = (StackFrame *)FrameAttempt->BasePointer;
} }
debug("Attempt: %s", DbgAttempt.c_str()); warn("Attempt: %s", DbgAttempt.c_str());
while (Memory::Virtual().Check(FrameHolder)) while (Memory::Virtual().Check(FrameHolder))
{ {
DbgHolder.concat(KernelSymbolTable->GetSymbolFromAddress(FrameHolder->ReturnAddress)); DbgHolder.concat(KernelSymbolTable->GetSymbol(FrameHolder->ReturnAddress));
DbgHolder.concat("<-"); DbgHolder.concat("<-");
FrameHolder = (StackFrame *)FrameHolder->BasePointer; FrameHolder = (StackFrame *)FrameHolder->BasePointer;
} }
debug("Holder: %s", DbgHolder.c_str()); warn("Holder: %s", DbgHolder.c_str());
// debug("\t\t%s<-%s<-%s<-%s<-%s<-%s<-%s<-%s<-%s<-%s", // warn("\t\t%s<-%s<-%s<-%s<-%s<-%s<-%s<-%s<-%s<-%s",
// KernelSymbolTable->GetSymbolFromAddress((uintptr_t)__builtin_return_address(0)), // KernelSymbolTable->GetSymbol((uintptr_t)__builtin_return_address(0)),
// KernelSymbolTable->GetSymbolFromAddress((uintptr_t)__builtin_return_address(1)), // KernelSymbolTable->GetSymbol((uintptr_t)__builtin_return_address(1)),
// KernelSymbolTable->GetSymbolFromAddress((uintptr_t)__builtin_return_address(2)), // KernelSymbolTable->GetSymbol((uintptr_t)__builtin_return_address(2)),
// KernelSymbolTable->GetSymbolFromAddress((uintptr_t)__builtin_return_address(3)), // KernelSymbolTable->GetSymbol((uintptr_t)__builtin_return_address(3)),
// KernelSymbolTable->GetSymbolFromAddress((uintptr_t)__builtin_return_address(4)), // KernelSymbolTable->GetSymbol((uintptr_t)__builtin_return_address(4)),
// KernelSymbolTable->GetSymbolFromAddress((uintptr_t)__builtin_return_address(5)), // KernelSymbolTable->GetSymbol((uintptr_t)__builtin_return_address(5)),
// KernelSymbolTable->GetSymbolFromAddress((uintptr_t)__builtin_return_address(6)), // KernelSymbolTable->GetSymbol((uintptr_t)__builtin_return_address(6)),
// KernelSymbolTable->GetSymbolFromAddress((uintptr_t)__builtin_return_address(7)), // KernelSymbolTable->GetSymbol((uintptr_t)__builtin_return_address(7)),
// KernelSymbolTable->GetSymbolFromAddress((uintptr_t)__builtin_return_address(8)), // KernelSymbolTable->GetSymbol((uintptr_t)__builtin_return_address(8)),
// KernelSymbolTable->GetSymbolFromAddress((uintptr_t)__builtin_return_address(9))); // KernelSymbolTable->GetSymbol((uintptr_t)__builtin_return_address(9)));
} }
}
#pragma GCC diagnostic pop
#endif #endif
#ifdef DEBUG #ifdef DEBUG
#define DEADLOCK_TIMEOUT 0x100000 #define DEADLOCK_TIMEOUT 0x1000
#define DEADLOCK_TIMEOUT_DEBUGGER 0x1000
#else #else
#define DEADLOCK_TIMEOUT 0x10000000 #define DEADLOCK_TIMEOUT 0x10000000
#define DEADLOCK_TIMEOUT_DEBUGGER 0x100000
#endif #endif
bool ForceUnlock = false; bool ForceUnlock = false;
@ -159,26 +154,26 @@ int LockClass::Lock(const char *FunctionName)
Retry: Retry:
int i = 0; int i = 0;
while (IsLocked.exchange(true, std::memory_order_acquire) && while (IsLocked.exchange(true, std::memory_order_acquire) &&
++i < (DebuggerIsAttached ? DEADLOCK_TIMEOUT_DEBUGGER : DEADLOCK_TIMEOUT)) ++i < DEADLOCK_TIMEOUT)
{ {
this->Yield(); this->Yield();
} }
if (i >= (DebuggerIsAttached ? DEADLOCK_TIMEOUT_DEBUGGER : DEADLOCK_TIMEOUT)) if (i >= DEADLOCK_TIMEOUT)
{ {
DeadLock(LockData); DeadLock(LockData);
goto Retry; goto Retry;
} }
LockData.Count++; LockData.Count.fetch_add(1);
LockData.CurrentHolder = FunctionName; LockData.CurrentHolder.store(FunctionName);
LockData.StackPointerHolder = (uintptr_t)__builtin_frame_address(0); LockData.StackPointerHolder.store((uintptr_t)__builtin_frame_address(0));
CPUData *CoreData = GetCurrentCPU(); CPUData *CoreData = GetCurrentCPU();
if (CoreData != nullptr) if (CoreData != nullptr)
LockData.Core = CoreData->ID; LockData.Core.store(CoreData->ID);
LocksCount++; LocksCount.fetch_add(1);
__sync; __sync;
return 0; return 0;
@ -189,8 +184,8 @@ int LockClass::Unlock()
__sync; __sync;
IsLocked.store(false, std::memory_order_release); IsLocked.store(false, std::memory_order_release);
LockData.Count--; LockData.Count.fetch_sub(1);
LocksCount--; LocksCount.fetch_sub(1);
return 0; return 0;
} }
@ -230,19 +225,19 @@ int LockClass::TimeoutLock(const char *FunctionName, uint64_t Timeout)
if (!TimeManager) if (!TimeManager)
return Lock(FunctionName); return Lock(FunctionName);
LockData.AttemptingToGet = FunctionName; LockData.AttemptingToGet.store(FunctionName);
LockData.StackPointerAttempt = (uintptr_t)__builtin_frame_address(0); LockData.StackPointerAttempt.store((uintptr_t)__builtin_frame_address(0));
std::atomic_uint64_t Target = 0; std::atomic_uint64_t Target = 0;
Retry: Retry:
int i = 0; int i = 0;
while (IsLocked.exchange(true, std::memory_order_acquire) && while (IsLocked.exchange(true, std::memory_order_acquire) &&
++i < (DebuggerIsAttached ? DEADLOCK_TIMEOUT_DEBUGGER : DEADLOCK_TIMEOUT)) ++i < DEADLOCK_TIMEOUT)
{ {
this->Yield(); this->Yield();
} }
if (i >= (DebuggerIsAttached ? DEADLOCK_TIMEOUT_DEBUGGER : DEADLOCK_TIMEOUT)) if (i >= DEADLOCK_TIMEOUT)
{ {
if (Target.load() == 0) if (Target.load() == 0)
Target.store(TimeManager->CalculateTarget(Timeout, Target.store(TimeManager->CalculateTarget(Timeout,
@ -251,15 +246,15 @@ Retry:
goto Retry; goto Retry;
} }
LockData.Count++; LockData.Count.fetch_add(1);
LockData.CurrentHolder = FunctionName; LockData.CurrentHolder.store(FunctionName);
LockData.StackPointerHolder = (uintptr_t)__builtin_frame_address(0); LockData.StackPointerHolder.store((uintptr_t)__builtin_frame_address(0));
CPUData *CoreData = GetCurrentCPU(); CPUData *CoreData = GetCurrentCPU();
if (CoreData != nullptr) if (CoreData != nullptr)
LockData.Core = CoreData->ID; LockData.Core.store(CoreData->ID);
LocksCount++; LocksCount.fetch_add(1);
__sync; __sync;
return 0; return 0;

View File

@ -38,39 +38,45 @@ namespace Memory
/* Check if the address is valid. */ /* Check if the address is valid. */
if ((uintptr_t)Address < HeapStart) if ((uintptr_t)Address < HeapStart)
{
debug("Address %#lx is less than HeapStart %#lx", Address, HeapStart);
return (void *)-ENOMEM; return (void *)-ENOMEM;
}
Virtual vmm = Virtual(this->Table); Virtual vmm(this->Table);
if ((uintptr_t)Address > Break) if ((uintptr_t)Address > Break)
{ {
/* Allocate more memory. */ /* 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); void *Allocated = vma->RequestPages(Pages);
if (Allocated == nullptr) if (Allocated == nullptr)
return (void *)-ENOMEM; return (void *)-ENOMEM;
/* Map the allocated pages. */ /* 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 *VirtAddr = (void *)(Break + (i * PAGE_SIZE));
void *PhysAddr = (void *)(uintptr_t(Allocated) + (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); vmm.Map(VirtAddr, PhysAddr, RW | US);
} }
Break = (uint64_t)Address; Break = ROUND_UP(uintptr_t(Address), PAGE_SIZE);
return (void *)Break; debug("Round up %#lx to %#lx", Address, Break);
return Address;
} }
/* Free memory. */ /* 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); vma->FreePages((void *)Break, Pages);
/* Unmap the freed 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); 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; Break = (uint64_t)Address;
@ -82,12 +88,16 @@ namespace Memory
assert(Table != nullptr); assert(Table != nullptr);
assert(vma != nullptr); assert(vma != nullptr);
debug("+ %#lx", this);
this->Table = Table; this->Table = Table;
this->vma = vma; this->vma = vma;
} }
ProgramBreak::~ProgramBreak() ProgramBreak::~ProgramBreak()
{ {
debug("- %#lx", this);
/* Do nothing because VirtualMemoryArea /* Do nothing because VirtualMemoryArea
will be destroyed later. */ will be destroyed later. */
} }

View File

@ -1,4 +1,5 @@
#include "liballoc_1_1.h" #include "liballoc_1_1.h"
#include <convert.h>
#pragma GCC diagnostic ignored "-Wconversion" #pragma GCC diagnostic ignored "-Wconversion"
#pragma GCC diagnostic ignored "-Wsign-conversion" #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) __no_sanitize("undefined") static void *liballoc_memset(void *s, int c, size_t n)
{ {
return memset(s, c, n);
unsigned int i; unsigned int i;
for (i = 0; i < n; i++) for (i = 0; i < n; i++)
((char *)s)[i] = c; ((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) __no_sanitize("undefined") static void *liballoc_memcpy(void *s1, const void *s2, size_t n)
{ {
return memcpy(s1, s2, n);
char *cdest; char *cdest;
char *csrc; char *csrc;
unsigned int *ldest = (unsigned int *)s1; unsigned int *ldest = (unsigned int *)s1;

View File

@ -16,11 +16,14 @@ EXTERNC int liballoc_unlock()
EXTERNC void *liballoc_alloc(size_t Pages) 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) EXTERNC int liballoc_free(void *Address, size_t Pages)
{ {
debug("(%#lx, %d)", Address, Pages);
KernelAllocator.FreePages(Address, Pages); KernelAllocator.FreePages(Address, Pages);
return 0; return 0;
} }

File diff suppressed because it is too large Load Diff

View File

@ -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 <stddef.h>
#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

View File

@ -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 <https://www.gnu.org/licenses/>.
*/
#include <memory/macro.hpp>
#include <sys/mman.h>
#include <memory.hpp>
#include <assert.h>
#include <unistd.h>
// #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;
}

View File

@ -26,6 +26,7 @@
#include "heap_allocators/Xalloc/Xalloc.hpp" #include "heap_allocators/Xalloc/Xalloc.hpp"
#include "heap_allocators/liballoc_1_1/liballoc_1_1.h" #include "heap_allocators/liballoc_1_1/liballoc_1_1.h"
#include "heap_allocators/rpmalloc/rpmalloc.h"
#include "../../kernel.h" #include "../../kernel.h"
// #define DEBUG_ALLOCATIONS 1 // #define DEBUG_ALLOCATIONS 1
@ -72,7 +73,7 @@ NIF void tracepagetable(PageTable *pt)
NIF void MapFromZero(PageTable *PT) NIF void MapFromZero(PageTable *PT)
{ {
debug("Mapping from 0x0 to %#llx", bInfo.Memory.Size); debug("Mapping from 0x0 to %#llx", bInfo.Memory.Size);
Virtual va = Virtual(PT); Virtual vmm = Virtual(PT);
size_t MemSize = bInfo.Memory.Size; size_t MemSize = bInfo.Memory.Size;
if (Page1GBSupport && PSESupport) if (Page1GBSupport && PSESupport)
@ -80,29 +81,29 @@ NIF void MapFromZero(PageTable *PT)
/* Map the first 100MB of memory as 4KB pages */ /* Map the first 100MB of memory as 4KB pages */
// uintptr_t Physical4KBSectionStart = 0x10000000; // uintptr_t Physical4KBSectionStart = 0x10000000;
// va.Map((void *)0, // vmm.Map((void *)0,
// (void *)0, // (void *)0,
// Physical4KBSectionStart, // Physical4KBSectionStart,
// PTFlag::RW); // RW);
// va.Map((void *)Physical4KBSectionStart, // vmm.Map((void *)Physical4KBSectionStart,
// (void *)Physical4KBSectionStart, // (void *)Physical4KBSectionStart,
// MemSize - Physical4KBSectionStart, // MemSize - Physical4KBSectionStart,
// PTFlag::RW, // RW,
// Virtual::MapType::OneGiB); // Virtual::MapType::OneGiB);
va.Map((void *)0, (void *)0, MemSize, PTFlag::RW); vmm.Map((void *)0, (void *)0, MemSize, RW);
} }
else 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"); debug("Mapping Framebuffer");
Virtual va = Virtual(PT); Virtual vmm = Virtual(PT);
int itrfb = 0; int itrfb = 0;
while (1) 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; size_t fbSize = bInfo.Framebuffer[itrfb].Pitch * bInfo.Framebuffer[itrfb].Height;
if (PSE && OneGB) if (PSESupport && Page1GBSupport)
{ {
va.OptimizedMap(bInfo.Framebuffer[itrfb].BaseAddress, vmm.OptimizedMap(bInfo.Framebuffer[itrfb].BaseAddress,
bInfo.Framebuffer[itrfb].BaseAddress, bInfo.Framebuffer[itrfb].BaseAddress,
fbSize, PTFlag::RW | PTFlag::US | PTFlag::G); fbSize, RW | US | G);
} }
else else
{ {
va.Map(bInfo.Framebuffer[itrfb].BaseAddress, vmm.Map(bInfo.Framebuffer[itrfb].BaseAddress,
bInfo.Framebuffer[itrfb].BaseAddress, bInfo.Framebuffer[itrfb].BaseAddress,
fbSize, PTFlag::RW | PTFlag::US | PTFlag::G); fbSize, RW | US | G);
} }
itrfb++; itrfb++;
} }
@ -176,14 +177,14 @@ NIF void MapKernel(PageTable *PT)
uintptr_t BaseKernelMapAddress = (uintptr_t)bInfo.Kernel.PhysicalBase; uintptr_t BaseKernelMapAddress = (uintptr_t)bInfo.Kernel.PhysicalBase;
debug("Base kernel map address: %#lx", BaseKernelMapAddress); debug("Base kernel map address: %#lx", BaseKernelMapAddress);
uintptr_t k; uintptr_t k;
Virtual va = Virtual(PT); Virtual vmm = Virtual(PT);
/* Bootstrap section */ /* Bootstrap section */
if (BaseKernelMapAddress == BootstrapStart) if (BaseKernelMapAddress == BootstrapStart)
{ {
for (k = BootstrapStart; k < BootstrapEnd; k += PAGE_SIZE) 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); KernelAllocator.ReservePage((void *)BaseKernelMapAddress);
BaseKernelMapAddress += PAGE_SIZE; BaseKernelMapAddress += PAGE_SIZE;
} }
@ -197,7 +198,7 @@ NIF void MapKernel(PageTable *PT)
/* Text section */ /* Text section */
for (k = KernelTextStart; k < KernelTextEnd; k += PAGE_SIZE) 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); KernelAllocator.ReservePage((void *)BaseKernelMapAddress);
BaseKernelMapAddress += PAGE_SIZE; BaseKernelMapAddress += PAGE_SIZE;
} }
@ -205,7 +206,7 @@ NIF void MapKernel(PageTable *PT)
/* Data section */ /* Data section */
for (k = KernelDataStart; k < KernelDataEnd; k += PAGE_SIZE) 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); KernelAllocator.ReservePage((void *)BaseKernelMapAddress);
BaseKernelMapAddress += PAGE_SIZE; BaseKernelMapAddress += PAGE_SIZE;
} }
@ -213,7 +214,7 @@ NIF void MapKernel(PageTable *PT)
/* Read only data section */ /* Read only data section */
for (k = KernelRoDataStart; k < KernelRoDataEnd; k += PAGE_SIZE) 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); KernelAllocator.ReservePage((void *)BaseKernelMapAddress);
BaseKernelMapAddress += PAGE_SIZE; BaseKernelMapAddress += PAGE_SIZE;
} }
@ -221,7 +222,7 @@ NIF void MapKernel(PageTable *PT)
/* Block starting symbol section */ /* Block starting symbol section */
for (k = KernelBssStart; k < KernelBssEnd; k += PAGE_SIZE) 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); KernelAllocator.ReservePage((void *)BaseKernelMapAddress);
BaseKernelMapAddress += PAGE_SIZE; BaseKernelMapAddress += PAGE_SIZE;
} }
@ -233,10 +234,63 @@ NIF void MapKernel(PageTable *PT)
{ {
for (k = KernelFileStart; k < KernelFileEnd; k += PAGE_SIZE) 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); 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() NIF void InitializeMemoryManagement()
@ -312,58 +366,59 @@ NIF void InitializeMemoryManagement()
KernelPageTable = (PageTable *)KernelAllocator.RequestPages(TO_PAGES(PAGE_SIZE + 1)); KernelPageTable = (PageTable *)KernelAllocator.RequestPages(TO_PAGES(PAGE_SIZE + 1));
memset(KernelPageTable, 0, PAGE_SIZE); memset(KernelPageTable, 0, PAGE_SIZE);
if (strcmp(CPU::Vendor(), x86_CPUID_VENDOR_AMD) == 0) CreatePageTable(KernelPageTable);
{
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) trace("Applying new page table from address %#lx",
{ KernelPageTable);
#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
CPU::PageTable(KernelPageTable); CPU::PageTable(KernelPageTable);
debug("Page table updated."); debug("Page table updated.");
XallocV1Allocator = new Xalloc::V1((void *)KERNEL_HEAP_BASE, false, false); /* FIXME: Read kernel params */
XallocV2Allocator = new Xalloc::V2((void *)KERNEL_HEAP_BASE); AllocatorType = Config.AllocatorType;
trace("XallocV1 Allocator initialized at %#lx", XallocV1Allocator);
trace("XallocV2 Allocator initialized at %#lx", XallocV2Allocator);
/* FIXME: Read kernel config */ switch (AllocatorType)
AllocatorType = MemoryAllocatorType::liballoc11; {
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) void *malloc(size_t Size)
@ -371,7 +426,7 @@ void *malloc(size_t Size)
assert(Size > 0); assert(Size > 0);
memdbg("malloc(%d)->[%s]", Size, memdbg("malloc(%d)->[%s]", Size,
KernelSymbolTable ? KernelSymbolTable->GetSymbolFromAddress((uintptr_t)__builtin_return_address(0)) KernelSymbolTable ? KernelSymbolTable->GetSymbol((uintptr_t)__builtin_return_address(0))
: "Unknown"); : "Unknown");
void *ret = nullptr; void *ret = nullptr;
@ -397,6 +452,11 @@ void *malloc(size_t Size)
ret = PREFIX(malloc)(Size); ret = PREFIX(malloc)(Size);
break; break;
} }
case MemoryAllocatorType::rpmalloc_:
{
ret = rpmalloc(Size);
break;
}
default: default:
{ {
error("Unknown allocator type %d", AllocatorType); error("Unknown allocator type %d", AllocatorType);
@ -413,7 +473,7 @@ void *calloc(size_t n, size_t Size)
assert(Size > 0); assert(Size > 0);
memdbg("calloc(%d, %d)->[%s]", n, Size, 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"); : "Unknown");
void *ret = nullptr; void *ret = nullptr;
@ -439,6 +499,11 @@ void *calloc(size_t n, size_t Size)
void *ret = PREFIX(calloc)(n, Size); void *ret = PREFIX(calloc)(n, Size);
return ret; return ret;
} }
case MemoryAllocatorType::rpmalloc_:
{
ret = rpcalloc(n, Size);
break;
}
default: default:
{ {
error("Unknown allocator type %d", AllocatorType); error("Unknown allocator type %d", AllocatorType);
@ -455,7 +520,7 @@ void *realloc(void *Address, size_t Size)
assert(Size > 0); assert(Size > 0);
memdbg("realloc(%#lx, %d)->[%s]", Address, Size, 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"); : "Unknown");
void *ret = nullptr; void *ret = nullptr;
@ -481,6 +546,11 @@ void *realloc(void *Address, size_t Size)
void *ret = PREFIX(realloc)(Address, Size); void *ret = PREFIX(realloc)(Address, Size);
return ret; return ret;
} }
case MemoryAllocatorType::rpmalloc_:
{
ret = rprealloc(Address, Size);
break;
}
default: default:
{ {
error("Unknown allocator type %d", AllocatorType); error("Unknown allocator type %d", AllocatorType);
@ -497,7 +567,7 @@ void free(void *Address)
assert(Address != nullptr); assert(Address != nullptr);
memdbg("free(%#lx)->[%s]", Address, memdbg("free(%#lx)->[%s]", Address,
KernelSymbolTable ? KernelSymbolTable->GetSymbolFromAddress((uintptr_t)__builtin_return_address(0)) KernelSymbolTable ? KernelSymbolTable->GetSymbol((uintptr_t)__builtin_return_address(0))
: "Unknown"); : "Unknown");
switch (AllocatorType) switch (AllocatorType)
@ -523,6 +593,11 @@ void free(void *Address)
(Address); (Address);
break; break;
} }
case MemoryAllocatorType::rpmalloc_:
{
rpfree(Address);
break;
}
default: default:
{ {
error("Unknown allocator type %d", AllocatorType); error("Unknown allocator type %d", AllocatorType);
@ -536,7 +611,7 @@ void *operator new(std::size_t Size)
assert(Size > 0); assert(Size > 0);
memdbg("new(%d)->[%s]", Size, memdbg("new(%d)->[%s]", Size,
KernelSymbolTable ? KernelSymbolTable->GetSymbolFromAddress((uintptr_t)__builtin_return_address(0)) KernelSymbolTable ? KernelSymbolTable->GetSymbol((uintptr_t)__builtin_return_address(0))
: "Unknown"); : "Unknown");
void *ret = malloc(Size); void *ret = malloc(Size);
@ -548,7 +623,7 @@ void *operator new[](std::size_t Size)
assert(Size > 0); assert(Size > 0);
memdbg("new[](%d)->[%s]", Size, memdbg("new[](%d)->[%s]", Size,
KernelSymbolTable ? KernelSymbolTable->GetSymbolFromAddress((uintptr_t)__builtin_return_address(0)) KernelSymbolTable ? KernelSymbolTable->GetSymbol((uintptr_t)__builtin_return_address(0))
: "Unknown"); : "Unknown");
void *ret = malloc(Size); void *ret = malloc(Size);
@ -560,7 +635,7 @@ void *operator new(std::size_t Size, std::align_val_t Alignment)
assert(Size > 0); assert(Size > 0);
memdbg("new(%d, %d)->[%s]", Size, Alignment, 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"); : "Unknown");
fixme("operator new with alignment(%#lx) is not implemented", fixme("operator new with alignment(%#lx) is not implemented",
@ -575,7 +650,7 @@ void operator delete(void *Pointer)
assert(Pointer != nullptr); assert(Pointer != nullptr);
memdbg("delete(%#lx)->[%s]", Pointer, memdbg("delete(%#lx)->[%s]", Pointer,
KernelSymbolTable ? KernelSymbolTable->GetSymbolFromAddress((uintptr_t)__builtin_return_address(0)) KernelSymbolTable ? KernelSymbolTable->GetSymbol((uintptr_t)__builtin_return_address(0))
: "Unknown"); : "Unknown");
free(Pointer); free(Pointer);
@ -586,7 +661,7 @@ void operator delete[](void *Pointer)
assert(Pointer != nullptr); assert(Pointer != nullptr);
memdbg("delete[](%#lx)->[%s]", Pointer, memdbg("delete[](%#lx)->[%s]", Pointer,
KernelSymbolTable ? KernelSymbolTable->GetSymbolFromAddress((uintptr_t)__builtin_return_address(0)) KernelSymbolTable ? KernelSymbolTable->GetSymbol((uintptr_t)__builtin_return_address(0))
: "Unknown"); : "Unknown");
free(Pointer); free(Pointer);
@ -599,7 +674,7 @@ void operator delete(void *Pointer, long unsigned int Size)
memdbg("delete(%#lx, %d)->[%s]", memdbg("delete(%#lx, %d)->[%s]",
Pointer, Size, Pointer, Size,
KernelSymbolTable ? KernelSymbolTable->GetSymbolFromAddress((uintptr_t)__builtin_return_address(0)) KernelSymbolTable ? KernelSymbolTable->GetSymbol((uintptr_t)__builtin_return_address(0))
: "Unknown"); : "Unknown");
free(Pointer); free(Pointer);
@ -612,7 +687,7 @@ void operator delete[](void *Pointer, long unsigned int Size)
memdbg("delete[](%#lx, %d)->[%s]", memdbg("delete[](%#lx, %d)->[%s]",
Pointer, Size, Pointer, Size,
KernelSymbolTable ? KernelSymbolTable->GetSymbolFromAddress((uintptr_t)__builtin_return_address(0)) KernelSymbolTable ? KernelSymbolTable->GetSymbol((uintptr_t)__builtin_return_address(0))
: "Unknown"); : "Unknown");
free(Pointer); free(Pointer);

View File

@ -1,6 +1,9 @@
#include <memory.hpp> #include <memory.hpp>
#include <filesystem.hpp> #include <filesystem.hpp>
#include <signal.hpp>
#include <utsname.h>
#include <time.h>
namespace Memory namespace Memory
{ {
@ -13,29 +16,75 @@ namespace Memory
#endif #endif
} }
PageTable PageTable::Fork() PageTable *PageTable::Fork()
{ {
PageTable NewTable; PageTable *NewTable = (PageTable *)KernelAllocator.RequestPages(TO_PAGES(sizeof(PageTable)));
memcpy(&NewTable, this, 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; return NewTable;
} }
template <typename T> /* We can't have Memory::Virtual in the header */
T PageTable::Get(T Address) void *PageTable::__getPhysical(void *Address)
{ {
Virtual vmm = Virtual(this); Virtual vmm(this);
void *PhysAddr = vmm.GetPhysical((void *)Address); void *PhysAddr = vmm.GetPhysical((void *)Address);
uintptr_t Diff = uintptr_t(Address); return PhysAddr;
Diff &= 0xFFF;
Diff = uintptr_t(PhysAddr) + Diff;
return (T)Diff;
} }
/* Templates */
template struct stat *PageTable::Get<struct stat *>(struct stat *);
template const char *PageTable::Get<const char *>(const char *);
template const void *PageTable::Get<const void *>(const void *);
template uintptr_t PageTable::Get<uintptr_t>(uintptr_t);
template void *PageTable::Get<void *>(void *);
/* ... */
} }

View File

@ -107,9 +107,11 @@ namespace Memory
} }
error("Out of memory! (Free: %ld MiB; Used: %ld MiB; Reserved: %ld MiB)", 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)", 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(); CPU::Stop();
__builtin_unreachable(); __builtin_unreachable();
} }
@ -157,9 +159,11 @@ namespace Memory
} }
error("Out of memory! (Free: %ld MiB; Used: %ld MiB; Reserved: %ld MiB)", 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)", 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); CPU::Halt(true);
__builtin_unreachable(); __builtin_unreachable();
} }
@ -185,8 +189,8 @@ namespace Memory
if (PageBitmap.Set(Index, false)) if (PageBitmap.Set(Index, false))
{ {
FreeMemory += PAGE_SIZE; FreeMemory.fetch_add(PAGE_SIZE);
UsedMemory -= PAGE_SIZE; UsedMemory.fetch_sub(PAGE_SIZE);
if (PageBitmapIndex > Index) if (PageBitmapIndex > Index)
PageBitmapIndex = Index; PageBitmapIndex = Index;
} }
@ -215,8 +219,8 @@ namespace Memory
if (PageBitmap.Set(Index, true)) if (PageBitmap.Set(Index, true))
{ {
FreeMemory -= PAGE_SIZE; FreeMemory.fetch_sub(PAGE_SIZE);
UsedMemory += PAGE_SIZE; UsedMemory.fetch_add(PAGE_SIZE);
} }
} }
@ -243,8 +247,8 @@ namespace Memory
if (PageBitmap.Set(Index, true)) if (PageBitmap.Set(Index, true))
{ {
FreeMemory -= PAGE_SIZE; FreeMemory.fetch_sub(PAGE_SIZE);
ReservedMemory += PAGE_SIZE; ReservedMemory.fetch_add(PAGE_SIZE);
} }
} }
@ -264,8 +268,8 @@ namespace Memory
if (PageBitmap.Set(Index, true)) if (PageBitmap.Set(Index, true))
{ {
FreeMemory -= PAGE_SIZE; FreeMemory.fetch_sub(PAGE_SIZE);
ReservedMemory += PAGE_SIZE; ReservedMemory.fetch_add(PAGE_SIZE);
} }
} }
} }
@ -282,8 +286,8 @@ namespace Memory
if (PageBitmap.Set(Index, false)) if (PageBitmap.Set(Index, false))
{ {
FreeMemory += PAGE_SIZE; FreeMemory.fetch_add(PAGE_SIZE);
ReservedMemory -= PAGE_SIZE; ReservedMemory.fetch_sub(PAGE_SIZE);
if (PageBitmapIndex > Index) if (PageBitmapIndex > Index)
PageBitmapIndex = Index; PageBitmapIndex = Index;
} }
@ -305,8 +309,8 @@ namespace Memory
if (PageBitmap.Set(Index, false)) if (PageBitmap.Set(Index, false))
{ {
FreeMemory += PAGE_SIZE; FreeMemory.fetch_add(PAGE_SIZE);
ReservedMemory -= PAGE_SIZE; ReservedMemory.fetch_sub(PAGE_SIZE);
if (PageBitmapIndex > Index) if (PageBitmapIndex > Index)
PageBitmapIndex = Index; PageBitmapIndex = Index;
} }
@ -320,8 +324,8 @@ namespace Memory
uint64_t MemorySize = bInfo.Memory.Size; uint64_t MemorySize = bInfo.Memory.Size;
debug("Memory size: %lld bytes (%ld pages)", debug("Memory size: %lld bytes (%ld pages)",
MemorySize, TO_PAGES(MemorySize)); MemorySize, TO_PAGES(MemorySize));
TotalMemory = MemorySize; TotalMemory.store(MemorySize);
FreeMemory = MemorySize; FreeMemory.store(MemorySize);
size_t BitmapSize = (size_t)(MemorySize / PAGE_SIZE) / 8 + 1; size_t BitmapSize = (size_t)(MemorySize / PAGE_SIZE) / 8 + 1;
uintptr_t BitmapAddress = 0x0; uintptr_t BitmapAddress = 0x0;

View File

@ -80,7 +80,7 @@ namespace Memory
if (this->UserMode) if (this->UserMode)
{ {
std::vector<AllocatedPages> ParentAllocatedPages = Parent->GetAllocatedPages(); std::vector<AllocatedPages> ParentAllocatedPages = Parent->GetAllocatedPages();
Virtual vma = Virtual(this->vma->GetTable()); Virtual vma(this->vma->GetTable());
foreach (auto Page in ParentAllocatedPages) foreach (auto Page in ParentAllocatedPages)
{ {
void *NewPhysical = this->vma->RequestPages(1); void *NewPhysical = this->vma->RequestPages(1);
@ -162,6 +162,7 @@ namespace Memory
} }
debug("Allocated stack at %#lx", this->StackBottom); debug("Allocated stack at %#lx", this->StackBottom);
debug("Stack Range: %#lx - %#lx", this->StackBottom, this->StackTop);
} }
StackGuard::~StackGuard() StackGuard::~StackGuard()

View File

@ -74,6 +74,8 @@ namespace Memory
bool VirtualMemoryArea::Add(void *Address, size_t Count) bool VirtualMemoryArea::Add(void *Address, size_t Count)
{ {
SmartLock(MgrLock); SmartLock(MgrLock);
function("%#lx, %lld", Address, Count);
if (Address == nullptr) if (Address == nullptr)
{ {
error("Address is null!"); error("Address is null!");
@ -118,7 +120,10 @@ namespace Memory
void *VirtualMemoryArea::RequestPages(size_t Count, bool User) void *VirtualMemoryArea::RequestPages(size_t Count, bool User)
{ {
SmartLock(MgrLock); SmartLock(MgrLock);
function("%lld, %s", Count, User ? "true" : "false");
void *Address = KernelAllocator.RequestPages(Count); void *Address = KernelAllocator.RequestPages(Count);
memset(Address, 0, Count * PAGE_SIZE);
for (size_t i = 0; i < Count; i++) for (size_t i = 0; i < Count; i++)
{ {
int Flags = Memory::PTFlag::RW; int Flags = Memory::PTFlag::RW;
@ -127,23 +132,19 @@ namespace Memory
void *AddressToMap = (void *)((uintptr_t)Address + (i * PAGE_SIZE)); void *AddressToMap = (void *)((uintptr_t)Address + (i * PAGE_SIZE));
Memory::Virtual vmm = Memory::Virtual(this->Table); Memory::Virtual vmm(this->Table);
vmm.Remap(AddressToMap, AddressToMap, Flags); vmm.Map(AddressToMap, AddressToMap, Flags);
} }
AllocatedPagesList.push_back({Address, Count}); 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; return Address;
} }
void VirtualMemoryArea::FreePages(void *Address, size_t Count) void VirtualMemoryArea::FreePages(void *Address, size_t Count)
{ {
SmartLock(MgrLock); SmartLock(MgrLock);
function("%#lx, %lld", Address, Count);
forItr(itr, AllocatedPagesList) forItr(itr, AllocatedPagesList)
{ {
if (itr->Address == Address) if (itr->Address == Address)
@ -162,7 +163,7 @@ namespace Memory
KernelAllocator.FreePages(Address, Count); KernelAllocator.FreePages(Address, Count);
Memory::Virtual vmm = Memory::Virtual(this->Table); Memory::Virtual vmm(this->Table);
for (size_t i = 0; i < Count; i++) for (size_t i = 0; i < Count; i++)
{ {
void *AddressToMap = (void *)((uintptr_t)Address + (i * PAGE_SIZE)); void *AddressToMap = (void *)((uintptr_t)Address + (i * PAGE_SIZE));
@ -178,6 +179,8 @@ namespace Memory
void VirtualMemoryArea::DetachAddress(void *Address) void VirtualMemoryArea::DetachAddress(void *Address)
{ {
SmartLock(MgrLock); SmartLock(MgrLock);
function("%#lx", Address);
forItr(itr, AllocatedPagesList) forItr(itr, AllocatedPagesList)
{ {
if (itr->Address == Address) if (itr->Address == Address)
@ -193,7 +196,14 @@ namespace Memory
bool Read, bool Write, bool Exec, bool Read, bool Write, bool Exec,
bool Fixed, bool Shared) 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 // FIXME
// for (uintptr_t j = uintptr_t(Address); // for (uintptr_t j = uintptr_t(Address);
@ -209,20 +219,21 @@ namespace Memory
// } // }
bool AnyAddress = Address == nullptr; bool AnyAddress = Address == nullptr;
debug("AnyAddress: %s", AnyAddress ? "true" : "false");
if (AnyAddress) if (AnyAddress)
{ {
Address = this->RequestPages(1); Address = this->RequestPages(TO_PAGES(Length), true);
if (Address == nullptr) debug("Allocated %#lx-%#lx for pt %#lx",
return nullptr; Address, (uintptr_t)Address + Length, this->Table);
memset(Address, 0, PAGE_SIZE); return Address;
} }
SmartLock(MgrLock);
vmm.Unmap(Address, Length); vmm.Unmap(Address, Length);
vmm.Map(Address, nullptr, Length, PTFlag::CoW); vmm.Map(Address, nullptr, Length, PTFlag::CoW);
debug("CoW region created at range %#lx-%#lx for pt %#lx",
if (AnyAddress) Address, (uintptr_t)Address + Length, this->Table);
vmm.Remap(Address, Address, PTFlag::RW | PTFlag::US);
SharedRegion sr{ SharedRegion sr{
.Address = Address, .Address = Address,
@ -235,13 +246,15 @@ namespace Memory
.ReferenceCount = 0, .ReferenceCount = 0,
}; };
SharedRegions.push_back(sr); SharedRegions.push_back(sr);
debug("CoW region created at %#lx for pt %#lx",
Address, this->Table);
return Address; return Address;
} }
bool VirtualMemoryArea::HandleCoW(uintptr_t PFA) bool VirtualMemoryArea::HandleCoW(uintptr_t PFA)
{ {
function("%#lx", PFA); function("%#lx", PFA);
Memory::Virtual vmm = Memory::Virtual(this->Table); Memory::Virtual vmm(this->Table);
Memory::PageTableEntry *pte = vmm.GetPTE((void *)PFA); Memory::PageTableEntry *pte = vmm.GetPTE((void *)PFA);
if (!pte) if (!pte)
@ -260,6 +273,9 @@ namespace Memory
if (PFA >= Start && PFA < End) if (PFA >= Start && PFA < End)
{ {
debug("Start: %#lx, End: %#lx (PFA: %#lx)",
Start, End, PFA);
if (sr.Shared) if (sr.Shared)
{ {
fixme("Shared CoW"); fixme("Shared CoW");
@ -272,30 +288,117 @@ namespace Memory
return false; return false;
memset(pAddr, 0, PAGE_SIZE); memset(pAddr, 0, PAGE_SIZE);
uint64_t Flags = 0; assert(pte->Present == true);
if (sr.Read) pte->ReadWrite = sr.Write;
Flags |= PTFlag::US; pte->UserSupervisor = sr.Read;
if (sr.Write) pte->ExecuteDisable = sr.Exec;
Flags |= PTFlag::RW;
// if (sr.Exec)
// Flags |= PTFlag::XD;
vmm.Remap((void *)PFA, pAddr, Flags);
pte->CopyOnWrite = false; 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; return true;
} }
} }
} }
} }
debug("PFA %#lx is not CoW", PFA); debug("PFA %#lx is not CoW (pt %#lx)",
PFA, this->Table);
return false; 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) VirtualMemoryArea::VirtualMemoryArea(PageTable *Table)
{ {
debug("+ %#lx %s", this, debug("+ %#lx %s", this,
KernelSymbolTable ? KernelSymbolTable->GetSymbolFromAddress((uintptr_t)__builtin_return_address(0)) : ""); KernelSymbolTable ? KernelSymbolTable->GetSymbol((uintptr_t)__builtin_return_address(0)) : "");
SmartLock(MgrLock); SmartLock(MgrLock);
if (Table) if (Table)
@ -316,12 +419,22 @@ namespace Memory
VirtualMemoryArea::~VirtualMemoryArea() VirtualMemoryArea::~VirtualMemoryArea()
{ {
debug("- %#lx %s", this, 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); SmartLock(MgrLock);
Memory::Virtual vmm(this->Table);
foreach (auto ap in AllocatedPagesList) foreach (auto ap in AllocatedPagesList)
{ {
KernelAllocator.FreePages(ap.Address, ap.PageCount); 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++) for (size_t i = 0; i < ap.PageCount; i++)
vmm.Remap((void *)((uintptr_t)ap.Address + (i * PAGE_SIZE)), vmm.Remap((void *)((uintptr_t)ap.Address + (i * PAGE_SIZE)),
(void *)((uintptr_t)ap.Address + (i * PAGE_SIZE)), (void *)((uintptr_t)ap.Address + (i * PAGE_SIZE)),

View File

@ -20,15 +20,25 @@
#include <convert.h> #include <convert.h>
#include <debug.h> #include <debug.h>
#include "../../kernel.h"
namespace Memory namespace Memory
{ {
Virtual::Virtual(PageTable *Table) Virtual::Virtual(PageTable *Table)
{ {
if (Table) if (Table)
this->Table = Table; this->pTable = Table;
else else
this->Table = (PageTable *)CPU::PageTable(); this->pTable = thisPageTable;
// debug("+ %#lx (PT: %#lx) %s", this, this->pTable,
// KernelSymbolTable
// ? KernelSymbolTable->GetSymbol((uintptr_t)__builtin_return_address(0))
// : "Unknown");
} }
Virtual::~Virtual() {} Virtual::~Virtual()
{
// debug("- %#lx", this);
}
} }

View File

@ -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 <https://www.gnu.org/licenses/>.
*/
#include <module.hpp>
#include <memory.hpp>
#include <ints.hpp>
#include <task.hpp>
#include <printf.h>
#include <cwalk.h>
#include <md5.h>
#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))(&regs);
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
}
}

View File

@ -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 <https://www.gnu.org/licenses/>.
*/
#include <module.hpp>
#include <dumper.hpp>
#include <lock.hpp>
#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,
},
};

View File

@ -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 <https://www.gnu.org/licenses/>.
*/
#include "../api.hpp"
#include <ints.hpp>
#include <memory.hpp>
#include <task.hpp>
#include <lock.hpp>
#include <printf.h>
#include <cwalk.h>
#include <md5.h>
#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;
}
}
}
}

View File

@ -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 <https://www.gnu.org/licenses/>.
*/
#include "../api.hpp"
#include <ints.hpp>
#include <memory.hpp>
#include <task.hpp>
#include <lock.hpp>
#include <printf.h>
#include <cwalk.h>
#include <md5.h>
#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<PCI::PCIDevice> 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;
}
}

View File

@ -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 <https://www.gnu.org/licenses/>.
*/
#include "../api.hpp"
#include <ints.hpp>
#include <memory.hpp>
#include <task.hpp>
#include <lock.hpp>
#include <printf.h>
#include <cwalk.h>
#include <md5.h>
#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;
}
}

View File

@ -279,6 +279,10 @@ namespace PCI
{ {
switch (VendorID) switch (VendorID)
{ {
case 0x106B:
return "Apple Inc.";
case 0x104B:
return "Bus Logic";
case 0x1000: case 0x1000:
return "Symbios Logic"; return "Symbios Logic";
case 0x1B36: case 0x1B36:
@ -317,12 +321,36 @@ namespace PCI
{ {
switch (VendorID) 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: case SymbiosLogic:
{ {
switch (DeviceID) switch (DeviceID)
{ {
case 0x30: case 0x30:
return "53c1030 PCI-X Fusion-MPT Dual Ultra320 SCSI"; return "53c1030 PCI-X Fusion-MPT Dual Ultra320 SCSI";
case 0x54:
return "SAS1068 PCI-X Fusion-MPT SAS";
case 0x1000: case 0x1000:
return "63C815"; return "63C815";
default: default:
@ -420,6 +448,12 @@ namespace PCI
return "RTL-8029(AS)"; return "RTL-8029(AS)";
case 0x8139: case 0x8139:
return "RTL-8139/8139C/8139C+ Ethernet Controller"; 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: default:
break; break;
} }
@ -503,6 +537,8 @@ namespace PCI
return "82557/8/9/0/1 Ethernet Pro 100"; return "82557/8/9/0/1 Ethernet Pro 100";
case 0x1209: case 0x1209:
return "8255xER/82551IT Fast Ethernet Controller"; return "8255xER/82551IT Fast Ethernet Controller";
case 0x1004:
return "82543GC Gigabit Ethernet Controller (Copper)";
case 0x100E: case 0x100E:
return "82540EM Gigabit Ethernet Controller"; return "82540EM Gigabit Ethernet Controller";
case 0x7190: case 0x7190:
@ -519,6 +555,10 @@ namespace PCI
return "7 Series/C210 Series Chipset Family USB xHCI Host Controller"; return "7 Series/C210 Series Chipset Family USB xHCI Host Controller";
case 0x100F: case 0x100F:
return "82545EM Gigabit Ethernet Controller (Copper)"; 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: case 0x1371:
return "ES1371/ES1373 / Creative Labs CT2518"; return "ES1371/ES1373 / Creative Labs CT2518";
case 0x27b9: case 0x27b9:
@ -537,6 +577,8 @@ namespace PCI
return "82801I (ICH9 Family) USB UHCI Controller #1"; return "82801I (ICH9 Family) USB UHCI Controller #1";
case 0x2668: case 0x2668:
return "82801FB/FBM/FR/FW/FRW (ICH6 Family) High Definition Audio Controller"; 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: case 0x2415:
return "82801AA AC'97 Audio Controller"; return "82801AA AC'97 Audio Controller";
case 0x10D3: case 0x10D3:
@ -551,6 +593,40 @@ namespace PCI
return "82801IR/IO/IH (ICH9R/DO/DH) 6 port SATA Controller [AHCI mode]"; return "82801IR/IO/IH (ICH9R/DO/DH) 6 port SATA Controller [AHCI mode]";
case 0x2930: case 0x2930:
return "82801I (ICH9 Family) SMBus Controller"; 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: default:
break; break;
} }
@ -567,9 +643,20 @@ namespace PCI
} }
break; break;
} }
case NVIDIACorporation:
{
switch (DeviceID)
{
case 0x174D:
return "GM108M [GeForce MX130]";
default: default:
break; break;
} }
break;
default:
break;
}
}
fixme("Unknown device %04x:%04x", VendorID, DeviceID); fixme("Unknown device %04x:%04x", VendorID, DeviceID);
return u32ToHexString(DeviceID); return u32ToHexString(DeviceID);
} }
@ -772,9 +859,12 @@ namespace PCI
} }
#ifdef DEBUG #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, hdr->VendorID, hdr->DeviceID,
Descriptors::GetVendorName(hdr->VendorID), Descriptors::GetVendorName(hdr->VendorID),
Descriptors::GetDeviceName(hdr->VendorID, hdr->DeviceID), Descriptors::GetDeviceName(hdr->VendorID, hdr->DeviceID),
@ -784,27 +874,31 @@ namespace PCI
} }
#endif #endif
void PCI::MapPCIAddresses(PCIDevice Device, Memory::PageTable *Table) void Manager::MapPCIAddresses(PCIDevice Device, Memory::PageTable *Table)
{ {
debug("Header Type: %d", Device.Header->HeaderType); debug("Header Type: %d", Device.Header->HeaderType);
switch (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 */ case 0: /* PCI Header 0 */
{ {
uint32_t BAR[6] = {0}; PCIHeader0 *hdr0 = (PCIHeader0 *)Device.Header;
size_t BARsSize[6] = {0};
BAR[0] = ((PCIHeader0 *)Device.Header)->BAR0; uint32_t BAR[6];
BAR[1] = ((PCIHeader0 *)Device.Header)->BAR1; size_t BARsSize[6];
BAR[2] = ((PCIHeader0 *)Device.Header)->BAR2;
BAR[3] = ((PCIHeader0 *)Device.Header)->BAR3; BAR[0] = hdr0->BAR0;
BAR[4] = ((PCIHeader0 *)Device.Header)->BAR4; BAR[1] = hdr0->BAR1;
BAR[5] = ((PCIHeader0 *)Device.Header)->BAR5; BAR[2] = hdr0->BAR2;
BAR[3] = hdr0->BAR3;
BAR[4] = hdr0->BAR4;
BAR[5] = hdr0->BAR5;
debug("Type: %d; IOBase: %#lx; MemoryBase: %#lx", debug("Type: %d; IOBase: %#lx; MemoryBase: %#lx",
BAR[0] & 1, BAR[0] & 1, BAR[1] & (~3), BAR[0] & (~15));
BAR[1] & (~3),
BAR[0] & (~15));
/* BARs Size */ /* BARs Size */
for (short i = 0; i < 6; i++) for (short i = 0; i < 6; i++)
@ -812,25 +906,28 @@ namespace PCI
if (BAR[i] == 0) if (BAR[i] == 0)
continue; continue;
size_t size;
if ((BAR[i] & 1) == 0) /* Memory Base */ if ((BAR[i] & 1) == 0) /* Memory Base */
{ {
((PCIHeader0 *)Device.Header)->BAR0 = 0xFFFFFFFF; hdr0->BAR0 = 0xFFFFFFFF;
size_t size = ((PCIHeader0 *)Device.Header)->BAR0; size = hdr0->BAR0;
((PCIHeader0 *)Device.Header)->BAR0 = BAR[i]; hdr0->BAR0 = BAR[i];
BARsSize[i] = size & (~15); BARsSize[i] = size & (~15);
BARsSize[i] = ~BARsSize[i] + 1; BARsSize[i] = ~BARsSize[i] + 1;
BARsSize[i] = BARsSize[i] & 0xFFFFFFFF; 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 */ else if ((BAR[i] & 1) == 1) /* I/O Base */
{ {
((PCIHeader0 *)Device.Header)->BAR1 = 0xFFFFFFFF; hdr0->BAR1 = 0xFFFFFFFF;
size_t size = ((PCIHeader0 *)Device.Header)->BAR1; size = hdr0->BAR1;
((PCIHeader0 *)Device.Header)->BAR1 = BAR[i]; hdr0->BAR1 = BAR[i];
BARsSize[i] = size & (~3); BARsSize[i] = size & (~3);
BARsSize[i] = ~BARsSize[i] + 1; BARsSize[i] = ~BARsSize[i] + 1;
BARsSize[i] = BARsSize[i] & 0xFFFF; 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); uintptr_t BARBase = BAR[i] & (~15);
size_t BARSize = BARsSize[i]; size_t BARSize = BARsSize[i];
debug("Mapping BAR%d %#lx-%#lx", i, BARBase, BARBase + BARSize); debug("Mapping BAR%d %#lx-%#lx",
Memory::Virtual(Table).Map((void *)BARBase, (void *)BARBase, BARSize, i, BARBase, BARBase + BARSize);
Memory::PTFlag::RW | Memory::PTFlag::PWT);
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 */ else if ((BAR[i] & 1) == 1) /* I/O Base */
{ {
uintptr_t BARBase = BAR[i] & (~3); uintptr_t BARBase = BAR[i] & (~3);
size_t BARSize = BARsSize[i]; size_t BARSize = BARsSize[i];
debug("Mapping BAR%d %#x-%#x", i, BARBase, BARBase + BARSize); debug("Mapping BAR%d %#x-%#x",
Memory::Virtual(Table).Map((void *)BARBase, (void *)BARBase, BARSize, i, BARBase, BARBase + BARSize);
Memory::PTFlag::RW | Memory::PTFlag::PWT);
if (BARSize > 0)
Memory::Virtual(Table).Map((void *)BARBase, (void *)BARBase,
BARSize, Memory::RW | Memory::PWT);
} }
} }
break; break;
@ -874,12 +977,12 @@ namespace PCI
default: default:
{ {
error("Unknown header type %d", Device.Header->HeaderType); 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; dev.Function = Function;
@ -896,11 +999,11 @@ namespace PCI
Devices.push_back(dev); Devices.push_back(dev);
#ifdef DEBUG #ifdef DEBUG
e(PCIDeviceHdr); e(dev);
#endif #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; dev.Device = Device;
@ -918,7 +1021,7 @@ namespace PCI
EnumerateFunction(DeviceAddress, Function, dev); 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; dev.Bus = Bus;
@ -945,9 +1048,9 @@ namespace PCI
EnumerateDevice(BusAddress, Device, dev); EnumerateDevice(BusAddress, Device, dev);
} }
std::vector<PCIDevice> PCI::FindPCIDevice(uint8_t Class, uint8_t Subclass, uint8_t ProgIF) std::list<PCIDevice> Manager::FindPCIDevice(uint8_t Class, uint8_t Subclass, uint8_t ProgIF)
{ {
std::vector<PCIDevice> DeviceFound; std::list<PCIDevice> DeviceFound;
foreach (auto dev in Devices) foreach (auto dev in Devices)
{ {
if (dev.Header->Class == Class && if (dev.Header->Class == Class &&
@ -960,9 +1063,9 @@ namespace PCI
return DeviceFound; return DeviceFound;
} }
std::vector<PCIDevice> PCI::FindPCIDevice(int VendorID, int DeviceID) std::list<PCIDevice> Manager::FindPCIDevice(uint16_t VendorID, uint16_t DeviceID)
{ {
std::vector<PCIDevice> DeviceFound; std::list<PCIDevice> DeviceFound;
foreach (auto dev in Devices) foreach (auto dev in Devices)
{ {
if (dev.Header->VendorID == VendorID && if (dev.Header->VendorID == VendorID &&
@ -974,7 +1077,28 @@ namespace PCI
return DeviceFound; return DeviceFound;
} }
PCI::PCI() std::list<PCIDevice> Manager::FindPCIDevice(std::list<uint16_t> VendorIDs,
std::list<uint16_t> DeviceIDs)
{
std::list<PCIDevice> 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 defined(a86)
if (!PowerManager->GetACPI()) 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)); 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++) for (int t = 0; t < Entries; t++)
{ {
DeviceConfig *NewDeviceConfig = (DeviceConfig *)((uintptr_t)((ACPI::ACPI *)PowerManager->GetACPI())->MCFG + sizeof(ACPI::ACPI::MCFGHeader) + (sizeof(DeviceConfig) * 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 #endif
} }
PCI::~PCI() {} Manager::~Manager() {}
} }

View File

@ -32,15 +32,6 @@ namespace Power
if (((ACPI::DSDT *)this->dsdt)->ACPIShutdownSupported) if (((ACPI::DSDT *)this->dsdt)->ACPIShutdownSupported)
((ACPI::DSDT *)this->dsdt)->Reboot(); ((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"); asmv("cli");
uint8_t temp; uint8_t temp;
do do
@ -50,24 +41,24 @@ namespace Power
inb(0x60); inb(0x60);
} while (((temp) & (1 << (1))) != 0); } while (((temp) & (1 << (1))) != 0);
outb(0x64, 0xFE); outb(0x64, 0xFE);
CPU::Stop();
} }
void Power::Shutdown() void Power::Shutdown()
{ {
if (((ACPI::ACPI *)this->acpi)->FADT) if (((ACPI::ACPI *)this->acpi)->FADT)
{
if (((ACPI::DSDT *)this->dsdt)->ACPIShutdownSupported) if (((ACPI::DSDT *)this->dsdt)->ACPIShutdownSupported)
((ACPI::DSDT *)this->dsdt)->Shutdown(); ((ACPI::DSDT *)this->dsdt)->Shutdown();
/* TODO: If no ACPI, display "It is now safe to turn off your computer" */ 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 */ /* FIXME: Detect emulators and use their shutdown methods */
#ifdef DEBUG #ifdef DEBUG
outl(0xB004, 0x2000); // for qemu outl(0xB004, 0x2000); // for qemu
outl(0x604, 0x2000); // if qemu not working, bochs and older versions of qemu outl(0x604, 0x2000); // if qemu not working, bochs and older versions of qemu
outl(0x4004, 0x3400); // virtual box outl(0x4004, 0x3400); // virtual box
#endif #endif
CPU::Stop();
} }
void Power::InitDSDT() void Power::InitDSDT()

View File

@ -25,20 +25,69 @@
namespace SymbolResolver namespace SymbolResolver
{ {
const NIF char *Symbols::GetSymbolFromAddress(uintptr_t Address) const NIF char *Symbols::GetSymbol(uintptr_t Address)
{ {
SymbolTable Result{}; SymbolTable Result{};
foreach (auto tbl in this->SymTable)
if (this->SymbolTableExists == false)
{ {
if (tbl.Address <= Address && debug("Symbol table does not exist");
tbl.Address > Result.Address) if (this->SymTable.size() > 0)
Result = tbl; {
debug("SymbolTableExists is false but SymTable.size() is %d",
this->SymTable.size());
} }
// debug("Address: %#lx, Function: %s",
// Address, Result.FunctionName);
return Result.FunctionName; return Result.FunctionName;
} }
std::vector<SymbolTable> 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<SymbolTable> 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) void Symbols::AddSymbol(uintptr_t Address, const char *Name)
{ {
SymbolTable tbl{}; SymbolTable tbl{};
@ -121,11 +170,11 @@ namespace SymbolResolver
TotalEntries, TO_KiB(TotalEntries * sizeof(SymbolTable))); TotalEntries, TO_KiB(TotalEntries * sizeof(SymbolTable)));
Elf_Sym *sym; Elf_Sym *sym;
const char *name; const char *name;
Memory::Virtual vma = Memory::Virtual(); Memory::Virtual vmm;
for (size_t i = 0, g = TotalEntries; i < g; i++) for (size_t i = 0, g = TotalEntries; i < g; i++)
{ {
sym = &Symbols[i]; sym = &Symbols[i];
if (!vma.Check(sym)) if (!vmm.Check(sym))
{ {
error("Symbol %d has invalid address %#lx!", error("Symbol %d has invalid address %#lx!",
i, sym); i, sym);
@ -137,7 +186,7 @@ namespace SymbolResolver
} }
name = (const char *)&StringAddress[Symbols[i].st_name]; 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!", error("String %d has invalid address %#lx!",
i, name); i, name);
@ -168,7 +217,8 @@ namespace SymbolResolver
{ {
/* FIXME: Get only the required headers instead of the whole file */ /* 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); error("Invalid image address %#lx", ImageAddress);
return; return;
@ -261,17 +311,27 @@ namespace SymbolResolver
// this->SymTable[i].FunctionName); // 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) Symbols::Symbols(uintptr_t ImageAddress)
{ {
debug("+ %#lx", this);
this->Image = (void *)ImageAddress; this->Image = (void *)ImageAddress;
this->AppendSymbols(ImageAddress); this->AppendSymbols(ImageAddress);
} }
Symbols::~Symbols() 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; delete[] tbl.FunctionName;
} }
} }

View File

@ -29,13 +29,13 @@ namespace Time
bool HighPrecisionEventTimer::Sleep(size_t Duration, Units Unit) bool HighPrecisionEventTimer::Sleep(size_t Duration, Units Unit)
{ {
#if defined(a64) #if defined(a64)
uint64_t Target = mminq(&((HPET *)hpet)->MainCounterValue) + (Duration * ConvertUnit(Unit)) / clk; uint64_t Target = mminq(&hpet->MainCounterValue) + (Duration * ConvertUnit(Unit)) / clk;
while (mminq(&((HPET *)hpet)->MainCounterValue) < Target) while (mminq(&hpet->MainCounterValue) < Target)
CPU::Pause(); CPU::Pause();
return true; return true;
#elif defined(a32) #elif defined(a32)
uint64_t Target = mminl(&((HPET *)hpet)->MainCounterValue) + (Duration * ConvertUnit(Unit)) / clk; uint64_t Target = mminl(&hpet->MainCounterValue) + (Duration * ConvertUnit(Unit)) / clk;
while (mminl(&((HPET *)hpet)->MainCounterValue) < Target) while (mminl(&hpet->MainCounterValue) < Target)
CPU::Pause(); CPU::Pause();
return true; return true;
#endif #endif
@ -45,18 +45,18 @@ namespace Time
uint64_t HighPrecisionEventTimer::GetCounter() uint64_t HighPrecisionEventTimer::GetCounter()
{ {
#if defined(a64) #if defined(a64)
return mminq(&((HPET *)hpet)->MainCounterValue); return mminq(&hpet->MainCounterValue);
#elif defined(a32) #elif defined(a32)
return mminl(&((HPET *)hpet)->MainCounterValue); return mminl(&hpet->MainCounterValue);
#endif #endif
} }
uint64_t HighPrecisionEventTimer::CalculateTarget(uint64_t Target, Units Unit) uint64_t HighPrecisionEventTimer::CalculateTarget(uint64_t Target, Units Unit)
{ {
#if defined(a64) #if defined(a64)
return mminq(&((HPET *)hpet)->MainCounterValue) + (Target * ConvertUnit(Unit)) / clk; return mminq(&hpet->MainCounterValue) + (Target * ConvertUnit(Unit)) / clk;
#elif defined(a32) #elif defined(a32)
return mminl(&((HPET *)hpet)->MainCounterValue) + (Target * ConvertUnit(Unit)) / clk; return mminl(&hpet->MainCounterValue) + (Target * ConvertUnit(Unit)) / clk;
#endif #endif
} }
@ -66,7 +66,9 @@ namespace Time
uint64_t Subtraction = this->GetCounter() - this->ClassCreationTime; uint64_t Subtraction = this->GetCounter() - this->ClassCreationTime;
if (Subtraction <= 0 || this->clk <= 0) if (Subtraction <= 0 || this->clk <= 0)
return 0; return 0;
return uint64_t(Subtraction / (this->clk / ConvertUnit(Units::Nanoseconds)));
Subtraction *= ConvertUnit(Units::Nanoseconds);
return uint64_t(Subtraction / this->clk);
#endif #endif
} }
@ -74,13 +76,16 @@ namespace Time
{ {
#if defined(a86) #if defined(a86)
ACPI::ACPI::HPETHeader *HPET_HDR = (ACPI::ACPI::HPETHeader *)hpet; ACPI::ACPI::HPETHeader *HPET_HDR = (ACPI::ACPI::HPETHeader *)hpet;
Memory::Virtual().Map((void *)HPET_HDR->Address.Address, Memory::Virtual vmm;
vmm.Map((void *)HPET_HDR->Address.Address,
(void *)HPET_HDR->Address.Address, (void *)HPET_HDR->Address.Address,
Memory::PTFlag::RW | Memory::PTFlag::PCD); Memory::PTFlag::RW | Memory::PTFlag::PCD);
this->hpet = (HPET *)HPET_HDR->Address.Address; 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); 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 #ifdef a64
mmoutq(&this->hpet->GeneralConfiguration, 0); mmoutq(&this->hpet->GeneralConfiguration, 0);
mmoutq(&this->hpet->MainCounterValue, 0); mmoutq(&this->hpet->MainCounterValue, 0);

View File

@ -60,7 +60,7 @@ namespace Time
TimeStampCounter::TimeStampCounter() TimeStampCounter::TimeStampCounter()
{ {
#if defined(a86) #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(); uint64_t Start = CPU::Counter();
TimeManager->Sleep(1, Units::Milliseconds); TimeManager->Sleep(1, Units::Milliseconds);
uint64_t End = CPU::Counter(); uint64_t End = CPU::Counter();

326
driver.h Normal file
View File

@ -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 <https://www.gnu.org/licenses/>.
*/
#ifndef __FENNIX_API_DRIVER_FUNCTIONS_H__
#define __FENNIX_API_DRIVER_FUNCTIONS_H__
#include <types.h>
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__

View File

@ -19,49 +19,31 @@
#include <msexec.h> #include <msexec.h>
#include "../kernel.h"
#include "../Fex.hpp"
namespace Execute namespace Execute
{ {
BinaryType GetBinaryType(const char *Path) BinaryType GetBinaryType(const char *Path)
{ {
debug("Checking binary type of %s(ptr: %#lx)",
Path, Path);
BinaryType Type; BinaryType Type;
int fd = fopen(Path, "r"); int fd = fopen(Path, "r");
if (fd < 0) if (fd < 0)
{
debug("Failed to open file %s: %s",
Path, strerror(fd));
return (BinaryType)fd; return (BinaryType)fd;
}
debug("File opened: %s, descriptor %d", Path, fd); debug("File opened: %s, descriptor %d", Path, fd);
Memory::SmartHeap sh = Memory::SmartHeap(1024); Memory::SmartHeap sh = Memory::SmartHeap(1024);
fread(fd, sh, 128); fread(fd, sh, 128);
Fex *FexHdr = (Fex *)sh.Get();
Elf32_Ehdr *ELFHeader = (Elf32_Ehdr *)sh.Get(); Elf32_Ehdr *ELFHeader = (Elf32_Ehdr *)sh.Get();
IMAGE_DOS_HEADER *MZHeader = (IMAGE_DOS_HEADER *)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. */ /* Check ELF header. */
else if (ELFHeader->e_ident[EI_MAG0] == ELFMAG0 && if (ELFHeader->e_ident[EI_MAG0] == ELFMAG0 &&
ELFHeader->e_ident[EI_MAG1] == ELFMAG1 && ELFHeader->e_ident[EI_MAG1] == ELFMAG1 &&
ELFHeader->e_ident[EI_MAG2] == ELFMAG2 && ELFHeader->e_ident[EI_MAG2] == ELFMAG2 &&
ELFHeader->e_ident[EI_MAG3] == ELFMAG3) ELFHeader->e_ident[EI_MAG3] == ELFMAG3)

View File

@ -26,7 +26,6 @@
#include <abi.h> #include <abi.h>
#include "../../kernel.h" #include "../../kernel.h"
#include "../../Fex.hpp"
using namespace Tasking; using namespace Tasking;
using namespace vfs; using namespace vfs;
@ -162,8 +161,9 @@ namespace Execute
uintptr_t EntryPoint = ELFHeader.e_entry; uintptr_t EntryPoint = ELFHeader.e_entry;
debug("Entry point is %#lx", EntryPoint); debug("Entry point is %#lx", EntryPoint);
Memory::Virtual vmm = Memory::Virtual(TargetProcess->PageTable); Memory::Virtual vmm(TargetProcess->PageTable);
Memory::VirtualMemoryArea *vma = TargetProcess->vma; Memory::VirtualMemoryArea *vma = TargetProcess->vma;
debug("Target process page table is %#lx", TargetProcess->PageTable);
LoadPhdrs_x86_64(fd, ELFHeader, vma, TargetProcess); LoadPhdrs_x86_64(fd, ELFHeader, vma, TargetProcess);
@ -188,9 +188,10 @@ namespace Execute
vmm.Map(vAddr, pAddr, vmm.Map(vAddr, pAddr,
ProgramHeader.p_memsz, 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("Segment Offset is %#lx", SegDestOffset);
debug("Copying segment to p: %#lx-%#lx; v: %#lx-%#lx (%ld file bytes, %ld mem bytes)", 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) 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); lseek(fd, ProgramHeader.p_offset, SEEK_SET);
fread(fd, (uint8_t *)pAddr + SegDestOffset, ProgramHeader.p_filesz); fread(fd, (uint8_t *)pAddr + SegDestOffset, ProgramHeader.p_filesz);
} }
@ -209,11 +212,100 @@ namespace Execute
if (ProgramHeader.p_memsz - ProgramHeader.p_filesz > 0) if (ProgramHeader.p_memsz - ProgramHeader.p_filesz > 0)
{ {
void *zAddr = (void *)(uintptr_t(pAddr) + SegDestOffset + ProgramHeader.p_filesz); 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); memset(zAddr, 0, ProgramHeader.p_memsz - ProgramHeader.p_filesz);
} }
ProgramBreakHeader = ProgramHeader; ProgramBreakHeader = ProgramHeader;
break; 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: default:
{ {
fixme("Unhandled program header type: %#lx", fixme("Unhandled program header type: %#lx",
@ -238,6 +330,11 @@ namespace Execute
fread(fd, sh, statbuf.st_size); fread(fd, sh, statbuf.st_size);
TargetProcess->ELFSymbolTable->AppendSymbols(uintptr_t(sh.Get())); TargetProcess->ELFSymbolTable->AppendSymbols(uintptr_t(sh.Get()));
#ifdef DEBUG
if (!TargetProcess->ELFSymbolTable->SymTableExists)
debug("NO SYMBOL TABLE FOUND?");
#endif
debug("Entry Point: %#lx", EntryPoint); debug("Entry Point: %#lx", EntryPoint);
this->GenerateAuxiliaryVector_x86_64(vma, fd, ELFHeader, this->GenerateAuxiliaryVector_x86_64(vma, fd, ELFHeader,
@ -299,7 +396,7 @@ namespace Execute
uintptr_t EntryPoint = ELFHeader.e_entry; uintptr_t EntryPoint = ELFHeader.e_entry;
debug("Entry point is %#lx", EntryPoint); debug("Entry point is %#lx", EntryPoint);
Memory::Virtual vmm = Memory::Virtual(TargetProcess->PageTable); Memory::Virtual vmm(TargetProcess->PageTable);
Memory::VirtualMemoryArea *vma = TargetProcess->vma; Memory::VirtualMemoryArea *vma = TargetProcess->vma;
uintptr_t BaseAddress = 0; uintptr_t BaseAddress = 0;
@ -396,6 +493,26 @@ namespace Execute
} }
break; 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: default:
{ {
fixme("Unhandled program header type: %#lx", fixme("Unhandled program header type: %#lx",
@ -417,240 +534,209 @@ namespace Execute
EntryPoint += BaseAddress; EntryPoint += BaseAddress;
debug("The new ep is %#lx", EntryPoint); debug("The new ep is %#lx", EntryPoint);
std::vector<Elf64_Dyn> JmpRel = ELFGetDynamicTag_x86_64(fd, DT_JMPREL); // std::vector<Elf64_Dyn> JmpRel = ELFGetDynamicTag_x86_64(fd, DT_JMPREL);
std::vector<Elf64_Dyn> SymTab = ELFGetDynamicTag_x86_64(fd, DT_SYMTAB); // std::vector<Elf64_Dyn> SymTab = ELFGetDynamicTag_x86_64(fd, DT_SYMTAB);
std::vector<Elf64_Dyn> StrTab = ELFGetDynamicTag_x86_64(fd, DT_STRTAB); // std::vector<Elf64_Dyn> StrTab = ELFGetDynamicTag_x86_64(fd, DT_STRTAB);
std::vector<Elf64_Dyn> RelaDyn = ELFGetDynamicTag_x86_64(fd, DT_RELA); // std::vector<Elf64_Dyn> RelaDyn = ELFGetDynamicTag_x86_64(fd, DT_RELA);
std::vector<Elf64_Dyn> RelaDynSize = ELFGetDynamicTag_x86_64(fd, DT_RELASZ); // std::vector<Elf64_Dyn> RelaDynSize = ELFGetDynamicTag_x86_64(fd, DT_RELASZ);
// size_t JmpRelSize = JmpRel.size();
size_t JmpRelSize = JmpRel.size(); // size_t SymTabSize = SymTab.size();
size_t SymTabSize = SymTab.size(); // size_t StrTabSize = StrTab.size();
size_t StrTabSize = StrTab.size(); // size_t RelaDynSize_v = RelaDyn.size();
size_t RelaDynSize_v = RelaDyn.size(); // if (JmpRelSize < 1)
// {
if (JmpRelSize < 1) // debug("No DT_JMPREL");
{ // }
debug("No DT_JMPREL"); // if (SymTabSize < 1)
} // {
// debug("No DT_SYMTAB");
if (SymTabSize < 1) // }
{ // if (StrTabSize < 1)
debug("No DT_SYMTAB"); // {
} // debug("No DT_STRTAB");
// }
if (StrTabSize < 1) // if (RelaDynSize_v < 1)
{ // {
debug("No DT_STRTAB"); // debug("No DT_RELA");
} // }
// if (RelaDynSize[0].d_un.d_val < 1)
if (RelaDynSize_v < 1) // {
{ // debug("DT_RELASZ is < 1");
debug("No DT_RELA"); // }
} // if (JmpRelSize > 0 && SymTabSize > 0 && StrTabSize > 0)
// {
if (RelaDynSize[0].d_un.d_val < 1) // debug("JmpRel: %#lx, SymTab: %#lx, StrTab: %#lx",
{ // JmpRel[0].d_un.d_ptr, SymTab[0].d_un.d_ptr,
debug("DT_RELASZ is < 1"); // 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);
if (JmpRelSize > 0 && SymTabSize > 0 && StrTabSize > 0) // 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);
debug("JmpRel: %#lx, SymTab: %#lx, StrTab: %#lx", // Elf64_Shdr shdr;
JmpRel[0].d_un.d_ptr, SymTab[0].d_un.d_ptr, // for (Elf64_Half i = 0; i < ELFHeader.e_shnum; i++)
StrTab[0].d_un.d_ptr); // {
// lseek(fd, ELFHeader.e_shoff + i * sizeof(Elf64_Shdr), SEEK_SET);
Elf64_Rela *_JmpRel = (Elf64_Rela *)((uintptr_t)BaseAddress + JmpRel[0].d_un.d_ptr); // fread(fd, (uint8_t *)&shdr, sizeof(Elf64_Shdr));
Elf64_Sym *_SymTab = (Elf64_Sym *)((uintptr_t)BaseAddress + SymTab[0].d_un.d_ptr); // char sectionName[32];
char *_DynStr = (char *)((uintptr_t)BaseAddress + StrTab[0].d_un.d_ptr); // Elf64_Shdr n_shdr;
Elf64_Rela *_RelaDyn = (Elf64_Rela *)((uintptr_t)BaseAddress + RelaDyn[0].d_un.d_ptr); // lseek(fd, ELFHeader.e_shoff + ELFHeader.e_shstrndx * sizeof(Elf64_Shdr), SEEK_SET);
// fread(fd, (uint8_t *)&n_shdr, sizeof(Elf64_Shdr));
Elf64_Shdr shdr; // lseek(fd, n_shdr.sh_offset + shdr.sh_name, SEEK_SET);
for (Elf64_Half i = 0; i < ELFHeader.e_shnum; i++) // fread(fd, (uint8_t *)sectionName, 32);
{ // debug("shdr: %s", sectionName);
lseek(fd, ELFHeader.e_shoff + i * sizeof(Elf64_Shdr), SEEK_SET); // if (strcmp(sectionName, ".rela.plt") == 0)
fread(fd, (uint8_t *)&shdr, sizeof(Elf64_Shdr)); // {
// // .rela.plt
char sectionName[32]; // // R_X86_64_JUMP_SLOT
Elf64_Shdr n_shdr; // Elf64_Xword numEntries = shdr.sh_size / shdr.sh_entsize;
lseek(fd, ELFHeader.e_shoff + ELFHeader.e_shstrndx * sizeof(Elf64_Shdr), SEEK_SET); // for (Elf64_Xword i = 0; i < numEntries; i++)
fread(fd, (uint8_t *)&n_shdr, sizeof(Elf64_Shdr)); // {
lseek(fd, n_shdr.sh_offset + shdr.sh_name, SEEK_SET); // Elf64_Addr *GOTEntry = (Elf64_Addr *)(shdr.sh_addr +
fread(fd, (uint8_t *)sectionName, 32); // BaseAddress +
debug("shdr: %s", sectionName); // i * sizeof(Elf64_Addr));
// Elf64_Rela *Rel = _JmpRel + i;
if (strcmp(sectionName, ".rela.plt") == 0) // Elf64_Xword RelType = ELF64_R_TYPE(Rel->r_info);
{ // switch (RelType)
// .rela.plt // {
// R_X86_64_JUMP_SLOT // case R_X86_64_JUMP_SLOT:
Elf64_Xword numEntries = shdr.sh_size / shdr.sh_entsize; // {
for (Elf64_Xword i = 0; i < numEntries; i++) // Elf64_Xword SymIndex = ELF64_R_SYM(Rel->r_info);
{ // Elf64_Sym *Sym = _SymTab + SymIndex;
Elf64_Addr *GOTEntry = (Elf64_Addr *)(shdr.sh_addr + // if (Sym->st_name)
BaseAddress + // {
i * sizeof(Elf64_Addr)); // char *SymName = _DynStr + Sym->st_name;
Elf64_Rela *Rel = _JmpRel + i; // debug("SymName: %s", SymName);
Elf64_Xword RelType = ELF64_R_TYPE(Rel->r_info); // Elf64_Sym LibSym = ELFLookupSymbol(fd, SymName);
// if (LibSym.st_value)
switch (RelType) // {
{ // *GOTEntry = (Elf64_Addr)(BaseAddress + LibSym.st_value);
case R_X86_64_JUMP_SLOT: // debug("GOT[%ld](%#lx): %#lx",
{ // i, uintptr_t(GOTEntry) - BaseAddress,
Elf64_Xword SymIndex = ELF64_R_SYM(Rel->r_info); // *GOTEntry);
Elf64_Sym *Sym = _SymTab + SymIndex; // }
// }
if (Sym->st_name) // continue;
{ // }
char *SymName = _DynStr + Sym->st_name; // default:
debug("SymName: %s", SymName); // {
// fixme("Unhandled relocation type: %#lx", RelType);
Elf64_Sym LibSym = ELFLookupSymbol(fd, SymName); // break;
if (LibSym.st_value) // }
{ // }
*GOTEntry = (Elf64_Addr)(BaseAddress + LibSym.st_value); // }
debug("GOT[%ld](%#lx): %#lx", // }
i, uintptr_t(GOTEntry) - BaseAddress, // else if (strcmp(sectionName, ".rela.dyn") == 0)
*GOTEntry); // {
} // // .rela.dyn
} // // R_X86_64_RELATIVE
continue; // // R_X86_64_GLOB_DAT
} // if (RelaDynSize_v < 1 || RelaDynSize[0].d_un.d_val < 1)
default: // continue;
{ // Elf64_Xword numRelaDynEntries = RelaDynSize[0].d_un.d_val / sizeof(Elf64_Rela);
fixme("Unhandled relocation type: %#lx", RelType); // for (Elf64_Xword i = 0; i < numRelaDynEntries; i++)
break; // {
} // 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)
else if (strcmp(sectionName, ".rela.dyn") == 0) // {
{ // case R_X86_64_RELATIVE:
// .rela.dyn // {
// R_X86_64_RELATIVE // *GOTEntry = (Elf64_Addr)(BaseAddress + Rel->r_addend);
// R_X86_64_GLOB_DAT // debug("GOT[%ld](%#lx): %#lx (R_X86_64_RELATIVE)",
if (RelaDynSize_v < 1 || RelaDynSize[0].d_un.d_val < 1) // i, uintptr_t(GOTEntry) - BaseAddress,
continue; // *GOTEntry);
Elf64_Xword numRelaDynEntries = RelaDynSize[0].d_un.d_val / sizeof(Elf64_Rela); // break;
for (Elf64_Xword i = 0; i < numRelaDynEntries; i++) // }
{ // case R_X86_64_GLOB_DAT:
Elf64_Rela *Rel = _RelaDyn + i; // {
Elf64_Addr *GOTEntry = (Elf64_Addr *)(Rel->r_offset + BaseAddress); // Elf64_Xword SymIndex = ELF64_R_SYM(Rel->r_info);
Elf64_Xword RelType = ELF64_R_TYPE(Rel->r_info); // Elf64_Sym *Sym = _SymTab + SymIndex;
// if (Sym->st_name)
switch (RelType) // {
{ // char *SymName = _DynStr + Sym->st_name;
case R_X86_64_RELATIVE: // debug("SymName: %s", SymName);
{ // Elf64_Sym LibSym = ELFLookupSymbol(fd, SymName);
*GOTEntry = (Elf64_Addr)(BaseAddress + Rel->r_addend); // if (LibSym.st_value)
debug("GOT[%ld](%#lx): %#lx (R_X86_64_RELATIVE)", // {
i, uintptr_t(GOTEntry) - BaseAddress, // *GOTEntry = (Elf64_Addr)(BaseAddress + LibSym.st_value);
*GOTEntry); // debug("GOT[%ld](%#lx): %#lx (R_X86_64_GLOB_DAT)",
break; // i, uintptr_t(GOTEntry) - BaseAddress,
} // *GOTEntry);
case R_X86_64_GLOB_DAT: // }
{ // }
Elf64_Xword SymIndex = ELF64_R_SYM(Rel->r_info); // break;
Elf64_Sym *Sym = _SymTab + SymIndex; // }
// default:
if (Sym->st_name) // {
{ // fixme("Unhandled relocation type: %#lx", RelType);
char *SymName = _DynStr + Sym->st_name; // break;
debug("SymName: %s", SymName); // }
// }
Elf64_Sym LibSym = ELFLookupSymbol(fd, SymName); // }
if (LibSym.st_value) // }
{ // else if (strcmp(sectionName, ".dynsym") == 0)
*GOTEntry = (Elf64_Addr)(BaseAddress + LibSym.st_value); // {
debug("GOT[%ld](%#lx): %#lx (R_X86_64_GLOB_DAT)", // // .dynsym
i, uintptr_t(GOTEntry) - BaseAddress, // // STT_OBJECT
*GOTEntry); // 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",
break; // SymArray, shdr.sh_addr, numEntries);
} // for (Elf64_Xword j = 0; j < numEntries; j++)
default: // {
{ // Elf64_Sym Sym = SymArray[j];
fixme("Unhandled relocation type: %#lx", RelType); // if (Sym.st_shndx == SHN_UNDEF)
break; // continue;
} // if (Sym.st_value == 0)
} // continue;
} // unsigned char SymType = ELF64_ST_TYPE(Sym.st_info);
} // if (SymType == STT_OBJECT)
else if (strcmp(sectionName, ".dynsym") == 0) // {
{ // Elf64_Addr *GOTEntry = (Elf64_Addr *)(Sym.st_value + BaseAddress);
// .dynsym // *GOTEntry = (Elf64_Addr)(BaseAddress + Sym.st_value);
// STT_OBJECT // debug("%ld: \"%s\" %#lx -> %#lx", j,
// _DynStr + Sym.st_name,
Elf64_Sym *SymArray = (Elf64_Sym *)(shdr.sh_addr + BaseAddress); // uintptr_t(GOTEntry) - BaseAddress,
Elf64_Xword numEntries = shdr.sh_size / shdr.sh_entsize; // *GOTEntry);
debug("start %#lx (off %#lx), entries %ld", // }
SymArray, shdr.sh_addr, numEntries); // }
for (Elf64_Xword j = 0; j < numEntries; j++) // }
{ // else if (strcmp(sectionName, ".symtab") == 0)
Elf64_Sym Sym = SymArray[j]; // {
// // .symtab
if (Sym.st_shndx == SHN_UNDEF) // // STT_OBJECT
continue; // Elf64_Xword numEntries = shdr.sh_size / shdr.sh_entsize;
// Elf64_Sym *SymArray = new Elf64_Sym[numEntries];
if (Sym.st_value == 0) // lseek(fd, shdr.sh_offset, SEEK_SET);
continue; // fread(fd, (uint8_t *)SymArray, shdr.sh_size);
// debug("start %#lx (off %#lx), entries %ld",
unsigned char SymType = ELF64_ST_TYPE(Sym.st_info); // SymArray, shdr.sh_addr, numEntries);
// for (Elf64_Xword j = 0; j < numEntries; j++)
if (SymType == STT_OBJECT) // {
{ // Elf64_Sym Sym = SymArray[j];
Elf64_Addr *GOTEntry = (Elf64_Addr *)(Sym.st_value + BaseAddress); // if (Sym.st_shndx == SHN_UNDEF)
*GOTEntry = (Elf64_Addr)(BaseAddress + Sym.st_value); // continue;
// if (Sym.st_value == 0)
debug("%ld: \"%s\" %#lx -> %#lx", j, // continue;
_DynStr + Sym.st_name, // unsigned char SymType = ELF64_ST_TYPE(Sym.st_info);
uintptr_t(GOTEntry) - BaseAddress, // if (SymType == STT_OBJECT)
*GOTEntry); // {
} // Elf64_Addr *GOTEntry = (Elf64_Addr *)(Sym.st_value + BaseAddress);
} // *GOTEntry = (Elf64_Addr)(BaseAddress + Sym.st_value);
} // debug("%ld: \"<fixme>\" %#lx -> %#lx", j,
else if (strcmp(sectionName, ".symtab") == 0) // /*_DynStr + Sym.st_name,*/
{ // uintptr_t(GOTEntry) - BaseAddress,
// .symtab // *GOTEntry);
// STT_OBJECT // }
// }
Elf64_Xword numEntries = shdr.sh_size / shdr.sh_entsize; // delete[] SymArray;
Elf64_Sym *SymArray = new Elf64_Sym[numEntries]; // }
lseek(fd, shdr.sh_offset, SEEK_SET); // // if (shdr.sh_type == SHT_PROGBITS &&
fread(fd, (uint8_t *)SymArray, shdr.sh_size); // // (shdr.sh_flags & SHF_WRITE) &&
// // (shdr.sh_flags & SHF_ALLOC))
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: \"<fixme>\" %#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); fread(fd, sh, statbuf.st_size);
TargetProcess->ELFSymbolTable->AppendSymbols(uintptr_t(sh.Get()), BaseAddress); TargetProcess->ELFSymbolTable->AppendSymbols(uintptr_t(sh.Get()), BaseAddress);
if (!TargetProcess->ELFSymbolTable->SymTableExists)
{
debug("NO SYMBOL TABLE FOUND?");
}
debug("Entry Point: %#lx", EntryPoint); debug("Entry Point: %#lx", EntryPoint);
this->GenerateAuxiliaryVector_x86_64(vma, fd, ELFHeader, this->GenerateAuxiliaryVector_x86_64(vma, fd, ELFHeader,
@ -759,6 +850,7 @@ namespace Execute
error("Failed to open %s, errno: %d", AbsolutePath, fd); error("Failed to open %s, errno: %d", AbsolutePath, fd);
return; return;
} }
debug("Opened %s", AbsolutePath);
int argc = 0; int argc = 0;
int envc = 0; int envc = 0;
@ -769,23 +861,23 @@ namespace Execute
envc++; envc++;
// ELFargv = new const char *[argc + 2]; // ELFargv = new const char *[argc + 2];
size_t argv_size = TO_PAGES(argc + 2 * sizeof(char *)); size_t argv_size = argc + 2 * sizeof(char *);
ELFargv = (const char **)TargetProcess->vma->RequestPages(argv_size); ELFargv = (const char **)TargetProcess->vma->RequestPages(TO_PAGES(argv_size));
for (int i = 0; i < argc; i++) for (int i = 0; i < argc; i++)
{ {
size_t arg_size = TO_PAGES(strlen(argv[i]) + 1); size_t arg_size = strlen(argv[i]) + 1;
ELFargv[i] = (const char *)TargetProcess->vma->RequestPages(arg_size); ELFargv[i] = (const char *)TargetProcess->vma->RequestPages(TO_PAGES(arg_size));
strcpy((char *)ELFargv[i], argv[i]); strcpy((char *)ELFargv[i], argv[i]);
} }
ELFargv[argc] = nullptr; ELFargv[argc] = nullptr;
// ELFenvp = new const char *[envc + 1]; // ELFenvp = new const char *[envc + 1];
size_t envp_size = TO_PAGES(envc + 1 * sizeof(char *)); size_t envp_size = envc + 1 * sizeof(char *);
ELFenvp = (const char **)TargetProcess->vma->RequestPages(envp_size); ELFenvp = (const char **)TargetProcess->vma->RequestPages(TO_PAGES(envp_size));
for (int i = 0; i < envc; i++) for (int i = 0; i < envc; i++)
{ {
size_t env_size = TO_PAGES(strlen(envp[i]) + 1); size_t env_size = strlen(envp[i]) + 1;
ELFenvp[i] = (const char *)TargetProcess->vma->RequestPages(env_size); ELFenvp[i] = (const char *)TargetProcess->vma->RequestPages(TO_PAGES(env_size));
strcpy((char *)ELFenvp[i], envp[i]); strcpy((char *)ELFenvp[i], envp[i]);
} }
ELFenvp[envc] = nullptr; ELFenvp[envc] = nullptr;

View File

@ -20,7 +20,6 @@
#include <msexec.h> #include <msexec.h>
#include "../../kernel.h" #include "../../kernel.h"
#include "../../Fex.hpp"
namespace Execute namespace Execute
{ {

View File

@ -20,7 +20,6 @@
#include <msexec.h> #include <msexec.h>
#include "../../kernel.h" #include "../../kernel.h"
#include "../../Fex.hpp"
namespace Execute namespace Execute
{ {

View File

@ -25,14 +25,13 @@
#include <abi.h> #include <abi.h>
#include "../kernel.h" #include "../kernel.h"
#include "../Fex.hpp"
using namespace Tasking; using namespace Tasking;
namespace Execute namespace Execute
{ {
int Spawn(char *Path, const char **argv, const char **envp, int Spawn(char *Path, const char **argv, const char **envp,
Tasking::PCB *Parent, Tasking::PCB *Parent, bool Fork,
Tasking::TaskCompatibility Compatibility, Tasking::TaskCompatibility Compatibility,
bool Critical) bool Critical)
{ {
@ -50,19 +49,6 @@ namespace Execute
switch (GetBinaryType(Path)) 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: case BinaryType::BinTypeELF:
{ {
TaskArchitecture Arch = TaskArchitecture::UnknownArchitecture; TaskArchitecture Arch = TaskArchitecture::UnknownArchitecture;
@ -118,20 +104,44 @@ namespace Execute
debug("Loaded elf %s at %#lx with the length of %ld", debug("Loaded elf %s at %#lx with the length of %ld",
Path, ElfFile, statbuf.st_size); Path, ElfFile, statbuf.st_size);
PCB *Process;
if (Fork)
{
assert(Parent != nullptr);
CriticalSection cs;
Process = Parent;
foreach (auto tcb in Process->Threads)
{
debug("Deleting thread %d", tcb->ID);
// delete tcb;
tcb->SetState(Tasking::Terminated);
}
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) if (Parent == nullptr)
Parent = thisProcess; Parent = thisProcess;
PCB *Process = TaskManager->CreateProcess(Parent, Process = TaskManager->CreateProcess(Parent,
BaseName, BaseName,
TaskExecutionMode::User, TaskExecutionMode::User,
ElfFile, false, ElfFile, false,
0, 0); 0, 0);
Process->Info.Compatibility = Compatibility;
KernelAllocator.FreePages(ElfFile, TO_PAGES(statbuf.st_size + 1)); Process->Info.Architecture = Arch;
}
Process->SetWorkingDirectory(fs->GetNodeFromPath(Path)->Parent); Process->SetWorkingDirectory(fs->GetNodeFromPath(Path)->Parent);
Process->Info.Compatibility = TaskCompatibility::Native; Process->SetExe(Path);
Process->Info.Architecture = TaskArchitecture::x64;
KernelAllocator.FreePages(ElfFile, TO_PAGES(statbuf.st_size + 1));
ELFObject *obj = new ELFObject(Path, Process, argv, envp); ELFObject *obj = new ELFObject(Path, Process, argv, envp);
if (!obj->IsValid) if (!obj->IsValid)
@ -142,14 +152,40 @@ namespace Execute
return -ENOEXEC; return -ENOEXEC;
} }
/* FIXME: implement stdio fildes */ vfs::FileDescriptorTable *pfdt = Parent->FileDescriptors;
vfs::FileDescriptorTable *fdt = Process->FileDescriptors; vfs::FileDescriptorTable *fdt = Process->FileDescriptors;
// stdin
fdt->_open("/dev/tty", O_RDWR, 0666); auto ForkStdio = [pfdt, fdt](Node *SearchNode)
// stdout {
fdt->_open("/dev/tty", O_RDWR, 0666); if (unlikely(SearchNode == nullptr))
// stderr return false;
fdt->_open("/dev/tty", O_RDWR, 0666);
std::vector<FileDescriptorTable::Fildes>
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; TCB *Thread = nullptr;
{ {

View File

@ -20,6 +20,7 @@
#include <types.h> #include <types.h>
#include <unordered_map>
#include <boot/binfo.h> #include <boot/binfo.h>
#include <ints.hpp> #include <ints.hpp>
#include <cpu.hpp> #include <cpu.hpp>
@ -52,6 +53,66 @@ namespace ACPI
uint64_t Address; uint64_t Address;
} __packed; } __packed;
enum DBG2PortType
{
TYPE_SERIAL = 0x8000,
TYPE_1394 = 0x8001,
TYPE_USB = 0x8002,
TYPE_NET = 0x8003
};
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,
SUBTYPE_1394_IEEE1394_HCI = 0x0000,
SUBTYPE_USB_XHCI = 0x0000,
SUBTYPE_USB_EHCI = 0x0001,
SUBTYPE_NET_NNNN = 0x0000,
};
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 MCFGHeader struct MCFGHeader
{ {
struct ACPIHeader Header; struct ACPIHeader Header;
@ -138,14 +199,14 @@ namespace ACPI
uint64_t ImageAddress; uint64_t ImageAddress;
uint32_t ImageOffsetX; uint32_t ImageOffsetX;
uint32_t ImageOffsetY; uint32_t ImageOffsetY;
}; } __packed;
struct SRATHeader struct SRATHeader
{ {
ACPIHeader Header; ACPIHeader Header;
uint32_t TableRevision; // Must be value 1 uint32_t TableRevision; // Must be value 1
uint64_t Reserved; // Reserved, must be zero uint64_t Reserved; // Reserved, must be zero
}; } __packed;
struct TPM2Header struct TPM2Header
{ {
@ -153,7 +214,7 @@ namespace ACPI
uint32_t Flags; uint32_t Flags;
uint64_t ControlAddress; uint64_t ControlAddress;
uint32_t StartMethod; uint32_t StartMethod;
}; } __packed;
struct TCPAHeader struct TCPAHeader
{ {
@ -161,19 +222,19 @@ namespace ACPI
uint16_t Reserved; uint16_t Reserved;
uint32_t MaxLogLength; uint32_t MaxLogLength;
uint64_t LogAddress; uint64_t LogAddress;
}; } __packed;
struct WAETHeader struct WAETHeader
{ {
ACPIHeader Header; ACPIHeader Header;
uint32_t Flags; uint32_t Flags;
}; } __packed;
struct HESTHeader struct HESTHeader
{ {
ACPIHeader Header; ACPIHeader Header;
uint32_t ErrorSourceCount; uint32_t ErrorSourceCount;
}; } __packed;
struct MADTHeader struct MADTHeader
{ {
@ -183,6 +244,32 @@ namespace ACPI
char Entries[]; char Entries[];
} __packed; } __packed;
struct SSDTHeader
{
ACPIHeader Header;
char DefinitionBlock[];
} __packed;
struct DBGPHeader
{
ACPIHeader Header;
/**
* 0 - 16550 compatible
* 1 - Subset of 16550
*/
uint8_t InterfaceType;
uint8_t Reserved[3];
GenericAddressStructure BaseAddress;
} __packed;
struct DBG2Header
{
ACPIHeader Header;
uint32_t OffsetDbgDeviceInfo;
uint32_t NumberDbgDeviceInfo;
/* DBG2Device[NumberDbgDeviceInfo] at offset OffsetDbgDeviceInfo */
} __packed;
ACPIHeader *XSDT = nullptr; ACPIHeader *XSDT = nullptr;
MCFGHeader *MCFG = nullptr; MCFGHeader *MCFG = nullptr;
HPETHeader *HPET = nullptr; HPETHeader *HPET = nullptr;
@ -194,8 +281,13 @@ namespace ACPI
WAETHeader *WAET = nullptr; WAETHeader *WAET = nullptr;
MADTHeader *MADT = nullptr; MADTHeader *MADT = nullptr;
HESTHeader *HEST = nullptr; HESTHeader *HEST = nullptr;
SSDTHeader *SSDT = nullptr;
DBGPHeader *DBGP = nullptr;
DBG2Header *DBG2 = nullptr;
bool XSDTSupported = false; bool XSDTSupported = false;
std::unordered_map<const char *, ACPIHeader *> Tables;
void *FindTable(ACPIHeader *ACPIHeader, char *Signature); void *FindTable(ACPIHeader *ACPIHeader, char *Signature);
void SearchTables(ACPIHeader *Header); void SearchTables(ACPIHeader *Header);
ACPI(); ACPI();
@ -278,11 +370,7 @@ namespace ACPI
uint8_t PM1_CNT_LEN = 0; uint8_t PM1_CNT_LEN = 0;
ACPI *acpi; ACPI *acpi;
#if defined(a64) void OnInterruptReceived(CPU::TrapFrame *Frame);
void OnInterruptReceived(CPU::x64::TrapFrame *Frame);
#elif defined(a32)
void OnInterruptReceived(CPU::x32::TrapFrame *Frame);
#endif
public: public:
bool ACPIShutdownSupported = false; bool ACPIShutdownSupported = false;

View File

@ -38,7 +38,7 @@
/* Alignment of the multiboot info structure. */ /* Alignment of the multiboot info structure. */
#define MULTIBOOT_INFO_ALIGN 0x00000004 #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. */ /* Align all boot modules on i386 page (4KB) boundaries. */
#define MULTIBOOT_PAGE_ALIGN 0x00000001 #define MULTIBOOT_PAGE_ALIGN 0x00000001
@ -52,7 +52,7 @@
/* This flag indicates the use of the address fields in the header. */ /* This flag indicates the use of the address fields in the header. */
#define MULTIBOOT_AOUT_KLUDGE 0x00010000 #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? */ /* is there basic lower/upper memory information? */
#define MULTIBOOT_INFO_MEMORY 0x00000001 #define MULTIBOOT_INFO_MEMORY 0x00000001
@ -243,7 +243,7 @@ typedef struct multiboot_mmap_entry multiboot_memory_map_t;
struct multiboot_mod_list 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_start;
multiboot_uint32_t mod_end; multiboot_uint32_t mod_end;

View File

@ -84,6 +84,15 @@ extern "C"
void *memmove_sse4_1(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_sse4_2(void *dest, const void *src, size_t n);
long unsigned __strlen(const char s[]);
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[]); long unsigned strlen(const char s[]);
int strncmp(const char *s1, const char *s2, unsigned long n); int strncmp(const char *s1, const char *s2, unsigned long n);
char *strcat_unsafe(char *destination, const char *source); char *strcat_unsafe(char *destination, const char *source);
@ -94,7 +103,7 @@ extern "C"
char *strdup(const char *String); char *strdup(const char *String);
char *strchr(const char *String, int Char); char *strchr(const char *String, int Char);
char *strrchr(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 strncasecmp(const char *string1, const char *string2, size_t count);
int strcasecmp(const char *s1, const char *s2); int strcasecmp(const char *s1, const char *s2);
char *strtok(char *src, const char *delim); char *strtok(char *src, const char *delim);
long int strtol(const char *str, char **endptr, int base); long int strtol(const char *str, char **endptr, int base);

View File

@ -161,7 +161,7 @@ namespace CPU
"cli\n" "cli\n"
"hlt\n" "hlt\n"
"jmp CPUStopLoop"); "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() SafeFunction __used inline void Stop()
{ {
asmv("CPUStopLoop:\n" asmv("CPUStopLoop:\n"
@ -198,10 +198,13 @@ namespace CPU
* @brief Get/Set the CPU's page table * @brief Get/Set the CPU's page table
* *
* @param PT The new page table, if empty, the current page table will be returned * @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); void *PageTable(void *PT = nullptr);
#define thisPageTable (Memory::PageTable *)CPU::PageTable()
/** @brief To be used only once. */ /** @brief To be used only once. */
void InitializeFeatures(int Core); void InitializeFeatures(int Core);
@ -826,7 +829,7 @@ namespace CPU
uint8_t st[8][16]; uint8_t st[8][16];
/** @brief XMM registers */ /** @brief XMM registers */
uint8_t xmm[16][16]; uint8_t xmm[16][16];
} __packed; } __packed __aligned(16);
SafeFunction static inline void lgdt(void *gdt) SafeFunction static inline void lgdt(void *gdt)
{ {
@ -950,6 +953,29 @@ namespace CPU
uint64_t InterruptNumber /* iar_el1 */; // Interrupt Acknowledge Register uint64_t InterruptNumber /* iar_el1 */; // Interrupt Acknowledge Register
} TrapFrame; } 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__ #endif // !__FENNIX_KERNEL_CPU_H__

View File

@ -82,7 +82,7 @@ namespace CPU
/* Reserved by OS */ /* Reserved by OS */
IRQ16 = 0x30, // Reserved for multitasking IRQ16 = 0x30, /* Reserved for multitasking */
IRQ17 = 0x31, IRQ17 = 0x31,
IRQ18 = 0x32, IRQ18 = 0x32,
IRQ19 = 0x33, IRQ19 = 0x33,
@ -95,12 +95,11 @@ namespace CPU
IRQ26 = 0x3a, IRQ26 = 0x3a,
IRQ27 = 0x3b, IRQ27 = 0x3b,
IRQ28 = 0x3c, IRQ28 = 0x3c,
IRQ29 = 0x3d, // Reserved for icr stop core IRQ29 = 0x3d,
IRQ30 = 0x3e,
IRQ31 = 0x3f, /* Halt core interrupt */
/* Free */ /* Free */
IRQ30 = 0x3e,
IRQ31 = 0x3f,
IRQ32 = 0x40, IRQ32 = 0x40,
IRQ33 = 0x41, IRQ33 = 0x41,
IRQ34 = 0x42, IRQ34 = 0x42,

View File

@ -117,4 +117,6 @@ void SysDbgLockedWriteLine(enum DebugLevel Level, const char *File, int Line, co
#endif // __cplusplus #endif // __cplusplus
EXTERNC void uart_wrapper(char c, void *unused);
#endif // !__FENNIX_KERNEL_DEBUGGER_H__ #endif // !__FENNIX_KERNEL_DEBUGGER_H__

208
include/driver.hpp Normal file
View File

@ -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 <https://www.gnu.org/licenses/>.
*/
#ifndef __FENNIX_KERNEL_DRIVER_H__
#define __FENNIX_KERNEL_DRIVER_H__
#include <types.h>
#include <filesystem.hpp>
#include <unordered_map>
#include <memory.hpp>
#include <ints.hpp>
#include <lock.hpp>
#include <task.hpp>
#include <debug.h>
#include <cpu.hpp>
#include <pci.hpp>
#include <vector>
#include <io.h>
#include <list>
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<uint8_t> 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<min_t, SlaveDeviceFile *> *Slaves;
std::unordered_map<maj_t, Slaves> SlavesMap;
std::list<uint8_t> RawKeyQueue;
std::list<uint8_t> 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<uint8_t, void *> *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<dev_t, DriverObject> 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<dev_t, DriverObject> &
GetDrivers() { return Drivers; }
void LoadAllDrivers();
void UnloadAllDrivers();
void Panic();
Manager();
~Manager();
};
void PopulateDriverAPI(void *API);
}
#endif // !__FENNIX_KERNEL_DRIVER_H__

View File

@ -26,6 +26,7 @@ typedef uint16_t Elf32_Half;
typedef uint32_t Elf32_Off; typedef uint32_t Elf32_Off;
typedef int32_t Elf32_Sword; typedef int32_t Elf32_Sword;
typedef uint32_t Elf32_Word; typedef uint32_t Elf32_Word;
typedef Elf32_Sword Elf32_pid_t;
/* 64-bit ELF base types. */ /* 64-bit ELF base types. */
typedef uint64_t Elf64_Addr; typedef uint64_t Elf64_Addr;
@ -36,6 +37,11 @@ typedef int32_t Elf64_Sword;
typedef uint32_t Elf64_Word; typedef uint32_t Elf64_Word;
typedef uint64_t Elf64_Xword; typedef uint64_t Elf64_Xword;
typedef int64_t Elf64_Sxword; 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 enum IdentificationIndex
{ {
@ -227,8 +233,6 @@ enum SegmentTypes
PT_TLS = 7, PT_TLS = 7,
PT_LOPROC = 0x70000000, PT_LOPROC = 0x70000000,
PT_HIPROC = 0x7fffffff, PT_HIPROC = 0x7fffffff,
PT_GNU_EH_FRAME = 0x6474e550,
PT_GNU_STACK = 0x6474e551,
}; };
enum DynamicArrayTags enum DynamicArrayTags
@ -576,6 +580,80 @@ enum SpecialSections
SHT_HIUSER = 0x8fffffff 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 typedef struct elf32_hdr
{ {
unsigned char e_ident[EI_NIDENT]; unsigned char e_ident[EI_NIDENT];
@ -730,6 +808,117 @@ typedef struct
Elf64_Sxword r_addend; Elf64_Sxword r_addend;
} Elf64_Rela; } 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) #if defined(a64) || defined(aa64)
typedef Elf64_Addr Elf_Addr; typedef Elf64_Addr Elf_Addr;
typedef Elf64_Half Elf_Half; typedef Elf64_Half Elf_Half;

View File

@ -32,7 +32,6 @@ namespace Execute
enum BinaryType : int enum BinaryType : int
{ {
BinTypeInvalid, BinTypeInvalid,
BinTypeFex,
BinTypeELF, BinTypeELF,
BinTypePE, BinTypePE,
BinTypeNE, BinTypeNE,
@ -122,7 +121,7 @@ namespace Execute
BinaryType GetBinaryType(const char *Path); BinaryType GetBinaryType(const char *Path);
int Spawn(char *Path, const char **argv, const char **envp, 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, Tasking::TaskCompatibility Compatibility = Tasking::TaskCompatibility::Native,
bool Critical = false); bool Critical = false);

View File

@ -84,40 +84,81 @@
#define S_ISLNK(mode) (((mode) & S_IFMT) == S_IFLNK) #define S_ISLNK(mode) (((mode) & S_IFMT) == S_IFLNK)
#define S_ISSOCK(mode) (((mode) & S_IFMT) == S_IFSOCK) #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 struct stat
{ {
/** Device ID of the file. */
dev_t st_dev; dev_t st_dev;
/** Inode number. */
ino_t st_ino; ino_t st_ino;
/** File type and mode. */
mode_t st_mode; mode_t st_mode;
/** Number of hard links. */
nlink_t st_nlink; nlink_t st_nlink;
/** User ID of the file's owner. */
uid_t st_uid; uid_t st_uid;
/** Group ID of the file's owner. */
gid_t st_gid; gid_t st_gid;
/** Device ID for special files. */
dev_t st_rdev; dev_t st_rdev;
/** Size of the file in bytes. */
off_t st_size; off_t st_size;
/** Time of last access. */
time_t st_atime; time_t st_atime;
/** Time of last modification. */
time_t st_mtime; time_t st_mtime;
/** Time of last status change. */
time_t st_ctime; time_t st_ctime;
/** Optimal I/O block size. */
blksize_t st_blksize; blksize_t st_blksize;
/** Number of blocks allocated. */
blkcnt_t st_blocks; blkcnt_t st_blocks;
/** Additional file attributes. */
mode_t st_attr; 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 struct stat64
{ {
/** Device ID of the file. */
dev_t st_dev; dev_t st_dev;
/** Inode number. */
ino64_t st_ino; ino64_t st_ino;
/** File type and mode. */
mode_t st_mode; mode_t st_mode;
/** Number of hard links. */
nlink_t st_nlink; nlink_t st_nlink;
/** User ID of the file's owner. */
uid_t st_uid; uid_t st_uid;
/** Group ID of the file's owner. */
gid_t st_gid; gid_t st_gid;
/** Device ID for special files. */
dev_t st_rdev; dev_t st_rdev;
/** Size of the file in bytes. */
off64_t st_size; off64_t st_size;
/** Time of last access. */
time_t st_atime; time_t st_atime;
/** Time of last modification. */
time_t st_mtime; time_t st_mtime;
/** Time of last status change. */
time_t st_ctime; time_t st_ctime;
/** Optimal I/O block size. */
blksize_t st_blksize; blksize_t st_blksize;
/** Number of blocks allocated. */
blkcnt64_t st_blocks; blkcnt64_t st_blocks;
/** Additional file attributes. */
mode_t st_attr; mode_t st_attr;
}; };
@ -165,6 +206,12 @@ namespace vfs
}; };
class RefNode; class RefNode;
/**
* Virtual filesystem node
*
* @note https://isocpp.org/wiki/faq/freestore-mgmt#delete-this
*/
class Node class Node
{ {
private: private:
@ -173,15 +220,35 @@ namespace vfs
public: public:
virtual int open(int Flags, mode_t Mode); virtual int open(int Flags, mode_t Mode);
virtual int close(); virtual int close();
virtual size_t read(uint8_t *Buffer, virtual size_t read(uint8_t *Buffer, size_t Size, off_t Offset);
size_t Size, virtual size_t write(uint8_t *Buffer, size_t Size, off_t Offset);
off_t Offset); virtual int ioctl(unsigned long Request, void *Argp);
virtual size_t write(uint8_t *Buffer, // virtual int stat(struct stat *Stat);
size_t Size, // virtual int lstat(struct stat *Stat);
off_t Offset); // virtual int fstat(struct stat *Stat);
virtual int ioctl(unsigned long Request, // virtual int unlink();
void *Argp); // virtual int mkdir(mode_t Mode);
virtual ~Node(); // 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; class Virtual *vFS = nullptr;
Node *Parent = nullptr; Node *Parent = nullptr;
@ -211,21 +278,13 @@ namespace vfs
RefNode *CreateReference(); RefNode *CreateReference();
void RemoveReference(RefNode *Reference); 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 * Create a new node
* *
* @param Parent The parent node * @param Parent The parent node
* @param Name The name of the node * @param Name The name of the node
* @param Type The type 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 * be used as a hint for the parent node, but it
* won't be set as the parent node. * won't be set as the parent node.
* @param fs The virtual filesystem (only if * @param fs The virtual filesystem (only if
@ -239,6 +298,8 @@ namespace vfs
bool NoParent = false, bool NoParent = false,
Virtual *fs = nullptr, Virtual *fs = nullptr,
int *Err = nullptr); int *Err = nullptr);
virtual ~Node();
}; };
class RefNode class RefNode
@ -250,6 +311,8 @@ namespace vfs
RefNode *SymlinkTo; RefNode *SymlinkTo;
public: public:
void *SpecialData;
decltype(FileSize) &Size = FileSize; decltype(FileSize) &Size = FileSize;
decltype(n) &node = n; decltype(n) &node = n;
@ -287,6 +350,7 @@ namespace vfs
bool PathExists(const char *Path, Node *Parent = nullptr); bool PathExists(const char *Path, Node *Parent = nullptr);
Node *Create(const char *Path, NodeType Type, 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(const char *Path, bool Recursive = false, Node *Parent = nullptr);
int Delete(Node *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); RefNode *Open(const char *Path, Node *Parent = nullptr);
Node *CreateIfNotExists(const char *Path, NodeType Type, Node *Parent);
Virtual(); Virtual();
~Virtual(); ~Virtual();
@ -310,27 +376,32 @@ namespace vfs
public: public:
struct Fildes struct Fildes
{ {
RefNode *Handle{}; RefNode *Handle = nullptr;
mode_t Mode = 0; mode_t Mode = 0;
int Flags = 0; int Flags = 0;
int Descriptor = -1; int Descriptor = -1;
};
struct DupFildes int operator==(const Fildes &other)
{ {
RefNode *Handle{}; return this->Handle == other.Handle &&
mode_t Mode = 0; this->Mode == other.Mode &&
int Flags = 0; this->Flags == other.Flags &&
int Descriptor = -1; this->Descriptor == other.Descriptor;
}; }
int operator!=(const Fildes &other)
{
return !(*this == other);
}
} __attribute__((packed)) nullfd;
private: private:
std::vector<Fildes> FileDescriptors; std::vector<Fildes> FileDescriptors;
std::vector<DupFildes> FildesDuplicates; std::vector<Fildes> FildesDuplicates;
vfs::Node *fdDir = nullptr; vfs::Node *fdDir = nullptr;
Fildes GetFileDescriptor(int FileDescriptor); Fildes &GetFileDescriptor(int FileDescriptor);
FileDescriptorTable::DupFildes GetDupFildes(int FileDescriptor); FileDescriptorTable::Fildes &GetDupFildes(int FileDescriptor);
int ProbeMode(mode_t Mode, int Flags); int ProbeMode(mode_t Mode, int Flags);
int AddFileDescriptor(const char *AbsolutePath, mode_t Mode, int Flags); int AddFileDescriptor(const char *AbsolutePath, mode_t Mode, int Flags);
@ -338,8 +409,14 @@ namespace vfs
int GetFreeFileDescriptor(); int GetFreeFileDescriptor();
public: public:
Fildes &GetDescriptor(int FileDescriptor);
const char *GetAbsolutePath(int FileDescriptor); const char *GetAbsolutePath(int FileDescriptor);
std::vector<Fildes> &GetFileDescriptors() { return FileDescriptors; } std::vector<Fildes> &GetFileDescriptors() { return FileDescriptors; }
std::vector<Fildes> &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 _open(const char *pathname, int flags, mode_t mode);
int _creat(const char *pathname, mode_t mode); int _creat(const char *pathname, mode_t mode);

View File

@ -20,13 +20,58 @@
#include <types.h> #include <types.h>
#include <stropts.h> #include <stropts.h>
#include <filesystem/termios.hpp>
struct winsize #define _IOC_NRBITS 8
{ #define _IOC_TYPEBITS 8
unsigned short ws_row; #define _IOC_SIZEBITS 14
unsigned short ws_col; #define _IOC_DIRBITS 2
unsigned short ws_xpixel;
unsigned short ws_ypixel; #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__ #endif // !__FENNIX_KERNEL_FILESYSTEM_IOCTL_H__

View File

@ -20,7 +20,12 @@
#include <types.h> #include <types.h>
#include <filesystem/termios.hpp>
#include <filesystem.hpp> #include <filesystem.hpp>
#include <bitmap.hpp>
#include <task.hpp>
#include <lock.hpp>
#include <vector>
namespace vfs namespace vfs
{ {
@ -34,12 +39,12 @@ namespace vfs
class NullDevice : public Node class NullDevice : public Node
{ {
public: public:
virtual size_t read(uint8_t *Buffer, size_t read(uint8_t *Buffer,
size_t Size, size_t Size,
off_t Offset); off_t Offset) final;
virtual size_t write(uint8_t *Buffer, size_t write(uint8_t *Buffer,
size_t Size, size_t Size,
off_t Offset); off_t Offset) final;
NullDevice(); NullDevice();
~NullDevice(); ~NullDevice();
@ -48,12 +53,12 @@ namespace vfs
class RandomDevice : public Node class RandomDevice : public Node
{ {
public: public:
virtual size_t read(uint8_t *Buffer, size_t read(uint8_t *Buffer,
size_t Size, size_t Size,
off_t Offset); off_t Offset) final;
virtual size_t write(uint8_t *Buffer, size_t write(uint8_t *Buffer,
size_t Size, size_t Size,
off_t Offset); off_t Offset) final;
RandomDevice(); RandomDevice();
~RandomDevice(); ~RandomDevice();
@ -62,42 +67,137 @@ namespace vfs
class ZeroDevice : public Node class ZeroDevice : public Node
{ {
public: public:
virtual size_t read(uint8_t *Buffer, size_t read(uint8_t *Buffer,
size_t Size, size_t Size,
off_t Offset); off_t Offset) final;
virtual size_t write(uint8_t *Buffer, size_t write(uint8_t *Buffer,
size_t Size, size_t Size,
off_t Offset); off_t Offset) final;
ZeroDevice(); ZeroDevice();
~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 class TTYDevice : public Node
{ {
public: public:
virtual size_t write(uint8_t *Buffer, size_t write(uint8_t *Buffer,
size_t Size, size_t Size,
off_t Offset); off_t Offset) final;
virtual int ioctl(unsigned long Request, int ioctl(unsigned long Request,
void *Argp); void *Argp) final;
TTYDevice(); TTYDevice();
~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 class PTMXDevice : public Node
{ {
private: private:
Node *pts = nullptr; NewLock(PTMXLock);
Node *pts;
Bitmap ptysId;
std::vector<PTYDevice *> ptysList;
public: public:
virtual size_t read(uint8_t *Buffer, int open(int Flags, mode_t Mode) final;
size_t Size,
off_t Offset); /**
virtual size_t write(uint8_t *Buffer, * Remove a PTY from the list
size_t Size, *
off_t Offset); * @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();
~PTMXDevice(); ~PTMXDevice();

View File

@ -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 <https://www.gnu.org/licenses/>.
*/
#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__

View File

@ -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 <https://www.gnu.org/licenses/>.
*/
#ifndef __FENNIX_KERNEL_TERMIOS_H__
#define __FENNIX_KERNEL_TERMIOS_H__
#include <types.h>
#include <filesystem/termios-bits.hpp>
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__

1067
include/ini.h Normal file

File diff suppressed because it is too large Load Diff

View File

@ -20,6 +20,7 @@
#include <types.h> #include <types.h>
#include <cpu.hpp> #include <cpu.hpp>
#include <pci.hpp>
namespace Interrupts namespace Interrupts
{ {
@ -30,11 +31,11 @@ namespace Interrupts
#endif #endif
#if defined(a64) #if defined(a64)
/* APIC::APIC */ extern void *apic[256]; // MAX_CPU /* APIC::APIC */ extern void *apic[255]; // MAX_CPU
/* APIC::Timer */ extern void *apicTimer[256]; // MAX_CPU /* APIC::Timer */ extern void *apicTimer[255]; // MAX_CPU
#elif defined(a32) #elif defined(a32)
/* APIC::APIC */ extern void *apic[256]; // MAX_CPU /* APIC::APIC */ extern void *apic[255]; // MAX_CPU
/* APIC::Timer */ extern void *apicTimer[256]; // MAX_CPU /* APIC::Timer */ extern void *apicTimer[255]; // MAX_CPU
#elif defined(aa64) #elif defined(aa64)
#endif #endif
extern void *InterruptFrames[INT_FRAMES_MAX]; extern void *InterruptFrames[INT_FRAMES_MAX];
@ -44,6 +45,16 @@ namespace Interrupts
void InitializeTimer(int Core); void InitializeTimer(int Core);
void RemoveAll(); void RemoveAll();
void AddHandler(void (*Callback)(CPU::TrapFrame *),
int InterruptNumber, void *ctx = nullptr,
bool Critical = false);
void RemoveHandler(void (*Callback)(CPU::TrapFrame *),
int InterruptNumber);
void RemoveHandler(void (*Callback)(CPU::TrapFrame *));
void RemoveHandler(int InterruptNumber);
class Handler class Handler
{ {
private: private:
@ -61,17 +72,13 @@ namespace Interrupts
* @brief Create a new interrupt handler. * @brief Create a new interrupt handler.
* @param InterruptNumber The interrupt number. NOT the IRQ number! (IRQ0 != 32) * @param InterruptNumber The interrupt number. NOT the IRQ number! (IRQ0 != 32)
*/ */
Handler(int InterruptNumber); Handler(int InterruptNumber, bool Critical = false);
Handler(PCI::PCIDevice Device, bool Critical = false);
Handler();
~Handler(); ~Handler();
public: public:
#if defined(a64) virtual void OnInterruptReceived(CPU::TrapFrame *Frame);
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
}; };
} }

View File

@ -26,7 +26,7 @@
extern "C" extern "C"
{ {
#endif #endif
static inline uint8_t inportb(uint16_t Port) static inline uint8_t inb(uint16_t Port)
{ {
uint8_t Result; uint8_t Result;
asm("in %%dx, %%al" asm("in %%dx, %%al"
@ -35,7 +35,7 @@ extern "C"
return Result; return Result;
} }
static inline uint16_t inportw(uint16_t Port) static inline uint16_t inw(uint16_t Port)
{ {
uint16_t Result; uint16_t Result;
asm("in %%dx, %%ax" asm("in %%dx, %%ax"
@ -44,7 +44,7 @@ extern "C"
return Result; return Result;
} }
static inline uint32_t inportl(uint16_t Port) static inline uint32_t inl(uint16_t Port)
{ {
uint32_t Result; uint32_t Result;
asmv("inl %1, %0" asmv("inl %1, %0"
@ -53,103 +53,27 @@ extern "C"
return Result; 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" asmv("out %%al, %%dx"
: :
: "a"(Data), "d"(Port)); : "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" asmv("out %%ax, %%dx"
: :
: "a"(Data), "d"(Port)); : "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" asmv("outl %1, %0"
: :
: "dN"(Port), "a"(Data)); : "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) static inline void mmoutb(void *Address, uint8_t Value)
{ {
asmv("mov %1, %0" asmv("mov %1, %0"
@ -225,17 +149,10 @@ extern "C"
return Result; return Result;
} }
#endif #endif
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #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 // defined(a86)
#endif // !__FENNIX_KERNEL_IO_H__ #endif // !__FENNIX_KERNEL_IO_H__

View File

@ -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 <https://www.gnu.org/licenses/>.
*/
#ifndef __FENNIX_KERNEL_IPC_H__
#define __FENNIX_KERNEL_IPC_H__
#include <types.h>
#include <filesystem.hpp>
#include <memory.hpp>
#include <lock.hpp>
#include <vector>
#include <atomic>
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<IPCHandle *> Handles;
Memory::VirtualMemoryArea *vma;
vfs::Node *IPCNode;
void *Process;
public:
std::vector<IPCHandle *> 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__

View File

@ -31,7 +31,7 @@ struct KernelConfig
{ {
Memory::MemoryAllocatorType AllocatorType; Memory::MemoryAllocatorType AllocatorType;
bool SchedulerType; bool SchedulerType;
char ModuleDirectory[256]; char DriverDirectory[256];
char InitPath[256]; char InitPath[256];
bool UseLinuxSyscalls; bool UseLinuxSyscalls;
bool InterruptsOnCrash; bool InterruptsOnCrash;
@ -39,7 +39,7 @@ struct KernelConfig
int IOAPICInterruptCore; int IOAPICInterruptCore;
bool UnlockDeadLock; bool UnlockDeadLock;
bool SIMD; bool SIMD;
bool BootAnimation; bool Quiet;
}; };
void ParseConfig(char *ConfigString, KernelConfig *ModConfig); void ParseConfig(char *ConfigString, KernelConfig *ModConfig);

View File

@ -60,6 +60,7 @@ private:
void Yield(); void Yield();
public: public:
bool Locked() { return IsLocked.load(); }
SpinLockData *GetLockData() { return &LockData; } SpinLockData *GetLockData() { return &LockData; }
int Lock(const char *FunctionName); int Lock(const char *FunctionName);
int Unlock(); int Unlock();
@ -74,6 +75,11 @@ private:
LockClass *LockPointer = nullptr; LockClass *LockPointer = nullptr;
public: public:
bool Locked()
{
return this->LockPointer->Locked();
}
SmartLockClass(LockClass &Lock, const char *FunctionName) SmartLockClass(LockClass &Lock, const char *FunctionName)
{ {
this->LockPointer = &Lock; this->LockPointer = &Lock;
@ -88,6 +94,11 @@ private:
LockClass *LockPointer = nullptr; LockClass *LockPointer = nullptr;
public: public:
bool Locked()
{
return this->LockPointer->Locked();
}
SmartTimeoutLockClass(LockClass &Lock, SmartTimeoutLockClass(LockClass &Lock,
const char *FunctionName, const char *FunctionName,
uint64_t Timeout) uint64_t Timeout)

View File

@ -43,10 +43,20 @@ namespace Memory
enum MemoryAllocatorType enum MemoryAllocatorType
{ {
None, None,
/** Allocate memory by pages. */
Pages, Pages,
XallocV1, XallocV1,
XallocV2, XallocV2,
liballoc11 liballoc11,
/**
* @warning Not working as expected.
*
* FIXME: This allocator is not working as expected.
*/
rpmalloc_,
}; };
} }
@ -61,6 +71,7 @@ namespace Memory
#include <memory/brk.hpp> #include <memory/brk.hpp>
void InitializeMemoryManagement(); void InitializeMemoryManagement();
void CreatePageTable(Memory::PageTable *pt);
void *operator new(std::size_t Size); void *operator new(std::size_t Size);
void *operator new[](std::size_t Size); void *operator new[](std::size_t Size);

View File

@ -36,6 +36,9 @@ namespace Memory
uintptr_t Break = 0x0; uintptr_t Break = 0x0;
public: public:
/* fork() */
void SetTable(PageTable *Table) { this->Table = Table; }
/* Directly to syscall */ /* Directly to syscall */
void *brk(void *Address); void *brk(void *Address);

View File

@ -148,7 +148,7 @@ namespace Memory
#elif defined(aa64) #elif defined(aa64)
#endif #endif
}; };
uintptr_t raw; uintptr_t raw = 0;
/** @brief Set Address */ /** @brief Set Address */
void SetAddress(uintptr_t _Address) void SetAddress(uintptr_t _Address)
@ -273,7 +273,7 @@ namespace Memory
} FourMiB; } FourMiB;
#elif defined(aa64) #elif defined(aa64)
#endif #endif
uintptr_t raw; uintptr_t raw = 0;
/** @brief Set PageTableEntryPtr address */ /** @brief Set PageTableEntryPtr address */
void SetAddress(uintptr_t _Address) void SetAddress(uintptr_t _Address)
@ -359,7 +359,7 @@ namespace Memory
} OneGiB; } OneGiB;
#elif defined(aa64) #elif defined(aa64)
#endif #endif
uintptr_t raw; uintptr_t raw = 0;
/** @brief Set PageDirectoryEntryPtr address */ /** @brief Set PageDirectoryEntryPtr address */
void SetAddress(uintptr_t _Address) void SetAddress(uintptr_t _Address)
@ -413,7 +413,7 @@ namespace Memory
}; };
#elif defined(aa64) #elif defined(aa64)
#endif #endif
uintptr_t raw; uintptr_t raw = 0;
/** @brief Set PageDirectoryPointerTableEntryPtr address */ /** @brief Set PageDirectoryPointerTableEntryPtr address */
void SetAddress(uintptr_t _Address) void SetAddress(uintptr_t _Address)
@ -467,7 +467,7 @@ namespace Memory
}; };
#elif defined(aa64) #elif defined(aa64)
#endif #endif
uintptr_t raw; uintptr_t raw = 0;
/** @brief Set PageMapLevel4Ptr address */ /** @brief Set PageMapLevel4Ptr address */
void SetAddress(uintptr_t _Address) void SetAddress(uintptr_t _Address)
@ -516,10 +516,34 @@ namespace Memory
* *
* @return A new PageTable with the same content * @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 <typename T> template <typename T>
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); } __aligned(0x1000);
} }

View File

@ -30,7 +30,7 @@ namespace Memory
{ {
private: private:
NewLock(MemoryLock); NewLock(MemoryLock);
PageTable *Table = nullptr; PageTable *pTable = nullptr;
public: public:
enum MapType enum MapType
@ -60,8 +60,7 @@ namespace Memory
* @param VirtualAddress Virtual address of the page * @param VirtualAddress Virtual address of the page
* @param Flag Flag to check * @param Flag Flag to check
* @param Type Type of the page. Check MapType enum. * @param Type Type of the page. Check MapType enum.
* @return true if page has the specified flag. * @return true if page has the specified flag, false otherwise.
* @return false if page is has the specified flag.
*/ */
bool Check(void *VirtualAddress, bool Check(void *VirtualAddress,
PTFlag Flag = PTFlag::P, PTFlag Flag = PTFlag::P,

View File

@ -56,6 +56,7 @@ namespace Memory
public: public:
PageTable *GetTable() { return Table; } PageTable *GetTable() { return Table; }
void SetTable(PageTable *Table) { this->Table = Table; }
std::vector<AllocatedPages> GetAllocatedPagesList() std::vector<AllocatedPages> GetAllocatedPagesList()
{ {
@ -94,6 +95,10 @@ namespace Memory
bool HandleCoW(uintptr_t PFA); bool HandleCoW(uintptr_t PFA);
void FreeAllPages();
void Fork(VirtualMemoryArea *Parent);
VirtualMemoryArea(PageTable *Table = nullptr); VirtualMemoryArea(PageTable *Table = nullptr);
~VirtualMemoryArea(); ~VirtualMemoryArea();
}; };

View File

@ -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 <https://www.gnu.org/licenses/>.
*/
#ifndef __FENNIX_KERNEL_MODULE_H__
#define __FENNIX_KERNEL_MODULE_H__
#include <types.h>
#include <memory.hpp>
#include <ints.hpp>
#include <lock.hpp>
#include <debug.h>
#include <cpu.hpp>
#include <pci.hpp>
#include <vector>
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<ModuleFile> 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<ModuleFile> A clone of the drivers vector.
*/
std::vector<ModuleFile> 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__

View File

@ -79,7 +79,7 @@ namespace NetworkEthernet
public: public:
/** @brief Get driver interface /** @brief Get driver interface
* @return Module interface * @return Driver interface
*/ */
NetworkInterfaceManager::DeviceInterface *GetInterface() NetworkInterfaceManager::DeviceInterface *GetInterface()
{ {

View File

@ -22,7 +22,7 @@
#include <memory.hpp> #include <memory.hpp>
#include <debug.h> #include <debug.h>
#include <vector> #include <list>
namespace PCI namespace PCI
{ {
@ -30,6 +30,8 @@ namespace PCI
{ {
enum PCIVendors enum PCIVendors
{ {
Apple = 0x106B,
BusLogic = 0x104B,
SymbiosLogic = 0x1000, SymbiosLogic = 0x1000,
RedHat = 0x1AF4, RedHat = 0x1AF4,
REDHat2 = 0x1B36, REDHat2 = 0x1B36,
@ -120,12 +122,9 @@ namespace PCI
uint8_t LatencyTimer; uint8_t LatencyTimer;
uint8_t HeaderType; uint8_t HeaderType;
uint8_t BIST; uint8_t BIST;
}; } __packed;
/** /** PCI Header Type 0 */
* @brief PCI Header Type 0
*
*/
struct PCIHeader0 struct PCIHeader0
{ {
PCIDeviceHeader Header; PCIDeviceHeader Header;
@ -147,11 +146,9 @@ namespace PCI
uint8_t InterruptPin; uint8_t InterruptPin;
uint8_t MinGrant; uint8_t MinGrant;
uint8_t MaxLatency; uint8_t MaxLatency;
}; } __packed;
/** /** PCI Header Type 1 (PCI-to-PCI Bridge) */
* @brief PCI Header Type 1 (PCI-to-PCI Bridge)
*/
struct PCIHeader1 struct PCIHeader1
{ {
PCIDeviceHeader Header; PCIDeviceHeader Header;
@ -179,11 +176,9 @@ namespace PCI
uint8_t InterruptLine; uint8_t InterruptLine;
uint8_t InterruptPin; uint8_t InterruptPin;
uint16_t BridgeControl; uint16_t BridgeControl;
}; } __packed;
/** /** PCI Header Type 2 (PCI-to-CardBus Bridge) */
* @brief PCI Header Type 2 (PCI-to-CardBus Bridge)
*/
struct PCIHeader2 struct PCIHeader2
{ {
PCIDeviceHeader Header; PCIDeviceHeader Header;
@ -209,7 +204,7 @@ namespace PCI
uint16_t SubsystemVendorID; uint16_t SubsystemVendorID;
uint16_t SubsystemID; uint16_t SubsystemID;
uint32_t LegacyBaseAddress; uint32_t LegacyBaseAddress;
}; } __packed;
struct DeviceConfig struct DeviceConfig
{ {
@ -227,24 +222,25 @@ namespace PCI
uint32_t Bus; uint32_t Bus;
uint32_t Device; uint32_t Device;
uint32_t Function; uint32_t Function;
}; } __packed;
class PCI class Manager
{ {
private: private:
std::vector<PCIDevice> Devices; std::list<PCIDevice> Devices;
public: public:
std::vector<PCIDevice> &GetDevices() { return Devices; } std::list<PCIDevice> GetDevices() { return Devices; }
void MapPCIAddresses(PCIDevice Device, Memory::PageTable *Table = nullptr); void MapPCIAddresses(PCIDevice Device, Memory::PageTable *Table);
void EnumerateFunction(uint64_t DeviceAddress, uint32_t Function, PCIDevice dev); void EnumerateFunction(uint64_t DeviceAddress, uint32_t Function, PCIDevice dev);
void EnumerateDevice(uint64_t BusAddress, uint32_t Device, PCIDevice dev); void EnumerateDevice(uint64_t BusAddress, uint32_t Device, PCIDevice dev);
void EnumerateBus(uint64_t BaseAddress, uint32_t Bus, PCIDevice dev); void EnumerateBus(uint64_t BaseAddress, uint32_t Bus, PCIDevice dev);
std::vector<PCIDevice> FindPCIDevice(uint8_t Class, uint8_t Subclass, uint8_t ProgIF); std::list<PCIDevice> FindPCIDevice(uint8_t Class, uint8_t Subclass, uint8_t ProgIF);
std::vector<PCIDevice> FindPCIDevice(int VendorID, int DeviceID); std::list<PCIDevice> FindPCIDevice(uint16_t VendorID, uint16_t DeviceID);
std::list<PCIDevice> FindPCIDevice(std::list<uint16_t> VendorIDs, std::list<uint16_t> DeviceIDs);
PCI(); Manager();
~PCI(); ~Manager();
}; };
} }

Some files were not shown because too many files have changed in this diff Show More