diff --git a/.gitignore b/.gitignore index 50b4e787..740d1066 100644 --- a/.gitignore +++ b/.gitignore @@ -39,6 +39,12 @@ documentation/out/* target/iso/boot/kernel target/iso/boot/loader target/iso/boot/ramdisk +target/iso/boot/limine/limine-*.sys +target/iso/boot/limine/limine-*.bin +target/limine-*/* +target/limine-*.tar.gz + +node_modules sysroot/system/include sysroot/system/lib/* diff --git a/applications/ahcidriver/src/ahcidriver.cpp b/applications/ahcidriver/src/ahcidriver.cpp index a416b808..9299cadb 100644 --- a/applications/ahcidriver/src/ahcidriver.cpp +++ b/applications/ahcidriver/src/ahcidriver.cpp @@ -79,7 +79,7 @@ bool ahciDriverIdentifyController() devices[i].subclassCode == PCI_01_SUBCLASS_SATA && devices[i].progIf == PCI_01_06_PROGIF_AHCI) { - uint32_t bar; + g_address bar; if(!pciDriverReadBAR(devices[i].deviceAddress, 5, &bar)) { klog("Failed to read BAR5 from PCI device %x", devices[i].deviceAddress); diff --git a/applications/devicemanager/src/manager.cpp b/applications/devicemanager/src/manager.cpp index d7b8de95..dd902c73 100644 --- a/applications/devicemanager/src/manager.cpp +++ b/applications/devicemanager/src/manager.cpp @@ -89,8 +89,8 @@ void _deviceManagerCheckPciDevices() } else { - klog("starting VBE driver"); - g_spawn("/applications/vbedriver.bin", "", "", G_SECURITY_LEVEL_DRIVER); + klog("starting EFI FB driver"); + g_spawn("/applications/efifbdriver.bin", "", "", G_SECURITY_LEVEL_DRIVER); } } diff --git a/applications/vbedriver/build.sh b/applications/efifbdriver/build.sh old mode 100755 new mode 100644 similarity index 86% rename from applications/vbedriver/build.sh rename to applications/efifbdriver/build.sh index 08b9ebab..27b45a79 --- a/applications/vbedriver/build.sh +++ b/applications/efifbdriver/build.sh @@ -6,7 +6,7 @@ fi . "$ROOT/ghost.sh" # Build configuration -ARTIFACT_NAME="vbedriver.bin" +ARTIFACT_NAME="efifbdriver.bin" LDFLAGS="-ldevice" # Include application build tasks diff --git a/applications/efifbdriver/src/efifbdriver.cpp b/applications/efifbdriver/src/efifbdriver.cpp new file mode 100644 index 00000000..db851deb --- /dev/null +++ b/applications/efifbdriver/src/efifbdriver.cpp @@ -0,0 +1,98 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * * + * Ghost, a micro-kernel based operating system for the x86 architecture * + * Copyright (C) 2015, Max Schlüssel * + * * + * This program 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. * + * * + * This program 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 this program. If not, see . * + * * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#include "efifbdriver.hpp" + +#include +#include + +#include +#include +#include + +g_device_id deviceId; + +int main() +{ + g_task_register_name("efifbdriver"); + + if(!deviceManagerRegisterDevice(G_DEVICE_TYPE_VIDEO, g_get_tid(), &deviceId)) + { + klog("failed to register device with device manager"); + return -1; + } + klog("registered EFI FB device %i", deviceId); + + efifbDriverReceiveMessages(); + return 0; +} + +void efifbDriverReceiveMessages() +{ + size_t buflen = sizeof(g_message_header) + 1024; + uint8_t buf[buflen]; + + for(;;) + { + auto status = g_receive_message(buf, buflen); + if(status != G_MESSAGE_RECEIVE_STATUS_SUCCESSFUL) + { + continue; + } + + g_message_header* header = (g_message_header*) buf; + g_video_request_header* request = (g_video_request_header*) G_MESSAGE_CONTENT(buf); + + if(request->command == G_VIDEO_COMMAND_SET_MODE) + { + efifbDriverHandleCommandSetMode((g_video_set_mode_request*) request, header->sender, header->transaction); + } + else + { + klog("efifbdriver: received unknown command %i from task %i", request->command, header->sender); + } + } +} + +void efifbDriverHandleCommandSetMode(g_video_set_mode_request* request, g_tid requestingTaskId, + g_message_transaction requestTransaction) +{ + g_address lfb; + uint16_t resX; + uint16_t resY; + uint16_t bpp; + uint32_t pitch; + g_get_efi_framebuffer(&lfb, &resX, &resY, &bpp, &pitch); + + uint64_t lfbSize = pitch * resY; + auto localMapped = g_map_mmio((void*) lfb, lfbSize); + // TODO: This is kind of unneccessary, we don't want to map it here + void* addressInRequestersSpace = g_share_mem((void*) localMapped, lfbSize, requestingTaskId); + + g_video_set_mode_response response{}; + response.status = G_VIDEO_SET_MODE_STATUS_SUCCESS; + response.mode_info.lfb = (g_address) addressInRequestersSpace; + response.mode_info.resX = resX; + response.mode_info.resY = resY; + response.mode_info.bpp = (uint8_t) bpp; + response.mode_info.bpsl = (uint16_t) pitch; + response.mode_info.explicit_update = false; + g_send_message_t(requestingTaskId, &response, sizeof(g_video_set_mode_response), requestTransaction); +} diff --git a/applications/efifbdriver/src/efifbdriver.hpp b/applications/efifbdriver/src/efifbdriver.hpp new file mode 100644 index 00000000..016ec818 --- /dev/null +++ b/applications/efifbdriver/src/efifbdriver.hpp @@ -0,0 +1,40 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * * + * Ghost, a micro-kernel based operating system for the x86 architecture * + * Copyright (C) 2015, Max Schlüssel * + * * + * This program 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. * + * * + * This program 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 this program. If not, see . * + * * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#ifndef __EFIFBDRIVER__ +#define __EFIFBDRIVER__ + +#include + +#include +#include + +/** + * Main loop receiving messages from other processes to do something. + */ +void efifbDriverReceiveMessages(); + +/** + * Handles a set-mode command. + */ +void efifbDriverHandleCommandSetMode(g_video_set_mode_request* request, g_tid requestingTaskId, + g_message_transaction requestTransaction); + +#endif diff --git a/applications/gsh/src/gosh.cpp b/applications/gsh/src/gosh.cpp index 2c200040..f3a2cd9b 100644 --- a/applications/gsh/src/gosh.cpp +++ b/applications/gsh/src/gosh.cpp @@ -28,6 +28,8 @@ #include #include +#include + char* cwdbuf = 0; std::vector gshAutocomplete(std::string toComplete) @@ -306,6 +308,12 @@ bool gshHandleBuiltin(program_call_t* call) return true; } + if(call->program == "bg") + { + g_spawn(call->arguments.at(0).c_str(), "", "", G_SECURITY_LEVEL_APPLICATION); + return true; + } + if(call->program == "clear" || call->program == "cls") { g_terminal::clear(); diff --git a/applications/libpci/inc/libpci/driver.hpp b/applications/libpci/inc/libpci/driver.hpp index f6efbba6..e115a015 100644 --- a/applications/libpci/inc/libpci/driver.hpp +++ b/applications/libpci/inc/libpci/driver.hpp @@ -140,7 +140,7 @@ struct g_pci_enable_resource_access_response /** * Read a BAR from a device. */ -bool pciDriverReadBAR(g_pci_device_address address, uint8_t bar, uint32_t* outValue); +bool pciDriverReadBAR(g_pci_device_address address, uint8_t bar, g_address* outValue); struct g_pci_read_bar_request { @@ -152,13 +152,13 @@ struct g_pci_read_bar_request struct g_pci_read_bar_response { bool successful; - uint32_t value; + g_address value; }__attribute__((packed)); /** * Read a BAR size from a device. */ -bool pciDriverReadBARSize(g_pci_device_address address, uint8_t bar, uint32_t* outValue); +bool pciDriverReadBARSize(g_pci_device_address address, uint8_t bar, g_address* outValue); struct g_pci_read_bar_size_request { @@ -170,7 +170,7 @@ struct g_pci_read_bar_size_request struct g_pci_read_bar_size_response { bool successful; - uint32_t value; + g_address value; }__attribute__((packed)); #endif diff --git a/applications/libpci/src/driver.cpp b/applications/libpci/src/driver.cpp index f1b9a5a5..93428f63 100644 --- a/applications/libpci/src/driver.cpp +++ b/applications/libpci/src/driver.cpp @@ -132,7 +132,7 @@ bool pciDriverEnableResourceAccess(g_pci_device_address address, bool enabled) return success; } -bool pciDriverReadBAR(g_pci_device_address address, uint8_t bar, uint32_t* outValue) +bool pciDriverReadBAR(g_pci_device_address address, uint8_t bar, g_address* outValue) { g_tid driverTid = g_task_await_by_name(G_PCI_DRIVER_NAME); @@ -156,7 +156,7 @@ bool pciDriverReadBAR(g_pci_device_address address, uint8_t bar, uint32_t* outVa return success; } -bool pciDriverReadBARSize(g_pci_device_address address, uint8_t bar, uint32_t* outValue) +bool pciDriverReadBARSize(g_pci_device_address address, uint8_t bar, g_address* outValue) { g_tid driverTid = g_task_await_by_name(G_PCI_DRIVER_NAME); diff --git a/applications/libvideo/inc/libvideo/videodriver.hpp b/applications/libvideo/inc/libvideo/videodriver.hpp index 70cb37af..11775ca5 100644 --- a/applications/libvideo/inc/libvideo/videodriver.hpp +++ b/applications/libvideo/inc/libvideo/videodriver.hpp @@ -23,6 +23,7 @@ #include #include +#include #include struct g_video_mode_info @@ -31,7 +32,7 @@ struct g_video_mode_info uint16_t resY; uint16_t bpp; uint16_t bpsl; - uint32_t lfb; + g_address lfb; bool explicit_update; }__attribute__((packed)); diff --git a/applications/vbedriver/.settings/org.eclipse.cdt.codan.core.prefs b/applications/vbedriver/.settings/org.eclipse.cdt.codan.core.prefs deleted file mode 100644 index fe13b550..00000000 --- a/applications/vbedriver/.settings/org.eclipse.cdt.codan.core.prefs +++ /dev/null @@ -1,67 +0,0 @@ -eclipse.preferences.version=1 -org.eclipse.cdt.codan.checkers.errnoreturn=Warning -org.eclipse.cdt.codan.checkers.errnoreturn.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},implicit\=>false} -org.eclipse.cdt.codan.checkers.errreturnvalue=Error -org.eclipse.cdt.codan.checkers.errreturnvalue.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}} -org.eclipse.cdt.codan.checkers.noreturn=Error -org.eclipse.cdt.codan.checkers.noreturn.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},implicit\=>false} -org.eclipse.cdt.codan.internal.checkers.AbstractClassCreation=Error -org.eclipse.cdt.codan.internal.checkers.AbstractClassCreation.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}} -org.eclipse.cdt.codan.internal.checkers.AmbiguousProblem=Error -org.eclipse.cdt.codan.internal.checkers.AmbiguousProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}} -org.eclipse.cdt.codan.internal.checkers.AssignmentInConditionProblem=Warning -org.eclipse.cdt.codan.internal.checkers.AssignmentInConditionProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}} -org.eclipse.cdt.codan.internal.checkers.AssignmentToItselfProblem=Error -org.eclipse.cdt.codan.internal.checkers.AssignmentToItselfProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}} -org.eclipse.cdt.codan.internal.checkers.CaseBreakProblem=Warning -org.eclipse.cdt.codan.internal.checkers.CaseBreakProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},no_break_comment\=>"no break",last_case_param\=>false,empty_case_param\=>false} -org.eclipse.cdt.codan.internal.checkers.CatchByReference=Warning -org.eclipse.cdt.codan.internal.checkers.CatchByReference.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},unknown\=>false,exceptions\=>()} -org.eclipse.cdt.codan.internal.checkers.CircularReferenceProblem=Error -org.eclipse.cdt.codan.internal.checkers.CircularReferenceProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}} -org.eclipse.cdt.codan.internal.checkers.ClassMembersInitialization=Warning -org.eclipse.cdt.codan.internal.checkers.ClassMembersInitialization.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},skip\=>true} -org.eclipse.cdt.codan.internal.checkers.FieldResolutionProblem=Error -org.eclipse.cdt.codan.internal.checkers.FieldResolutionProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}} -org.eclipse.cdt.codan.internal.checkers.FunctionResolutionProblem=Error -org.eclipse.cdt.codan.internal.checkers.FunctionResolutionProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}} -org.eclipse.cdt.codan.internal.checkers.InvalidArguments=Error -org.eclipse.cdt.codan.internal.checkers.InvalidArguments.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}} -org.eclipse.cdt.codan.internal.checkers.InvalidTemplateArgumentsProblem=Error -org.eclipse.cdt.codan.internal.checkers.InvalidTemplateArgumentsProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}} -org.eclipse.cdt.codan.internal.checkers.LabelStatementNotFoundProblem=Error -org.eclipse.cdt.codan.internal.checkers.LabelStatementNotFoundProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}} -org.eclipse.cdt.codan.internal.checkers.MemberDeclarationNotFoundProblem=Error -org.eclipse.cdt.codan.internal.checkers.MemberDeclarationNotFoundProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}} -org.eclipse.cdt.codan.internal.checkers.MethodResolutionProblem=Error -org.eclipse.cdt.codan.internal.checkers.MethodResolutionProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}} -org.eclipse.cdt.codan.internal.checkers.NamingConventionFunctionChecker=-Info -org.eclipse.cdt.codan.internal.checkers.NamingConventionFunctionChecker.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},pattern\=>"^[a-z]",macro\=>true,exceptions\=>()} -org.eclipse.cdt.codan.internal.checkers.NonVirtualDestructorProblem=Warning -org.eclipse.cdt.codan.internal.checkers.NonVirtualDestructorProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}} -org.eclipse.cdt.codan.internal.checkers.OverloadProblem=Error -org.eclipse.cdt.codan.internal.checkers.OverloadProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}} -org.eclipse.cdt.codan.internal.checkers.RedeclarationProblem=Error -org.eclipse.cdt.codan.internal.checkers.RedeclarationProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}} -org.eclipse.cdt.codan.internal.checkers.RedefinitionProblem=Error -org.eclipse.cdt.codan.internal.checkers.RedefinitionProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}} -org.eclipse.cdt.codan.internal.checkers.ReturnStyleProblem=-Warning -org.eclipse.cdt.codan.internal.checkers.ReturnStyleProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}} -org.eclipse.cdt.codan.internal.checkers.ScanfFormatStringSecurityProblem=-Warning -org.eclipse.cdt.codan.internal.checkers.ScanfFormatStringSecurityProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}} -org.eclipse.cdt.codan.internal.checkers.StatementHasNoEffectProblem=Warning -org.eclipse.cdt.codan.internal.checkers.StatementHasNoEffectProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},macro\=>true,exceptions\=>()} -org.eclipse.cdt.codan.internal.checkers.SuggestedParenthesisProblem=Warning -org.eclipse.cdt.codan.internal.checkers.SuggestedParenthesisProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},paramNot\=>false} -org.eclipse.cdt.codan.internal.checkers.SuspiciousSemicolonProblem=Warning -org.eclipse.cdt.codan.internal.checkers.SuspiciousSemicolonProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},else\=>false,afterelse\=>false} -org.eclipse.cdt.codan.internal.checkers.TypeResolutionProblem=Error -org.eclipse.cdt.codan.internal.checkers.TypeResolutionProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}} -org.eclipse.cdt.codan.internal.checkers.UnusedFunctionDeclarationProblem=Warning -org.eclipse.cdt.codan.internal.checkers.UnusedFunctionDeclarationProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},macro\=>true} -org.eclipse.cdt.codan.internal.checkers.UnusedStaticFunctionProblem=Warning -org.eclipse.cdt.codan.internal.checkers.UnusedStaticFunctionProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},macro\=>true} -org.eclipse.cdt.codan.internal.checkers.UnusedVariableDeclarationProblem=Warning -org.eclipse.cdt.codan.internal.checkers.UnusedVariableDeclarationProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},macro\=>true,exceptions\=>("@(\#)","$Id")} -org.eclipse.cdt.codan.internal.checkers.VariableResolutionProblem=Error -org.eclipse.cdt.codan.internal.checkers.VariableResolutionProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}} diff --git a/applications/vbedriver/.settings/org.eclipse.cdt.core.prefs b/applications/vbedriver/.settings/org.eclipse.cdt.core.prefs deleted file mode 100644 index 3320636e..00000000 --- a/applications/vbedriver/.settings/org.eclipse.cdt.core.prefs +++ /dev/null @@ -1,163 +0,0 @@ -eclipse.preferences.version=1 -org.eclipse.cdt.core.formatter.alignment_for_arguments_in_method_invocation=16 -org.eclipse.cdt.core.formatter.alignment_for_assignment=16 -org.eclipse.cdt.core.formatter.alignment_for_base_clause_in_type_declaration=80 -org.eclipse.cdt.core.formatter.alignment_for_binary_expression=16 -org.eclipse.cdt.core.formatter.alignment_for_compact_if=16 -org.eclipse.cdt.core.formatter.alignment_for_conditional_expression=34 -org.eclipse.cdt.core.formatter.alignment_for_conditional_expression_chain=18 -org.eclipse.cdt.core.formatter.alignment_for_constructor_initializer_list=0 -org.eclipse.cdt.core.formatter.alignment_for_declarator_list=16 -org.eclipse.cdt.core.formatter.alignment_for_enumerator_list=48 -org.eclipse.cdt.core.formatter.alignment_for_expression_list=0 -org.eclipse.cdt.core.formatter.alignment_for_expressions_in_array_initializer=16 -org.eclipse.cdt.core.formatter.alignment_for_member_access=0 -org.eclipse.cdt.core.formatter.alignment_for_overloaded_left_shift_chain=16 -org.eclipse.cdt.core.formatter.alignment_for_parameters_in_method_declaration=16 -org.eclipse.cdt.core.formatter.alignment_for_throws_clause_in_method_declaration=16 -org.eclipse.cdt.core.formatter.brace_position_for_array_initializer=end_of_line -org.eclipse.cdt.core.formatter.brace_position_for_block=end_of_line -org.eclipse.cdt.core.formatter.brace_position_for_block_in_case=end_of_line -org.eclipse.cdt.core.formatter.brace_position_for_method_declaration=end_of_line -org.eclipse.cdt.core.formatter.brace_position_for_namespace_declaration=end_of_line -org.eclipse.cdt.core.formatter.brace_position_for_switch=end_of_line -org.eclipse.cdt.core.formatter.brace_position_for_type_declaration=end_of_line -org.eclipse.cdt.core.formatter.comment.min_distance_between_code_and_line_comment=1 -org.eclipse.cdt.core.formatter.comment.never_indent_line_comments_on_first_column=true -org.eclipse.cdt.core.formatter.comment.preserve_white_space_between_code_and_line_comments=true -org.eclipse.cdt.core.formatter.compact_else_if=true -org.eclipse.cdt.core.formatter.continuation_indentation=2 -org.eclipse.cdt.core.formatter.continuation_indentation_for_array_initializer=2 -org.eclipse.cdt.core.formatter.format_guardian_clause_on_one_line=false -org.eclipse.cdt.core.formatter.indent_access_specifier_compare_to_type_header=false -org.eclipse.cdt.core.formatter.indent_access_specifier_extra_spaces=0 -org.eclipse.cdt.core.formatter.indent_body_declarations_compare_to_access_specifier=true -org.eclipse.cdt.core.formatter.indent_body_declarations_compare_to_namespace_header=false -org.eclipse.cdt.core.formatter.indent_breaks_compare_to_cases=true -org.eclipse.cdt.core.formatter.indent_declaration_compare_to_template_header=false -org.eclipse.cdt.core.formatter.indent_empty_lines=false -org.eclipse.cdt.core.formatter.indent_statements_compare_to_block=true -org.eclipse.cdt.core.formatter.indent_statements_compare_to_body=true -org.eclipse.cdt.core.formatter.indent_switchstatements_compare_to_cases=true -org.eclipse.cdt.core.formatter.indent_switchstatements_compare_to_switch=false -org.eclipse.cdt.core.formatter.indentation.size=4 -org.eclipse.cdt.core.formatter.insert_new_line_after_opening_brace_in_array_initializer=do not insert -org.eclipse.cdt.core.formatter.insert_new_line_after_template_declaration=do not insert -org.eclipse.cdt.core.formatter.insert_new_line_at_end_of_file_if_missing=do not insert -org.eclipse.cdt.core.formatter.insert_new_line_before_catch_in_try_statement=do not insert -org.eclipse.cdt.core.formatter.insert_new_line_before_closing_brace_in_array_initializer=do not insert -org.eclipse.cdt.core.formatter.insert_new_line_before_colon_in_constructor_initializer_list=do not insert -org.eclipse.cdt.core.formatter.insert_new_line_before_else_in_if_statement=do not insert -org.eclipse.cdt.core.formatter.insert_new_line_before_identifier_in_function_declaration=do not insert -org.eclipse.cdt.core.formatter.insert_new_line_before_while_in_do_statement=do not insert -org.eclipse.cdt.core.formatter.insert_new_line_in_empty_block=insert -org.eclipse.cdt.core.formatter.insert_space_after_assignment_operator=insert -org.eclipse.cdt.core.formatter.insert_space_after_binary_operator=insert -org.eclipse.cdt.core.formatter.insert_space_after_closing_angle_bracket_in_template_arguments=insert -org.eclipse.cdt.core.formatter.insert_space_after_closing_angle_bracket_in_template_parameters=insert -org.eclipse.cdt.core.formatter.insert_space_after_closing_brace_in_block=insert -org.eclipse.cdt.core.formatter.insert_space_after_closing_paren_in_cast=insert -org.eclipse.cdt.core.formatter.insert_space_after_colon_in_base_clause=insert -org.eclipse.cdt.core.formatter.insert_space_after_colon_in_case=insert -org.eclipse.cdt.core.formatter.insert_space_after_colon_in_conditional=insert -org.eclipse.cdt.core.formatter.insert_space_after_colon_in_labeled_statement=insert -org.eclipse.cdt.core.formatter.insert_space_after_comma_in_array_initializer=insert -org.eclipse.cdt.core.formatter.insert_space_after_comma_in_base_types=insert -org.eclipse.cdt.core.formatter.insert_space_after_comma_in_declarator_list=insert -org.eclipse.cdt.core.formatter.insert_space_after_comma_in_enum_declarations=insert -org.eclipse.cdt.core.formatter.insert_space_after_comma_in_expression_list=insert -org.eclipse.cdt.core.formatter.insert_space_after_comma_in_method_declaration_parameters=insert -org.eclipse.cdt.core.formatter.insert_space_after_comma_in_method_declaration_throws=insert -org.eclipse.cdt.core.formatter.insert_space_after_comma_in_method_invocation_arguments=insert -org.eclipse.cdt.core.formatter.insert_space_after_comma_in_template_arguments=insert -org.eclipse.cdt.core.formatter.insert_space_after_comma_in_template_parameters=insert -org.eclipse.cdt.core.formatter.insert_space_after_opening_angle_bracket_in_template_arguments=do not insert -org.eclipse.cdt.core.formatter.insert_space_after_opening_angle_bracket_in_template_parameters=do not insert -org.eclipse.cdt.core.formatter.insert_space_after_opening_brace_in_array_initializer=insert -org.eclipse.cdt.core.formatter.insert_space_after_opening_bracket=do not insert -org.eclipse.cdt.core.formatter.insert_space_after_opening_paren_in_cast=do not insert -org.eclipse.cdt.core.formatter.insert_space_after_opening_paren_in_catch=do not insert -org.eclipse.cdt.core.formatter.insert_space_after_opening_paren_in_exception_specification=do not insert -org.eclipse.cdt.core.formatter.insert_space_after_opening_paren_in_for=do not insert -org.eclipse.cdt.core.formatter.insert_space_after_opening_paren_in_if=do not insert -org.eclipse.cdt.core.formatter.insert_space_after_opening_paren_in_method_declaration=do not insert -org.eclipse.cdt.core.formatter.insert_space_after_opening_paren_in_method_invocation=do not insert -org.eclipse.cdt.core.formatter.insert_space_after_opening_paren_in_parenthesized_expression=do not insert -org.eclipse.cdt.core.formatter.insert_space_after_opening_paren_in_switch=do not insert -org.eclipse.cdt.core.formatter.insert_space_after_opening_paren_in_while=do not insert -org.eclipse.cdt.core.formatter.insert_space_after_postfix_operator=do not insert -org.eclipse.cdt.core.formatter.insert_space_after_prefix_operator=do not insert -org.eclipse.cdt.core.formatter.insert_space_after_question_in_conditional=insert -org.eclipse.cdt.core.formatter.insert_space_after_semicolon_in_for=insert -org.eclipse.cdt.core.formatter.insert_space_after_unary_operator=do not insert -org.eclipse.cdt.core.formatter.insert_space_before_assignment_operator=insert -org.eclipse.cdt.core.formatter.insert_space_before_binary_operator=insert -org.eclipse.cdt.core.formatter.insert_space_before_closing_angle_bracket_in_template_arguments=do not insert -org.eclipse.cdt.core.formatter.insert_space_before_closing_angle_bracket_in_template_parameters=do not insert -org.eclipse.cdt.core.formatter.insert_space_before_closing_brace_in_array_initializer=insert -org.eclipse.cdt.core.formatter.insert_space_before_closing_bracket=do not insert -org.eclipse.cdt.core.formatter.insert_space_before_closing_paren_in_cast=do not insert -org.eclipse.cdt.core.formatter.insert_space_before_closing_paren_in_catch=do not insert -org.eclipse.cdt.core.formatter.insert_space_before_closing_paren_in_exception_specification=do not insert -org.eclipse.cdt.core.formatter.insert_space_before_closing_paren_in_for=do not insert -org.eclipse.cdt.core.formatter.insert_space_before_closing_paren_in_if=do not insert -org.eclipse.cdt.core.formatter.insert_space_before_closing_paren_in_method_declaration=do not insert -org.eclipse.cdt.core.formatter.insert_space_before_closing_paren_in_method_invocation=do not insert -org.eclipse.cdt.core.formatter.insert_space_before_closing_paren_in_parenthesized_expression=do not insert -org.eclipse.cdt.core.formatter.insert_space_before_closing_paren_in_switch=do not insert -org.eclipse.cdt.core.formatter.insert_space_before_closing_paren_in_while=do not insert -org.eclipse.cdt.core.formatter.insert_space_before_colon_in_base_clause=do not insert -org.eclipse.cdt.core.formatter.insert_space_before_colon_in_case=do not insert -org.eclipse.cdt.core.formatter.insert_space_before_colon_in_conditional=insert -org.eclipse.cdt.core.formatter.insert_space_before_colon_in_default=do not insert -org.eclipse.cdt.core.formatter.insert_space_before_colon_in_labeled_statement=do not insert -org.eclipse.cdt.core.formatter.insert_space_before_comma_in_array_initializer=do not insert -org.eclipse.cdt.core.formatter.insert_space_before_comma_in_base_types=do not insert -org.eclipse.cdt.core.formatter.insert_space_before_comma_in_declarator_list=do not insert -org.eclipse.cdt.core.formatter.insert_space_before_comma_in_enum_declarations=do not insert -org.eclipse.cdt.core.formatter.insert_space_before_comma_in_expression_list=do not insert -org.eclipse.cdt.core.formatter.insert_space_before_comma_in_method_declaration_parameters=do not insert -org.eclipse.cdt.core.formatter.insert_space_before_comma_in_method_declaration_throws=do not insert -org.eclipse.cdt.core.formatter.insert_space_before_comma_in_method_invocation_arguments=do not insert -org.eclipse.cdt.core.formatter.insert_space_before_comma_in_template_arguments=do not insert -org.eclipse.cdt.core.formatter.insert_space_before_comma_in_template_parameters=do not insert -org.eclipse.cdt.core.formatter.insert_space_before_opening_angle_bracket_in_template_arguments=do not insert -org.eclipse.cdt.core.formatter.insert_space_before_opening_angle_bracket_in_template_parameters=do not insert -org.eclipse.cdt.core.formatter.insert_space_before_opening_brace_in_array_initializer=insert -org.eclipse.cdt.core.formatter.insert_space_before_opening_brace_in_block=insert -org.eclipse.cdt.core.formatter.insert_space_before_opening_brace_in_method_declaration=insert -org.eclipse.cdt.core.formatter.insert_space_before_opening_brace_in_namespace_declaration=insert -org.eclipse.cdt.core.formatter.insert_space_before_opening_brace_in_switch=insert -org.eclipse.cdt.core.formatter.insert_space_before_opening_brace_in_type_declaration=insert -org.eclipse.cdt.core.formatter.insert_space_before_opening_bracket=do not insert -org.eclipse.cdt.core.formatter.insert_space_before_opening_paren_in_catch=insert -org.eclipse.cdt.core.formatter.insert_space_before_opening_paren_in_exception_specification=insert -org.eclipse.cdt.core.formatter.insert_space_before_opening_paren_in_for=insert -org.eclipse.cdt.core.formatter.insert_space_before_opening_paren_in_if=insert -org.eclipse.cdt.core.formatter.insert_space_before_opening_paren_in_method_declaration=do not insert -org.eclipse.cdt.core.formatter.insert_space_before_opening_paren_in_method_invocation=do not insert -org.eclipse.cdt.core.formatter.insert_space_before_opening_paren_in_parenthesized_expression=do not insert -org.eclipse.cdt.core.formatter.insert_space_before_opening_paren_in_switch=insert -org.eclipse.cdt.core.formatter.insert_space_before_opening_paren_in_while=insert -org.eclipse.cdt.core.formatter.insert_space_before_postfix_operator=do not insert -org.eclipse.cdt.core.formatter.insert_space_before_prefix_operator=do not insert -org.eclipse.cdt.core.formatter.insert_space_before_question_in_conditional=insert -org.eclipse.cdt.core.formatter.insert_space_before_semicolon=do not insert -org.eclipse.cdt.core.formatter.insert_space_before_semicolon_in_for=do not insert -org.eclipse.cdt.core.formatter.insert_space_before_unary_operator=do not insert -org.eclipse.cdt.core.formatter.insert_space_between_empty_braces_in_array_initializer=do not insert -org.eclipse.cdt.core.formatter.insert_space_between_empty_brackets=do not insert -org.eclipse.cdt.core.formatter.insert_space_between_empty_parens_in_exception_specification=do not insert -org.eclipse.cdt.core.formatter.insert_space_between_empty_parens_in_method_declaration=do not insert -org.eclipse.cdt.core.formatter.insert_space_between_empty_parens_in_method_invocation=do not insert -org.eclipse.cdt.core.formatter.join_wrapped_lines=true -org.eclipse.cdt.core.formatter.keep_else_statement_on_same_line=false -org.eclipse.cdt.core.formatter.keep_empty_array_initializer_on_one_line=false -org.eclipse.cdt.core.formatter.keep_imple_if_on_one_line=false -org.eclipse.cdt.core.formatter.keep_then_statement_on_same_line=false -org.eclipse.cdt.core.formatter.lineSplit=160 -org.eclipse.cdt.core.formatter.number_of_empty_lines_to_preserve=1 -org.eclipse.cdt.core.formatter.put_empty_statement_on_new_line=true -org.eclipse.cdt.core.formatter.tabulation.char=tab -org.eclipse.cdt.core.formatter.tabulation.size=4 -org.eclipse.cdt.core.formatter.use_tabs_only_for_leading_indentations=false diff --git a/applications/vbedriver/.settings/org.eclipse.cdt.ui.prefs b/applications/vbedriver/.settings/org.eclipse.cdt.ui.prefs deleted file mode 100644 index 99dd086c..00000000 --- a/applications/vbedriver/.settings/org.eclipse.cdt.ui.prefs +++ /dev/null @@ -1,3 +0,0 @@ -eclipse.preferences.version=1 -formatter_profile=_Ghost Formatter -formatter_settings_version=1 diff --git a/applications/vbedriver/src/vbedriver.cpp b/applications/vbedriver/src/vbedriver.cpp deleted file mode 100644 index ff00af3f..00000000 --- a/applications/vbedriver/src/vbedriver.cpp +++ /dev/null @@ -1,277 +0,0 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * * - * Ghost, a micro-kernel based operating system for the x86 architecture * - * Copyright (C) 2015, Max Schlüssel * - * * - * This program 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. * - * * - * This program 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 this program. If not, see . * - * * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -#include "vbedriver.hpp" - -#include -#include - -#include -#include -#include - -g_device_id deviceId; - -int main() -{ - g_task_register_name("vbedriver"); - klog("started"); - - if(!deviceManagerRegisterDevice(G_DEVICE_TYPE_VIDEO, g_get_tid(), &deviceId)) - { - klog("failed to register device with device manager"); - return -1; - } - klog("registered VBE device %i", deviceId); - - vbeReceiveMessages(); - return 0; -} - -void vbeReceiveMessages() -{ - size_t buflen = sizeof(g_message_header) + 1024; - uint8_t buf[buflen]; - - for(;;) - { - auto status = g_receive_message(buf, buflen); - if(status != G_MESSAGE_RECEIVE_STATUS_SUCCESSFUL) - { - continue; - } - - g_message_header* header = (g_message_header*) buf; - g_video_request_header* request = (g_video_request_header*) G_MESSAGE_CONTENT(buf); - - if(request->command == G_VIDEO_COMMAND_SET_MODE) - { - vbeHandleCommandSetMode((g_video_set_mode_request*) request, header->sender, header->transaction); - } - else - { - klog("vbedriver: received unknown command %i from task %i", request->command, header->sender); - } - } -} - -void vbeHandleCommandSetMode(g_video_set_mode_request* request, g_tid requestingTaskId, - g_message_transaction requestTransaction) -{ - // create response - g_video_set_mode_response response; - - // switch video mode - g_vbe_vesa_video_info result; - uint16_t resX = request->width; - uint16_t resY = request->height; - uint8_t bpp = request->bpp; - - klog("vbedriver: attempting to set video mode to %ix%i@%i", resX, resY, bpp); - if(vbeSetVideoMode(resX, resY, bpp, result)) - { - uint32_t lfbSize = result.bytesPerScanline * result.resolutionY; - void* addressInRequestersSpace = g_share_mem(result.lfb, lfbSize, requestingTaskId); - - response.status = G_VIDEO_SET_MODE_STATUS_SUCCESS; - response.mode_info.lfb = (uint32_t) addressInRequestersSpace; - response.mode_info.resX = result.resolutionX; - response.mode_info.resY = result.resolutionY; - response.mode_info.bpp = (uint8_t) result.bpp; - response.mode_info.bpsl = (uint16_t) result.bytesPerScanline; - response.mode_info.explicit_update = false; - } - else - { - klog("vbedriver: unable to switch to video resolution %ix%i@%i", resX, resY, bpp); - response.status = G_VIDEO_SET_MODE_STATUS_FAILED; - } - - // send response - g_send_message_t(requestingTaskId, &response, sizeof(g_video_set_mode_response), requestTransaction); -} - -bool vbeSetVideoMode(uint16_t width, uint16_t height, uint8_t bpp, g_vbe_vesa_video_info& result) -{ - bool success = false; - g_vbe_info_block* vbeInfoBlock = (g_vbe_info_block*) g_lower_malloc( - VBE_INFO_BLOCK_SIZE); - - if(vm86LoadVbeInfo(vbeInfoBlock)) - { - klog("vbedriver: version %x", (uint32_t) vbeInfoBlock->version); - - g_vbe_mode_info_block* modeInfoBlock = (g_vbe_mode_info_block*) g_lower_malloc(VBE_MODE_INFO_BLOCK_SIZE); - uint32_t mode = vbeFindBestMatchingVideoMode(vbeInfoBlock, modeInfoBlock, width, height, bpp); - if(mode) - { - if(vbeApplyVideoMode(mode, modeInfoBlock, result)) - { - success = true; - } - } - g_lower_free(modeInfoBlock); - } - else - { - klog("vbedriver: failed to load basic VBE information"); - } - - g_lower_free(vbeInfoBlock); - - return success; -} - -uint32_t vbeFindBestMatchingVideoMode(g_vbe_info_block* vbeInfoBlock, g_vbe_mode_info_block* modeInfoBlock, - uint16_t width, uint16_t height, uint8_t bpp) -{ - uint32_t bestMatchingMode = 0; - uint32_t bestFoundDepthDiff = -1; - uint32_t bestFoundResolutionDiff = -1; - uint32_t wantedResolution = width * height; - - uint16_t* modes = (uint16_t*) G_FP_TO_LINEAR(vbeInfoBlock->videoModeFarPtr); - for(uint32_t i = 0;; ++i) - { - uint16_t mode = modes[i]; - if(mode == 0xFFFF) - { - break; - } - - if(!vm86LoadModeInfo(mode, modeInfoBlock)) - { - klog("vbedriver: mode %i: could not load mode info block, skipping", mode); - continue; - } - - // Must be supported by hardware - if((modeInfoBlock->modeAttributes & 0x1) != 0x1) - { - continue; - } - - // Need LFB support - if((modeInfoBlock->modeAttributes & 0x90) != 0x90) - { - continue; - } - - // Need direct color mode - if(modeInfoBlock->memoryModel != 6) - { - continue; - } - - // Check if it's matching better - uint32_t resolution = modeInfoBlock->resolutionX * modeInfoBlock->resolutionY; - uint32_t resolutionDiff = (resolution > wantedResolution) - ? (resolution - wantedResolution) - : (wantedResolution - resolution); - uint32_t depthDiff = (modeInfoBlock->bpp > bpp) ? (modeInfoBlock->bpp - bpp) : (bpp - modeInfoBlock->bpp); - - if(resolutionDiff < bestFoundResolutionDiff || ( - resolutionDiff == bestFoundResolutionDiff && depthDiff < bestFoundDepthDiff)) - { - bestMatchingMode = mode; - bestFoundDepthDiff = depthDiff; - bestFoundResolutionDiff = resolutionDiff; - - // Break on perfect match - if(depthDiff == 0 && resolutionDiff == 0) - { - break; - } - } - } - - return bestMatchingMode; -} - -bool vbeApplyVideoMode(uint32_t mode, g_vbe_mode_info_block* modeInfoBlock, g_vbe_vesa_video_info& result) -{ - klog("vbedriver: switching to video mode %i", mode); - - if(vm86SwitchVideoMode(mode) && vm86LoadModeInfo(mode, modeInfoBlock)) - { - void* area = g_map_mmio((void*) modeInfoBlock->lfbPhysicalBase, - modeInfoBlock->linBytesPerScanline * modeInfoBlock->resolutionY); - result.resolutionX = modeInfoBlock->resolutionX; - result.resolutionY = modeInfoBlock->resolutionY; - result.bpp = modeInfoBlock->bpp; - result.bytesPerScanline = modeInfoBlock->linBytesPerScanline; - result.lfb = area; - return true; - } - return false; -} - -bool vm86LoadVbeInfo(g_vbe_info_block* target) -{ - g_vm86_registers out; - g_vm86_registers in; - - g_far_pointer vbeInfoBlockFp = G_LINEAR_TO_FP((uint32_t)target); - - in.ax = 0x4F00; - in.bx = 0; - in.cx = 0; - in.dx = 0; - in.es = G_FP_SEG(vbeInfoBlockFp); - in.di = G_FP_OFF(vbeInfoBlockFp); - in.ds = 0; - in.si = 0; - - g_call_vm86(0x10, &in, &out); - - return (out.ax == 0x4F); -} - -bool vm86LoadModeInfo(uint16_t mode, g_vbe_mode_info_block* target) -{ - g_vm86_registers out; - g_vm86_registers regs; - - g_far_pointer modeInfoBlockFp = G_LINEAR_TO_FP((uint32_t)target); - - regs.ax = 0x4F01; - regs.cx = mode; - regs.es = G_FP_SEG(modeInfoBlockFp); - regs.di = G_FP_OFF(modeInfoBlockFp); - - g_call_vm86(0x10, ®s, &out); - - return (out.ax == 0x4F); -} - -bool vm86SwitchVideoMode(uint32_t mode) -{ - g_vm86_registers out; - g_vm86_registers regs; - - regs.ax = 0x4F02; - regs.bx = mode; - - regs.bx |= 0x4000; // Flat frame buffer - - g_call_vm86(0x10, ®s, &out); - - return (out.ax == 0x4F); -} diff --git a/applications/vbedriver/src/vbedriver.hpp b/applications/vbedriver/src/vbedriver.hpp deleted file mode 100644 index f674f2aa..00000000 --- a/applications/vbedriver/src/vbedriver.hpp +++ /dev/null @@ -1,158 +0,0 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * * - * Ghost, a micro-kernel based operating system for the x86 architecture * - * Copyright (C) 2015, Max Schlüssel * - * * - * This program 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. * - * * - * This program 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 this program. If not, see . * - * * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -#ifndef __VBEDRIVER__ -#define __VBEDRIVER__ - -#include - -#include -#include - -/** - * - */ -#define VBE_INFO_BLOCK_SIZE 512 -struct g_vbe_info_block -{ - // Signature should be "VESA" (0x56455341) - uint8_t signature[4]; - // For example 0x300 for VESA 3.0 - uint16_t version; - - // OEM string pointer - g_far_pointer oemStringFarPtr; - // Capability information - uint8_t capabilities[4]; - // Video modes - g_far_pointer videoModeFarPtr; - - // Size of video memory in 64KiB blocks - uint16_t memoryBlockCount; - - // OEM information - uint16_t oemSoftwareRevision; - g_far_pointer oemVendorNameStringFarPtr; - g_far_pointer oemProductNameStringFarPtr; - g_far_pointer oemProductRevisionFarPtr; -} __attribute__((packed)); - -/** - * - */ -#define VBE_MODE_INFO_BLOCK_SIZE 256 -struct g_vbe_mode_info_block -{ - // 0 - uint16_t modeAttributes; - uint8_t windowAttributesA; - uint8_t windowAttributesB; - uint16_t granularityKb; - uint16_t windowSizeKb; - uint16_t segmentA; - uint16_t segmentB; - g_far_pointer windowFunctionFarPtr; - - // 16 - uint16_t bytesPerScanline; - uint16_t resolutionX; - uint16_t resolutionY; - uint8_t charSizeX; - uint8_t charSizeY; - uint8_t planes; - uint8_t bpp; - uint8_t banks; - uint8_t memoryModel; - uint8_t bankSizeKb; - uint8_t imagePages; - uint8_t reserved0; - - // 31 - uint8_t redMaskSize; - uint8_t redFieldPosition; - uint8_t greenMaskSize; - uint8_t greenFieldPosition; - uint8_t blueMaskSize; - uint8_t blueFieldPosition; - uint8_t rsvdMaskSize; - uint8_t rsvdFieldPosition; - uint8_t directColorModeInfo; - - // 40 - uint32_t lfbPhysicalBase; - uint32_t offScreenMemOffset; - uint16_t offScreenMemSizeKb; - uint16_t linBytesPerScanline; - uint8_t bnkNumberOfImagePages; - uint8_t linNumberOfImagePages; - uint8_t linRedMaskSize; - uint8_t linRedFieldPosition; - uint8_t linGreenMaskSize; - uint8_t linGreenFieldPosition; - uint8_t linBlueMaskSize; - uint8_t linkBlueFieldPosition; - uint8_t linReservedMaskSize; - uint8_t linReservedFieldPosition; - uint32_t maxPixelClock; -} __attribute__((packed)); - -/** - * Info about the enabled video mode - */ -struct g_vbe_vesa_video_info -{ - uint32_t resolutionX; - uint32_t resolutionY; - uint8_t bpp; - uint32_t bytesPerScanline; - void *lfb; -}; - -/** - * Main loop receiving messages from other processes to do something. - */ -void vbeReceiveMessages(); - -/** - * Handles a set-mode command. - */ -void vbeHandleCommandSetMode(g_video_set_mode_request *request, g_tid requestingTaskId, g_message_transaction requestTransaction); - -/** - * Attempts to set the video mode to the specified parameters. - */ -bool vbeSetVideoMode(uint16_t width, uint16_t wantedHeight, uint8_t wantedBpp, g_vbe_vesa_video_info &result); - -/** - * Checks all existing video modes to find the best matching video mode. - */ -uint32_t vbeFindBestMatchingVideoMode(g_vbe_info_block *vbeInfoBlock, g_vbe_mode_info_block *modeInfoBlock, - uint16_t width, uint16_t height, uint8_t bpp); - -/** - * Switches to a given video mode. - */ -bool vbeApplyVideoMode(uint32_t mode, g_vbe_mode_info_block *modeInfoBlock, g_vbe_vesa_video_info &result); - -bool vm86LoadVbeInfo(g_vbe_info_block *target); -bool vm86LoadModeInfo(uint16_t mode, g_vbe_mode_info_block *target); -bool vm86SwitchVideoMode(uint32_t mode); - -#endif diff --git a/applications/vmsvgadriver/src/svga.hpp b/applications/vmsvgadriver/src/svga.hpp index b56e539d..778f7b9e 100644 --- a/applications/vmsvgadriver/src/svga.hpp +++ b/applications/vmsvgadriver/src/svga.hpp @@ -27,8 +27,8 @@ struct svga_device_t { uint32_t versionId = SVGA_ID_2; - uint32_t ioBase = 0; - uint32_t vramSize = 0; + g_address ioBase = 0; + g_size vramSize = 0; struct { diff --git a/applications/vmsvgadriver/src/vmsvgadriver.cpp b/applications/vmsvgadriver/src/vmsvgadriver.cpp index 80f1de52..3a89bf9b 100644 --- a/applications/vmsvgadriver/src/vmsvgadriver.cpp +++ b/applications/vmsvgadriver/src/vmsvgadriver.cpp @@ -80,10 +80,10 @@ void vmsvgaDriverReceiveMessages() void* addressInRequestersSpace = g_share_mem(svgaGetFb(), svgaGetFbSize(), header->sender); response.status = G_VIDEO_SET_MODE_STATUS_SUCCESS; - response.mode_info.lfb = (uint32_t) addressInRequestersSpace; + response.mode_info.lfb = (g_address) addressInRequestersSpace; response.mode_info.resX = modeSetRequest->width; // TODO read back from SVGA registers response.mode_info.resY = modeSetRequest->height; - response.mode_info.bpp = (uint8_t) modeSetRequest->bpp; + response.mode_info.bpp = modeSetRequest->bpp; response.mode_info.bpsl = (uint16_t) (modeSetRequest->width * 4); // TODO response.mode_info.explicit_update = true; } diff --git a/build.sh b/build.sh index 68a01f27..39f16eb7 100755 --- a/build.sh +++ b/build.sh @@ -25,6 +25,9 @@ APPS_ALL=0 EVERYTHING=1 +# Targets +requireTool mtools + # Define some helpers pushd() { command pushd "$@" >/dev/null @@ -85,7 +88,27 @@ backspace_len() { printf "%0.s\b" $(seq 1 $@) } -# Targets +# Build limine if required +verify_limine() { + pushd target + + # TODO: Maybe move this all to toolchain setup + if [ ! -d "limine-$LIMINE_VERSION" ]; then + print_name "limine-prepare" + printf "\n" + curl "$LIMINE_SOURCE" -k -o "limine-$LIMINE_VERSION.tar.gz" + tar -xf "limine-$LIMINE_VERSION.tar.gz" + pushd "limine-$LIMINE_VERSION" + ./configure --enable-bios-cd --enable-uefi-cd + make + popd + fi + + cp "limine-$LIMINE_VERSION/limine.h" "$SYSROOT/system/include/limine.h" + + popd +} + build_ports() { pushd patches/ports @@ -281,6 +304,9 @@ if [ ! -f "$SYSROOT/system/lib/libgcc_s.so.1" ]; then FIRST_RUN=1 fi +# Always check limine +verify_limine + # Parse arguments NEXT_ARGS_APPS=0 for var in "$@"; do diff --git a/docker-build-toolchain-image.sh b/docker-build-toolchain-image.sh index 7ae763f2..d6e4103c 100755 --- a/docker-build-toolchain-image.sh +++ b/docker-build-toolchain-image.sh @@ -8,12 +8,12 @@ echo "Building toolchain within Docker container..." docker run --name ghost-toolchain-setup -v "$(pwd):/ghost/source" ubuntu:latest /ghost/source/docker-prepare.sh >>ghost-build.log 2>&1 echo "Committing image..." -docker commit --change='WORKDIR /ghost/source' --change='CMD ["/bin/bash"]' ghost-toolchain-setup ghost-toolchain +docker commit --change='WORKDIR /ghost/source' --change='CMD ["/bin/bash"]' ghost-toolchain-setup ghost-toolchain-64 echo "Removing temporary container..." docker rm ghost-toolchain-setup echo "Starting toolchain container now!" echo "To build the operating system, run within container: ./build.sh" -echo "After exiting, you can join it again with: docker exec -it ghost-toolchain bash" -docker run -it --name ghost-toolchain -v "$(pwd):/ghost/source" ghost-toolchain +echo "After exiting, you can join it again with: docker exec -it ghost-toolchain-64 bash" +docker run -it --name ghost-toolchain-64 -v "$(pwd):/ghost/source" ghost-toolchain-64 diff --git a/docker-prepare.sh b/docker-prepare.sh index 6433610b..30b85c97 100755 --- a/docker-prepare.sh +++ b/docker-prepare.sh @@ -17,6 +17,7 @@ apt-get install -y \ autoconf2.69 pkg-config xorriso grub-pc-bin \ make texinfo flex bison gcc g++ nasm \ asciidoc asciidoctor \ + mtools \ patch curl # Clean up diff --git a/ghost.sh b/ghost.sh index 04bc6855..ac3ef83d 100755 --- a/ghost.sh +++ b/ghost.sh @@ -145,13 +145,16 @@ popd () { # Global variables -with TARGET "i686-ghost" +with TARGET "x86_64-ghost" with CROSS_CC $TARGET"-gcc" with CROSS_CXX $TARGET"-g++" with CROSS_LD $TARGET"-ld" with CROSS_GAS $TARGET"-as" with CROSS_AR $TARGET"-ar" +# Limine +with LIMINE_VERSION "9.2.0" +with LIMINE_SOURCE "https://ghostkernel.org/repository/limine/limine-$LIMINE_VERSION.tar.gz" # Target architecture __TARGET_ARCH_PART=${TARGET%-*} diff --git a/kernel/build.sh b/kernel/build.sh index a8172166..5f29bbeb 100644 --- a/kernel/build.sh +++ b/kernel/build.sh @@ -15,7 +15,6 @@ with TARGET "all" INC=inc BIN=bin SRC=src -SRC_LOADER=$SRC/loader SRC_KERNEL=$SRC/kernel SRC_SHARED=$SRC/shared @@ -23,22 +22,19 @@ SRC_SHARED=$SRC/shared # Compiler flags # LDFLAGS="-nostdlib -nostartfiles" -CFLAGS="-std=c++11 -D_GHOST_KERNEL_=1 -Wall -Wno-unused-but-set-variable -ffreestanding -fno-exceptions -fno-rtti" +CFLAGS="-mcmodel=large -mno-sse -mno-sse2 -mno-mmx -mno-avx -mno-red-zone -std=c++11 -D_GHOST_KERNEL_=1 -Wall -Wno-unused-but-set-variable -ffreestanding -fno-exceptions -fno-rtti" # # Object output folders # OBJ_SHARED=$BIN/obj-shared -OBJ_LOADER=$BIN/obj-loader OBJ_KERNEL=$BIN/obj-kernel # # Generated artifacts & linker scripts # -ARTIFACT_LOADER=loader ARTIFACT_KERNEL=kernel -LINKSCRIPT_LOADER=extra/link-loader.ld LINKSCRIPT_KERNEL=extra/link-kernel.ld @@ -59,11 +55,9 @@ target_headline $TARGET target_clean() { headline "cleaning" - remove $ARTIFACT_LOADER remove $ARTIFACT_KERNEL cleanDirectory $BIN cleanDirectory $OBJ_SHARED - cleanDirectory $OBJ_LOADER cleanDirectory $OBJ_KERNEL changes --clear } @@ -76,7 +70,7 @@ target_compile_ap_startup() { $NASM -f bin -o "$AP_STARTUP_OBJ" -s "$AP_STARTUP_SRC" failOnError - mv "$AP_STARTUP_OBJ" "$AP_STARTUP_TGT" + cp "$AP_STARTUP_OBJ" "$AP_STARTUP_TGT" list $AP_STARTUP_OBJ } @@ -122,7 +116,7 @@ target_compile() { if ( [ $headers_have_changed -eq 1 ] || [ $changed -eq 1 ] ); then out=`sourceToObject $file` list $out - $NASM -f elf -s $file -o "$objdir/$out" + $NASM -f elf64 -s $file -o "$objdir/$out" failOnError changes -s $file fi @@ -138,7 +132,8 @@ target_link() { script=$2 objects=$3 headline "linking $artifact" - + + echo $CROSS_LD $LD_FLAGS -o $artifact -T $script $objects $CROSS_LD $LD_FLAGS -o $artifact -T $script $objects failOnError } @@ -149,9 +144,7 @@ target_link() { target_all() { target_compile_ap_startup target_compile $SRC_SHARED $OBJ_SHARED "-I$INC -I$SRC" - target_compile $SRC_LOADER $OBJ_LOADER "-I$INC -I$SRC" target_compile $SRC_KERNEL $OBJ_KERNEL "-I$INC -I$SRC" - target_link $ARTIFACT_LOADER $LINKSCRIPT_LOADER "$OBJ_LOADER/* $OBJ_SHARED/*" target_link $ARTIFACT_KERNEL $LINKSCRIPT_KERNEL "$OBJ_KERNEL/* $OBJ_SHARED/*" } diff --git a/kernel/extra/link-kernel.ld b/kernel/extra/link-kernel.ld index 5c2b29e8..6c4a4f94 100644 --- a/kernel/extra/link-kernel.ld +++ b/kernel/extra/link-kernel.ld @@ -1,47 +1,50 @@ -ENTRY (kernelMain) +OUTPUT_FORMAT(elf64-x86-64) + +ENTRY(kernelMain) + +PHDRS +{ + limine_requests PT_LOAD; + text PT_LOAD; + rodata PT_LOAD; + data PT_LOAD; +} SECTIONS { - /* Start at this address*/ - . = 0xC0000000; - - /* Text section */ - textSectionStart = .; - .text BLOCK(4K) : ALIGN(4K) - { - *(.text) - } - textSectionEnd = .; - - /* Read-only section */ - rodataSectionStart = .; - .rodata BLOCK(4K) : ALIGN(4K) - { - startConstructors = .; - *(SORT(.ctors*)) - endConstructors = .; - - *(.rodata) - } - rodataSectionEnd = .; - - /* Data section */ - dataSectionStart = .; - .data BLOCK(4K) : ALIGN(4K) - { - *(.data) - } - dataSectionEnd = .; - - /* BSS section */ - bssSectionStart = .; - .bss BLOCK(4K) : ALIGN(4K) - { - *(COMMON) - *(.bss) - } - bssSectionEnd = .; - - /* Align the end of the kernel to 0x1000 */ - endKernel = ALIGN(4K); + . = 0xffffffff80000000; + + .limine_requests : { + KEEP(*(.limine_requests_start)) + KEEP(*(.limine_requests)) + KEEP(*(.limine_requests_end)) + } :limine_requests + + . = ALIGN(CONSTANT(MAXPAGESIZE)); + + .text : { + *(.text .text.*) + } :text + + . = ALIGN(CONSTANT(MAXPAGESIZE)); + + .rodata : { + *(.rodata .rodata.*) + } :rodata + + . = ALIGN(CONSTANT(MAXPAGESIZE)); + + .data : { + *(.data .data.*) + } :data + + .bss : { + *(.bss .bss.*) + *(COMMON) + } :data + + /DISCARD/ : { + *(.eh_frame*) + *(.note .note.*) + } } \ No newline at end of file diff --git a/kernel/extra/link-loader.ld b/kernel/extra/link-loader.ld deleted file mode 100644 index 75b6bfde..00000000 --- a/kernel/extra/link-loader.ld +++ /dev/null @@ -1,53 +0,0 @@ -ENTRY (loaderEntry) - -SECTIONS -{ - /* Start at this address*/ - . = 0x100000; - - /* Multiboot section */ - .multiboot BLOCK(4K) : ALIGN(4K) - { - *(.multiboot) - } - - /* Text section */ - textSectionStart = .; - .text BLOCK(4K) : ALIGN(4K) - { - *(.text) - } - textSectionEnd = .; - - /* Read-only section */ - rodataSectionStart = .; - .rodata BLOCK(4K) : ALIGN(4K) - { - startConstructors = .; - *(SORT(.ctors*)) - endConstructors = .; - - *(.rodata) - } - rodataSectionEnd = .; - - /* Data section */ - dataSectionStart = .; - .data BLOCK(4K) : ALIGN(4K) - { - *(.data) - } - dataSectionEnd = .; - - /* BSS section */ - bssSectionStart = .; - .bss BLOCK(4K) : ALIGN(4K) - { - *(COMMON) - *(.bss) - } - bssSectionEnd = .; - - /* Align the end of the loader to 0x1000 */ - endAddress = ALIGN(4K); -} \ No newline at end of file diff --git a/kernel/inc/build_config.hpp b/kernel/inc/build_config.hpp index 8af0c898..15fabb3f 100644 --- a/kernel/inc/build_config.hpp +++ b/kernel/inc/build_config.hpp @@ -32,8 +32,8 @@ #endif // pretty boot -#define G_PRETTY_BOOT true -#define G_VIDEO_LOG_BOOT false +#define G_PRETTY_BOOT false +#define G_VIDEO_LOG_BOOT true // logging settings #define G_LOG_LEVEL G_LOG_LEVEL_INFO @@ -45,6 +45,9 @@ // mode for the debug interface #define G_DEBUG_INTERFACE_MODE G_DEBUG_INTERFACE_MODE_PLAIN_LOG +// whether SMP should be used +#define G_SMP_ENABLED true + // version #define G_VERSION_MAJOR 0 #define G_VERSION_MINOR 25 diff --git a/kernel/src/shared/memory/gdt.cpp b/kernel/inc/shared/boot/limine.hpp similarity index 76% rename from kernel/src/shared/memory/gdt.cpp rename to kernel/inc/shared/boot/limine.hpp index af86b0fa..8ab68013 100644 --- a/kernel/src/shared/memory/gdt.cpp +++ b/kernel/inc/shared/boot/limine.hpp @@ -18,18 +18,22 @@ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ -#include "shared/memory/gdt.hpp" +#ifndef __BOOT_LIMINE__ +#define __BOOT_LIMINE__ -void gdtCreateGate(g_gdt_entry* entry, uint32_t base, uint32_t limit, uint8_t access, uint8_t granularity) -{ - entry->baseLow = (base & 0xFFFF); - entry->baseMiddle = (base >> 16) & 0xFF; - entry->baseHigh = (base >> 24) & 0xFF; +#include - entry->limitLow = (limit & 0xFFFF); - entry->limitHigh = limit >> 16; +/** + * Looks for the module with the given path. + * + * @param info bootloader information structure + * @param path module path + * @return the file or null + */ +limine_file* limineFindModule(limine_module_response* info, const char* path); - entry->granularity = granularity; +void limineStoreFramebuffer(limine_framebuffer* framebuffer); - entry->access = access; -} +limine_framebuffer* limineGetFramebuffer(); + +#endif diff --git a/kernel/inc/shared/logger/logger.hpp b/kernel/inc/shared/logger/logger.hpp index 42ad6c16..b8498ce7 100644 --- a/kernel/inc/shared/logger/logger.hpp +++ b/kernel/inc/shared/logger/logger.hpp @@ -73,6 +73,6 @@ void loggerPrintFormatted(const char *message, va_list va); * - if the base is 10 then signs are added * - if the base is 16 a preceding '0x' is added */ -void loggerPrintNumber(uint32_t number, uint16_t base); +void loggerPrintNumber(uint64_t number, uint16_t base, bool shortened); #endif diff --git a/kernel/inc/shared/memory/bitmap.hpp b/kernel/inc/shared/memory/bitmap.hpp deleted file mode 100644 index c1fa4e69..00000000 --- a/kernel/inc/shared/memory/bitmap.hpp +++ /dev/null @@ -1,90 +0,0 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * * - * Ghost, a micro-kernel based operating system for the x86 architecture * - * Copyright (C) 2015, Max Schlüssel * - * * - * This program 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. * - * * - * This program 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 this program. If not, see . * - * * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -#ifndef __BITMAP__ -#define __BITMAP__ - -#include "shared/memory/paging.hpp" -#include "shared/system/mutex.hpp" - -/** - * When creating the bitmap array, this controls how large the maximum physical - * memory area can be that a single bitmap maintains. - */ -#define G_BITMAP_MAX_RANGE 0x05000000 - -/** - * One bitmap entry, each bit representing one page. - */ -typedef uint8_t g_bitmap_entry; - -/** - * A bitmap stores information about a number of free pages, starting from the - * base address. In memory, there are multiple bitmaps following each other, - * the "hasNext" flag indicating whether there is another one. - * - * ...[g_bitmap_header][g_bitmap_entry][g_bitmap_entry]...[g_bitmap_header]][g_bitmap_entry]... - * - * There can be no pointers within these structures, since the kernel maps the - * bitmap to its own area in the virtual space before unmapping the setup memory. - */ -typedef struct -{ - g_physical_address baseAddress; - uint32_t entryCount; - bool hasNext; - g_mutex lock; - uint32_t firstFree; -} __attribute__((packed)) g_bitmap_header; - -/** - * Number of pages each entry contains. - */ -#define G_BITMAP_PAGES_PER_ENTRY (sizeof(g_bitmap_entry) * 8) - -/** - * @returns the next bitmap of the given bitmap, if the "hasNext" flag indicates - * the presence of this bitmap. Offset is calculated by the amount of - * following s - */ -#define G_BITMAP_NEXT_UNCHECKED(bitmap) ((g_bitmap_header*) (((g_address) (bitmap)) + sizeof(g_bitmap_header) + (bitmap->entryCount * sizeof(g_bitmap_entry)))) -#define G_BITMAP_NEXT(bitmap) (bitmap->hasNext ? G_BITMAP_NEXT_UNCHECKED(bitmap) : nullptr) - -/** - * @returns a pointer to the entries of this bitmap - */ -#define G_BITMAP_ENTRIES(bitmap) ((g_bitmap_entry*) (((g_address) bitmap) + sizeof(g_bitmap_header))) - -/** - * Calculates the index relative to an offset and vice-versa. - */ -#define G_OFFSET_TO_BITMAP_INDEX(address) ((address / G_PAGE_SIZE) / G_BITMAP_PAGES_PER_ENTRY) -#define G_OFFSET_TO_BITMAP_BIT(address) ((address / G_PAGE_SIZE) % G_BITMAP_PAGES_PER_ENTRY) -#define G_BITMAP_TO_OFFSET(index, bit) ((index * G_BITMAP_PAGES_PER_ENTRY * G_PAGE_SIZE) + (bit * G_PAGE_SIZE)) - -/** - * Checks whether a bit is set or sets/unsets it. - */ -#define G_BITMAP_IS_SET(bitmap, index, bit) (G_BITMAP_ENTRIES(bitmap)[index] & (1 << bit)) -#define G_BITMAP_SET(bitmap, index, bit) (G_BITMAP_ENTRIES(bitmap)[index] |= (1 << bit)) -#define G_BITMAP_UNSET(bitmap, index, bit) (G_BITMAP_ENTRIES(bitmap)[index] &= ~(1 << bit)) -#define G_BITMAP_ENTRY_FULL 0xFFFFFFFF - -#endif diff --git a/kernel/inc/shared/memory/bitmap_page_allocator.hpp b/kernel/inc/shared/memory/bitmap_page_allocator.hpp index c7b983ea..d33a98cc 100644 --- a/kernel/inc/shared/memory/bitmap_page_allocator.hpp +++ b/kernel/inc/shared/memory/bitmap_page_allocator.hpp @@ -1,7 +1,7 @@ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Ghost, a micro-kernel based operating system for the x86 architecture * - * Copyright (C) 2015, Max Schlüssel * + * Copyright (C) 2025, Max Schlüssel * * * * This program is free software: you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * @@ -21,16 +21,54 @@ #ifndef __BITMAP_PAGE_ALLOCATOR__ #define __BITMAP_PAGE_ALLOCATOR__ -#include "shared/memory/bitmap.hpp" +#include "shared/memory/paging.hpp" +#include "shared/system/mutex.hpp" +#include #include #define G_BITMAP_ALLOCATOR_FASTBUFFER_SIZE 128 +#define G_BITMAP_ENTRY_TYPE uint64_t +#define G_BITMAP_BITS_PER_ENTRY (sizeof(G_BITMAP_ENTRY_TYPE) * 8) + +struct g_bitmap_header; + +/** + * Header of each bitmap index page. The bitmap index page is the top-level + * structure that keeps track of a list of bitmaps. + */ +struct g_bitmap_index_page_header +{ + g_bitmap_index_page_header* next; + g_bitmap_header* entries[]; +}__attribute__((packed)); + +#define G_BITMAP_INDEX_MAX_ENTRIES ((G_PAGE_SIZE - offsetof(g_bitmap_index_page_header, entries)) / sizeof(g_bitmap_index_page_header)) + +/** + * Header of a single bitmap. The entries are the actual bitmap and each address + * is calculated by the base plus total bit index multiplied by page size. + */ +struct g_bitmap_header +{ + g_physical_address base; + g_physical_address end; + g_mutex lock; + G_BITMAP_ENTRY_TYPE entries[]; +}__attribute__((packed)); + +#define G_BITMAP_MAX_ENTRIES ((G_PAGE_SIZE - offsetof(g_bitmap_header, entries)) / sizeof(G_BITMAP_ENTRY_TYPE)) +#define G_BITMAP_TOTAL_BITS (G_BITMAP_MAX_ENTRIES * 8) + +/** + * Allocator structure + */ struct g_bitmap_page_allocator { + g_mutex lock; uint32_t freePageCount; - g_bitmap_header* bitmapArray; + g_bitmap_index_page_header* indexPage; struct { @@ -41,14 +79,9 @@ struct g_bitmap_page_allocator }; /** - * Initializes the allocator in-place; the bitmap array is used as it is. - */ -void bitmapPageAllocatorInitialize(g_bitmap_page_allocator* allocator, g_bitmap_header* bitmapArray); - -/** - * Changes the address of the bitmap array used by the bitmap allocator to the new address. + * Initializes the bitmap page allocator. */ -void bitmapPageAllocatorRelocate(g_bitmap_page_allocator* allocator, g_virtual_address newBitmapArray); +void bitmapPageAllocatorInitialize(g_bitmap_page_allocator* allocator, limine_memmap_response* memoryMap); void bitmapPageAllocatorMarkFree(g_bitmap_page_allocator* allocator, g_physical_address address); diff --git a/kernel/inc/shared/memory/constants.hpp b/kernel/inc/shared/memory/constants.hpp index 3d629188..20de389f 100644 --- a/kernel/inc/shared/memory/constants.hpp +++ b/kernel/inc/shared/memory/constants.hpp @@ -21,32 +21,38 @@ #ifndef __MEMORY_CONSTANTS__ #define __MEMORY_CONSTANTS__ -#define G_SMP_STARTUP_AREA 0x00000500 -#define G_SMP_STARTUP_AREA_PAGEDIR 0x00000500 // initial page directory address is put here -#define G_SMP_STARTUP_AREA_AP_ENTRY 0x00000504 // kernel entry point for AP -#define G_SMP_STARTUP_AREA_AP_COUNTER 0x00000508 // counter for stack array indexing -#define G_SMP_STARTUP_AREA_AP_STACK_ARRAY 0x0000050C // array of stacks -#define G_SMP_STARTUP_AREA_CODE_START 0x00001000 // must be 000XX000, used for SIPI -#define G_SMP_STARTUP_AREA_END 0x00007BFF - -#define G_LOWER_HEAP_MEMORY_START 0x00007E00 // area used by the lower memory allocator -#define G_LOWER_HEAP_MEMORY_END 0x000CFFFF // for vm86 and other 16bit stuff -#define G_LOWER_MEMORY_END 0x00100000 - +#define G_SMP_STARTUP_AREA 0x500 +#define G_SMP_STARTUP_AREA_PAGEDIR 0x500 // initial page directory address is put here +#define G_SMP_STARTUP_AREA_AP_ENTRY 0x508 // kernel entry point for AP +#define G_SMP_STARTUP_AREA_AP_COUNTER 0x510 // counter for stack pointer array indexing +#define G_SMP_STARTUP_AREA_AP_STACK_ARRAY 0x518 // array of stack pointers +#define G_SMP_STARTUP_AREA_CODE_START 0x1000 // must be 000XX000, used for SIPI +#define G_SMP_STARTUP_AREA_END 0x7BFF + +// TODO change values #define G_USER_MAXIMUM_HEAP_BREAK 0xA0000000 #define G_USER_VIRTUAL_RANGES_START 0xA0000000 #define G_USER_VIRTUAL_RANGES_END 0xC0000000 #define G_KERNEL_AREA_START 0xC0000000 -#define G_KERNEL_HEAP_INIT_SIZE 0x01000000 -#define G_KERNEL_HEAP_EXPAND_STEP 0x00100000 -#define G_KERNEL_HEAP_END 0xF0000000 -#define G_KERNEL_VIRTUAL_RANGES_START 0xF0000000 -#define G_KERNEL_VIRTUAL_RANGES_END 0xFFC00000 -#define G_RECURSIVE_PAGE_DIRECTORY_AREA 0xFFC00000 -#define G_RECURSIVE_PAGE_DIRECTORY_ADDRESS 0xFFFFF000 -#define G_RECURSIVE_PAGE_TABLE(ti) (((g_page_table) G_RECURSIVE_PAGE_DIRECTORY_AREA) + (0x400 * ti)) +// TODO new constants +#define G_MEM_LOWER_END 0x100000 +#define G_MEM_LOWER_HALF_END 0x7fffffffffff + +/** + * Due to the Higher Half Direct Map feature, every physical address is mapped + * to this higher-half offset in virtual memory by default. + */ +#define G_MEM_HIGHER_HALF_DIRECT_MAP_OFFSET 0xffff800000000000 +#define G_MEM_PHYS_TO_VIRT(phys) ((G_MEM_HIGHER_HALF_DIRECT_MAP_OFFSET) + (g_address) phys) + +#define G_MEM_KERN_VIRT_RANGES_START 0xffffff8090000000 +#define G_MEM_KERN_VIRT_RANGES_END 0xffffff89ffc00000 +#define G_MEM_HEAP_START 0xffffff8a00000000 +#define G_MEM_HEAP_INITIAL_SIZE 0x100000 +#define G_MEM_KERN_HEAP_EXPAND_STEP 0x100000 + #endif diff --git a/kernel/inc/shared/memory/gdt.hpp b/kernel/inc/shared/memory/gdt.hpp deleted file mode 100644 index f6a6e63e..00000000 --- a/kernel/inc/shared/memory/gdt.hpp +++ /dev/null @@ -1,71 +0,0 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * * - * Ghost, a micro-kernel based operating system for the x86 architecture * - * Copyright (C) 2015, Max Schlüssel * - * * - * This program 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. * - * * - * This program 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 this program. If not, see . * - * * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -#ifndef __GDT__ -#define __GDT__ - -#include -#include "shared/memory/gdt_macros.hpp" - -/** - * Structure of a GDT entry - */ -struct g_gdt_entry -{ - uint16_t limitLow : 16; - uint16_t baseLow : 16; - uint8_t baseMiddle : 8; - uint8_t access : 8; - uint16_t limitHigh : 4; - uint8_t granularity : 4; - uint8_t baseHigh : 8; -} __attribute__((packed)); - -/** - * Structure of the GDT pointer - */ -struct g_gdt_pointer -{ - uint16_t limit; - uint32_t base; -} __attribute__((packed)); - -/** - * Fills the given GDTEntry with the given data. - * - * @param gdtEntry the target GDT entry - * @param base the base address to write - * @param limit the limit to write - * @param access the access flag to write - * @param granularity the granularity to write - */ -void gdtCreateGate(g_gdt_entry* gdtEntry, uint32_t base, uint32_t limit, uint8_t access, uint8_t granularity); - -/** - * Loads the GDT using the GDT pointer structure at the given address. - */ -extern "C" void _loadGdt(uint32_t gdtPointerAddress); - -/** - * Loads the TSS at the given descriptor index. - */ -extern "C" void _loadTss(uint16_t tssDescriptorIndex); - -#endif diff --git a/kernel/inc/shared/memory/gdt_macros.hpp b/kernel/inc/shared/memory/gdt_macros.hpp deleted file mode 100644 index e4d7824b..00000000 --- a/kernel/inc/shared/memory/gdt_macros.hpp +++ /dev/null @@ -1,83 +0,0 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * * - * Ghost, a micro-kernel based operating system for the x86 architecture * - * Copyright (C) 2015, Max Schlüssel * - * * - * This program 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. * - * * - * This program 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 this program. If not, see . * - * * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -#ifndef __GDT_MACROS__ -#define __GDT_MACROS__ - -/** - * Macro to create the ACCESS byte for a GDT entry to a code or data segment - * - * Parameters: - * readWrite if code read allowed, if data write allowed - * codeOrData determines if its a code (1) or a data (0) segment - * privilege Privilege level (Ring 0 - Ring 3) - * present 1 if present - * - * Bits: Values: Info: - * 0 0 Accessed bit, free for developers use - * 1 parameter readWrite read if code segment, or write if data segment - * 2 0 Direction bit or conforming bit) - * 3 parameter codeOrData Entry is a code (1) or data (0) segment - * 4 0 Entry is for Code/Data (1) or Gate/TSS (0) - * 5 - 6 parameter privilege Ring 0 - Ring 3 - * 7 parameter present Must be 1 for active entry - */ -#define G_ACCESS_BYTE__FOR__CODE_OR_DATA(readWrite, codeOrData, privilege, present) \ - (0 | (readWrite << 1) | (0 << 2) | (codeOrData << 3) | (1 << 4) | (privilege << 5) | (present << 7)) - -/** - * Macro to create the ACCESS byte for a GDT entry to a Gate/TSS - * - * Parameters: - * segmentType e.g. 0x9 for 386-TSS - * privilege Privilege level (Ring 0 - Ring 3) - * present 1 if present - * - * Bits: Values: Info: - * 0 - 3 parameter segmentType Segment type - * 4 0 Entry is for Code/Data (1) or Gate/TSS (0) - * 5 - 6 parameter privilege Ring 0 - Ring 3 - * 7 parameter present Must be 1 for active entry - */ -#define G_ACCESS_BYTE__FOR__GATE_OR_TSS(segmentType, privilege, present) \ - (segmentType | (0 << 4) | (privilege << 5) | (present << 7)) - -/** - * Common descriptor access flags - */ -#define G_ACCESS_BYTE__KERNEL_CODE_SEGMENT G_ACCESS_BYTE__FOR__CODE_OR_DATA(1, 1, 0, 1) -#define G_ACCESS_BYTE__KERNEL_DATA_SEGMENT G_ACCESS_BYTE__FOR__CODE_OR_DATA(1, 0, 0, 1) -#define G_ACCESS_BYTE__USER_CODE_SEGMENT G_ACCESS_BYTE__FOR__CODE_OR_DATA(1, 1, 3, 1) -#define G_ACCESS_BYTE__USER_DATA_SEGMENT G_ACCESS_BYTE__FOR__CODE_OR_DATA(1, 0, 3, 1) -#define G_ACCESS_BYTE__TSS_386_SEGMENT G_ACCESS_BYTE__FOR__GATE_OR_TSS(0x9, 0, 1) - -// Descriptor index constants -#define G_GDT_DESCRIPTOR_KERNEL_CODE 0x08 -#define G_GDT_DESCRIPTOR_KERNEL_DATA 0x10 -#define G_GDT_DESCRIPTOR_USER_CODE 0x18 -#define G_GDT_DESCRIPTOR_USER_DATA 0x20 -#define G_GDT_DESCRIPTOR_TSS 0x28 -#define G_GDT_DESCRIPTOR_USERTHREADLOCAL 0x30 -#define G_GDT_DESCRIPTOR_KERNELTHREADLOCAL 0x38 - -#define G_SEGMENT_SELECTOR_RING0 0 // 00 -#define G_SEGMENT_SELECTOR_RING3 3 // 11 - -#endif diff --git a/kernel/inc/shared/memory/paging.hpp b/kernel/inc/shared/memory/paging.hpp index f262011c..e20a9d56 100644 --- a/kernel/inc/shared/memory/paging.hpp +++ b/kernel/inc/shared/memory/paging.hpp @@ -24,38 +24,34 @@ #include #include -#define G_PAGE_TABLE_PRESENT (1) -#define G_PAGE_TABLE_READWRITE (1 << 1) -#define G_PAGE_TABLE_USERSPACE (1 << 2) -#define G_PAGE_TABLE_WRITETHROUGH (1 << 3) -#define G_PAGE_TABLE_CACHE_DISABLED (1 << 4) -#define G_PAGE_TABLE_ACCESSED (1 << 5) -#define G_PAGE_TABLE_SIZE (1 << 6) - -#define G_PAGE_PRESENT (1) -#define G_PAGE_READWRITE (1 << 1) -#define G_PAGE_USERSPACE (1 << 2) -#define G_PAGE_WRITETHROUGH (1 << 3) -#define G_PAGE_CACHE_DISABLED (1 << 4) -#define G_PAGE_ACCESSED (1 << 5) -#define G_PAGE_DIRTY (1 << 6) -#define G_PAGE_GLOBAL (1 << 7) +#define G_PAGE_PRESENT (1ULL << 0) // Page is present +#define G_PAGE_WRITABLE_FLAG (1ULL << 1) // Page is writable +#define G_PAGE_USER_FLAG (1ULL << 2) // Page is accessible from user mode +#define G_PAGE_WRITE_THROUGH (1ULL << 3) // Write-through caching +#define G_PAGE_CACHE_DISABLE (1ULL << 4) // Disable caching +#define G_PAGE_ACCESSED_FLAG (1ULL << 5) // Page has been accessed +#define G_PAGE_DIRTY_FLAG (1ULL << 6) // Page has been written to (only for PT entries) +#define G_PAGE_LARGE_PAGE_FLAG (1ULL << 7) // Page is a large page (2MB or 1GB) +#define G_PAGE_GLOBAL_FLAG (1ULL << 8) // Page is global (only for PT entries) +#define G_PAGE_NX_FLAG (1ULL << 63) // No-execute flag (if supported) /** * Default flag definitions */ -#define G_PAGE_TABLE_KERNEL_DEFAULT (G_PAGE_TABLE_PRESENT | G_PAGE_TABLE_READWRITE) -#define G_PAGE_TABLE_USER_DEFAULT (G_PAGE_TABLE_PRESENT | G_PAGE_TABLE_READWRITE | G_PAGE_TABLE_USERSPACE) +#define G_PAGE_TABLE_KERNEL_DEFAULT (G_PAGE_PRESENT | G_PAGE_WRITABLE_FLAG) +#define G_PAGE_TABLE_USER_DEFAULT (G_PAGE_PRESENT | G_PAGE_WRITABLE_FLAG | G_PAGE_USER_FLAG) -#define G_PAGE_KERNEL_DEFAULT (G_PAGE_PRESENT | G_PAGE_READWRITE | G_PAGE_GLOBAL) -#define G_PAGE_KERNEL_UNCACHED (G_PAGE_KERNEL_DEFAULT | G_PAGE_CACHE_DISABLED) -#define G_PAGE_USER_DEFAULT (G_PAGE_PRESENT | G_PAGE_READWRITE | G_PAGE_USERSPACE) +#define G_PAGE_KERNEL_DEFAULT (G_PAGE_PRESENT | G_PAGE_WRITABLE_FLAG | G_PAGE_GLOBAL_FLAG) +#define G_PAGE_KERNEL_UNCACHED (G_PAGE_KERNEL_DEFAULT | G_PAGE_CACHE_DISABLE) +#define G_PAGE_USER_DEFAULT (G_PAGE_PRESENT | G_PAGE_WRITABLE_FLAG | G_PAGE_USER_FLAG) -/** - * Type definitions for pointers to a directory or table - */ -typedef volatile uint32_t* g_page_directory; -typedef volatile uint32_t* g_page_table; +#define G_PML4_INDEX(addr) (((addr) >> 39) & 0x1FF) +#define G_PDPT_INDEX(addr) (((addr) >> 30) & 0x1FF) +#define G_PD_INDEX(addr) (((addr) >> 21) & 0x1FF) +#define G_PT_INDEX(addr) (((addr) >> 12) & 0x1FF) +#define G_PML4_VIRT_ADDRESS(pml4, pdpt, pd, pt) \ + ((((uint64_t)(pml4) << 39) | ((uint64_t)(pdpt) << 30) | ((uint64_t)(pd) << 21) | ((uint64_t)(pt) << 12)) | \ + ((((uint64_t)(pml4) & 0x100) ? 0xFFFF000000000000ULL : 0))) /** * Switches to the given page directory. @@ -80,10 +76,15 @@ void pagingSwitchToSpace(g_physical_address dir); * whether an existing entry may be overriden * * - */ +*/ +bool pagingMapPage(g_virtual_address virt, g_physical_address phys, + uint64_t tableFlags, uint64_t ptFlags, + bool allowOverride = false); + bool pagingMapPage(g_virtual_address virt, g_physical_address phys, - uint32_t tableFlags = G_PAGE_TABLE_KERNEL_DEFAULT, - uint32_t pageFlags = G_PAGE_KERNEL_DEFAULT, bool allowOverride = false); + uint64_t pdptFlags, uint64_t pdFlags, + uint64_t ptFlags, uint64_t pageFlags, + bool allowOverride = false); /** * Unmaps the given virtual page in the current address space. @@ -103,7 +104,7 @@ g_physical_address pagingGetCurrentSpace(); /** * Invalidates the translation lookaside buffer (TLB) entries for a given page. */ -static inline void pagingInvalidatePage(uint32_t addr) +static inline void pagingInvalidatePage(g_address addr) { __asm__ __volatile__("invlpg (%0)" : : "r"(addr) : "memory"); } diff --git a/kernel/inc/shared/memory/tss.hpp b/kernel/inc/shared/memory/tss.hpp index 421c3485..35e53df1 100644 --- a/kernel/inc/shared/memory/tss.hpp +++ b/kernel/inc/shared/memory/tss.hpp @@ -24,37 +24,20 @@ #include /** - * Structure of the x86 task state segment. + * Structure of the x86_64 task state segment. */ struct g_tss { - uint32_t prev_tss; - uint32_t esp0; - uint32_t ss0; - uint32_t esp1; - uint32_t ss1; - uint32_t esp2; - uint32_t ss2; - uint32_t cr3; - uint32_t eip; - uint32_t eflags; - uint32_t eax; - uint32_t ecx; - uint32_t edx; - uint32_t ebx; - uint32_t esp; - uint32_t ebp; - uint32_t esi; - uint32_t edi; - uint32_t es; - uint32_t cs; - uint32_t ss; - uint32_t ds; - uint32_t fs; - uint32_t gs; - uint32_t ldt; - uint16_t trap; - uint16_t iomap_base; + uint32_t reserved0; + uint64_t rsp0; + uint64_t rsp1; + uint64_t rsp2; + uint64_t reserved1; + uint64_t ist[7]; + uint64_t reserved2; + uint16_t reserved3; + uint16_t iomapBase; }__attribute__((packed)); + #endif diff --git a/kernel/inc/shared/multiboot/multiboot.hpp b/kernel/inc/shared/multiboot/multiboot.hpp deleted file mode 100644 index c85d525f..00000000 --- a/kernel/inc/shared/multiboot/multiboot.hpp +++ /dev/null @@ -1,163 +0,0 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * * - * Ghost, a micro-kernel based operating system for the x86 architecture * - * Copyright (C) 2015, Max Schlüssel * - * * - * This program 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. * - * * - * This program 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 this program. If not, see . * - * * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -#ifndef __MULTIBOOT__ -#define __MULTIBOOT__ - -#include - -#define G_MULTIBOOT_HEADER_MAGIC 0x1BADB002 -#define G_MULTIBOOT_BOOTLOADER_MAGIC 0x2BADB002 - -/** - * a.out symbol table - */ -struct g_multiboot_aout_symbol_table -{ - uint32_t tabSize; - uint32_t strSize; - uint32_t address; - uint32_t reserved; -} __attribute__((packed)); - -/** - * ELF section header - */ -struct g_multiboot_elf_section_header_table -{ - uint32_t num; - uint32_t size; - uint32_t addr; - uint32_t shndx; -} __attribute__((packed)); - -/** - * Structure of a multiboot module. - */ -struct g_multiboot_module -{ - uint32_t moduleStart; - uint32_t moduleEnd; - char* path; - uint32_t reserved; -} __attribute__((packed)); - -/** - * Structure of one entry in the memory map. - */ -struct g_multiboot_mmap -{ - uint32_t size; - uint64_t baseAddress; - uint64_t length; - uint32_t type; -} __attribute__((packed)); - -#define G_MULTIBOOT_MMAP_TYPE_FREE 1 -#define G_MULTIBOOT_MMAP_TYPE_ACPI 3 -#define G_MULTIBOOT_MMAP_TYPE_RESERVED 4 -#define G_MULTIBOOT_MMAP_TYPE_DEFECT 5 - - -struct g_multiboot_drives -{ - uint32_t size; - uint8_t number; - uint8_t mode; - uint16_t cylinders; - uint8_t heads; - uint8_t sectors; - uint16_t ports; // Array -} __attribute__((packed)); - -#define G_MULTIBOOT_DRIVES_MODE_CHS 0 -#define G_MULTIBOOT_DRIVES_MODE_LBA 1 - -struct g_multiboot_apm -{ - uint16_t version; - uint16_t cseg; - uint32_t offset; - uint16_t cseg16; - uint16_t dseg; - uint16_t flags; - uint16_t csegLen; - uint16_t cseg16Len; - uint16_t dsegLen; -} __attribute__((packed)); - -/** - * Structure of the multiboot information. This struct is - * built by GRUB somewhere in memory, and a pointer to it is - * passed to the multiboot-compliant loader assembler stub. - */ -struct g_multiboot_information -{ - uint32_t flags; - uint32_t memoryLower; - uint32_t memoryUpper; - uint32_t bootDevice; - uint32_t cmdline; - uint32_t modulesCount; - g_multiboot_module* modules; - - union - { - g_multiboot_aout_symbol_table aoutSymbolTable; - g_multiboot_elf_section_header_table elfSectionHeaderTable; - } tables; - - uint32_t memoryMapLength; - g_multiboot_mmap* memoryMap; - - uint32_t drivesLength; - g_multiboot_drives* drives; - - void* configTable; - const char* bootloaderName; - g_multiboot_apm* apm; - - // Followed by VBE and Framebuffer structures -} __attribute__((packed)); - -#define G_MULTIBOOT_FLAGS_LOWERMEM (1 << 0) -#define G_MULTIBOOT_FLAGS_BOOTDEV (1 << 1) -#define G_MULTIBOOT_FLAGS_CMDLINE (1 << 2) -#define G_MULTIBOOT_FLAGS_MODS (1 << 3) -#define G_MULTIBOOT_FLAGS_IS_AOUT (1 << 4) -#define G_MULTIBOOT_FLAGS_IS_ELF (1 << 5) -#define G_MULTIBOOT_FLAGS_MMAP (1 << 6) -#define G_MULTIBOOT_FLAGS_DRIVES (1 << 7) -#define G_MULTIBOOT_FLAGS_CONFIGS (1 << 8) -#define G_MULTIBOOT_FLAGS_BOOTLDNAM (1 << 9) -#define G_MULTIBOOT_FLAGS_APM (1 << 10) -#define G_MULTIBOOT_FLAGS_VBE (1 << 11) -#define G_MULTIBOOT_FLAGS_FRAMEBUF (1 << 12) - -/** - * Looks for the module with the given path. - * - * @param info multiboot information structure - * @param path module path - * @return the module or null - */ -g_multiboot_module* multibootFindModule(g_multiboot_information* info, const char* path); - -#endif diff --git a/kernel/inc/shared/setup_information.hpp b/kernel/inc/shared/setup_information.hpp index 15d785b1..3117e394 100644 --- a/kernel/inc/shared/setup_information.hpp +++ b/kernel/inc/shared/setup_information.hpp @@ -22,36 +22,7 @@ #define __SETUP_INFORMATION__ #include -#include "shared/multiboot/multiboot.hpp" +#include -/** - * A struct filled by the initial loader containing information about things - * that the loader has prepared for the kernel. - * - * Loader prepares a page directory where all page tables in the kernel area - * are allocated. - * - Kernel binary image is loaded at 0xC0000000 - * - Kernel stack is allocated right after the image - * - Kernel heap is allocated right after the stack - * - Directory is recursively mapped - * - * The given bitmap gives information about all the available physical memory - * in the system. - */ -struct g_setup_information -{ - g_virtual_address bitmapArrayStart; - g_virtual_address bitmapArrayEnd; - g_multiboot_information *multibootInformation; - - g_virtual_address kernelImageStart; - g_virtual_address kernelImageEnd; - g_virtual_address stackStart; - g_virtual_address stackEnd; - g_virtual_address heapStart; - g_virtual_address heapEnd; - - g_physical_address initialPageDirectoryPhysical; -}__attribute__((packed)); #endif diff --git a/kernel/inc/shared/system/serial_port.hpp b/kernel/inc/shared/system/serial_port.hpp index 8159985c..06462938 100644 --- a/kernel/inc/shared/system/serial_port.hpp +++ b/kernel/inc/shared/system/serial_port.hpp @@ -23,6 +23,8 @@ #include +#define G_SERIAL_DEFAULT_COM1 0x3F8 + #define G_SERIAL_PORT_OFFSET_DATA_REGISTER 0 // without DLAB, register for receiving and writing #define G_SERIAL_PORT_OFFSET_INTERRUPT_ENABLE 1 // without DLAB, interrupt enable register #define G_SERIAL_PORT_OFFSET_DIVISOR_LEAST 0 // with DLAB, least significant divisor byte @@ -34,6 +36,8 @@ #define G_SERIAL_PORT_OFFSET_MODEM_STATUS 6 // modem status register #define G_SERIAL_PORT_OFFSET_SCRATCH 7 // scratch register +bool serialPortIsAvailable(uint16_t port); + void serialPortInitialize(uint16_t port, bool interruptsEnabled); void serialPortWrite(uint16_t port, uint8_t value); diff --git a/kernel/src/loader/panic.cpp b/kernel/inc/shared/video/bitmap_font.hpp similarity index 77% rename from kernel/src/loader/panic.cpp rename to kernel/inc/shared/video/bitmap_font.hpp index ebda9096..ddacade2 100644 --- a/kernel/src/loader/panic.cpp +++ b/kernel/inc/shared/video/bitmap_font.hpp @@ -1,7 +1,7 @@ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Ghost, a micro-kernel based operating system for the x86 architecture * - * Copyright (C) 2015, Max Schlüssel * + * Copyright (C) 2025, Max Schlüssel * * * * This program is free software: you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * @@ -18,19 +18,18 @@ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ -#include "shared/logger/logger.hpp" +#ifndef __VIDEO_BITMAPFONT__ +#define __VIDEO_BITMAPFONT__ -void panic(const char* msg, ...) -{ - asm("cli"); - logInfo("%! an unrecoverable error has occured. reason:", "panic"); +#include - va_list valist; - va_start(valist, msg); - loggerPrintFormatted(msg, valist); - va_end(valist); - loggerPrintCharacter('\n'); +#include "bitmap_font_data.hpp" - for(;;) - asm("hlt"); -} +extern uint8_t bitmapFontCharWidth; +extern uint8_t bitmapFontCharHeight; +extern uint16_t bitmapFontCharCount; +extern uint8_t bitmapFontAsciiOffset; + +uint8_t* bitmapFontGetChar(char c); + +#endif diff --git a/kernel/inc/shared/video/bitmap_font_data.hpp b/kernel/inc/shared/video/bitmap_font_data.hpp new file mode 100644 index 00000000..58ef813c --- /dev/null +++ b/kernel/inc/shared/video/bitmap_font_data.hpp @@ -0,0 +1,10 @@ +/* + * NOTE: This file is generated by the bitmap-font tool, use it to update it. + */ +#ifndef __BITMAP_FONT_DATA__ +#define __BITMAP_FONT_DATA__ +#include + +extern uint8_t bitmapFontCharSet[130][190]; +#endif + \ No newline at end of file diff --git a/kernel/inc/shared/video/console_video.hpp b/kernel/inc/shared/video/console_video.hpp index 76598f91..f5f01cb3 100644 --- a/kernel/inc/shared/video/console_video.hpp +++ b/kernel/inc/shared/video/console_video.hpp @@ -23,23 +23,22 @@ #include #include - -#define G_CONSOLE_VIDEO_MEMORY 0xB8000 -#define G_CONSOLE_VIDEO_WIDTH 80 -#define G_CONSOLE_VIDEO_HEIGHT 25 -#define G_CONSOLE_VIDEO_LINE_BYTES (G_CONSOLE_VIDEO_WIDTH * 2) -#define G_CONSOLE_VIDEO_SCREEN_BYTES (G_CONSOLE_VIDEO_HEIGHT * G_CONSOLE_VIDEO_LINE_BYTES) +#include #define G_CONSOLE_VIDEO_DEFAULT_COLOR 0x07 #define G_CONSOLE_VIDEO_HEADER_COLOR 0x0F +void consoleVideoInitialize(limine_framebuffer* framebuffer); + void consoleVideoPrint(char c); -void consoleVideoPutChar(uint16_t x, uint16_t y, char c, uint8_t color); +void consoleVideoPutChar(uint16_t x, uint16_t y, char c, uint32_t color); + +void consoleVideoPutString(uint16_t x, uint16_t y, const char* c, uint32_t color); -void consoleVideoPutString(uint16_t x, uint16_t y, const char *c, uint8_t color); +void consoleVideoSetColor(uint32_t color); -void consoleVideoSetColor(uint8_t color); +uint32_t consoleVideoGetColor(); void consoleVideoClear(); diff --git a/kernel/src/ap/ap_startup.asm b/kernel/src/ap/ap_startup.asm index 12f91891..56e5d41b 100644 --- a/kernel/src/ap/ap_startup.asm +++ b/kernel/src/ap/ap_startup.asm @@ -1,6 +1,6 @@ ;* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * ;* * -;* Ghost, a micro-kernel based operating system for the x86 architecture * +;* Ghost, a micro-kernel based operating system for the x86_64 architecture * ;* Copyright (C) 2015, Max Schlüssel * ;* * ;* This program is free software: you can redistribute it and/or modify * @@ -16,14 +16,14 @@ ;* You should have received a copy of the GNU General Public License * ;* along with this program. If not, see . * ;* * -;* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ +;* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * ; ############################################################################ ; ; NOTE ; -; At this point, no stack is a available, don't use PUSH or POP! +; At this point, no stack is available, don't use PUSH or POP! ; ; This file is compiled to the ramdisk and loaded by the SMP mechanism to ; start up APs. @@ -37,7 +37,7 @@ ; Loaded by the kernel to this location org 0x1000 -; Initial setup +; Real mode BITS 16 startup: ; Load the GDT @@ -64,53 +64,71 @@ protectedStart: mov ss, ax ; Lock all cores - acquireLock: + acquireLock: lock bts dword [interlock], 0 jc acquireLock - ; Set page directory - mov eax, [0x500] - mov cr3, eax + ; Enable PAE + mov eax, cr4 + or eax, 1 << 5 + mov cr4, eax + + ; Set page directory + mov eax, [0x500] + mov cr3, eax - ; Enable paging - mov eax, cr0 - or eax, 0x80000000 - mov cr0, eax + ; Enable PGE + mov eax, cr4 + or eax, 1 << 7 + mov cr4, eax - ; Set "global pages" flag - mov eax, cr4 - or eax, 80 - mov cr4, eax + ; Set up EFER MSR to enable long mode (EFER.LME) + mov ecx, 0xC0000080 + rdmsr + or eax, 1 << 8 + wrmsr - ; Load stack from stack array - mov eax, [0x508] ; current index - shl eax, 2 ; multiply by 4 (size of one entry) - mov esp, [0x50C + eax] ; move entry to ESP - mov ebp, esp + ; Enable paging + mov eax, cr0 + or eax, 1 << 31 + mov cr0, eax - ; Increment AP counter - inc dword [0x508] + ; Get index of this AP and increment counter + mov eax, [0x510] + inc dword [0x510] ; Release lock lock btr dword [interlock], 0 - ; Jump to kernel - call [0x504] + ; Far-jump to 64 bits + jmp 0x18:longStart - ; AP should never exit, just for safety - hang: - hlt - jmp hang +; Long mode +[BITS 64] +longStart: + ; Set data segments + mov bx, 0x20 + mov ds, bx + mov ss, bx + ; 32-bit code provides AP index in EAX + ; From the stack array, take the entry at offset multiplied by 8 + shl rax, 3 + mov rsp, [0x518 + rax] + mov rbp, rsp + + ; Jump into kernel code + mov rax, [0x508] + jmp rax ; Inter-core synchronization interlock: - dd 0x00000000 + dd 0 ; Pointer to the GDT gdtPointer: - dw 24 + dw 39 dd gdt ; Basic setup GDT @@ -124,7 +142,7 @@ gdt: ; code descriptor dw 0xFFFF dw 0x0000 - dw 0x9800 + dw 0x9A00 dw 0x00CF ; data descriptor @@ -132,3 +150,15 @@ gdt: dw 0x0000 dw 0x9200 dw 0x00CF + + ; code descriptor (64-bit) + dw 0xFFFF + dw 0x0000 + dw 0x9A00 + dw 0x00A0 + + ; data descriptor (64-bit) + dw 0xFFFF + dw 0x0000 + dw 0x9200 + dw 0x00A0 diff --git a/kernel/src/kernel/calls/syscall.cpp b/kernel/src/kernel/calls/syscall.cpp index 7d006fe5..1a73634a 100644 --- a/kernel/src/kernel/calls/syscall.cpp +++ b/kernel/src/kernel/calls/syscall.cpp @@ -33,12 +33,12 @@ #include -g_syscall_registration* syscallRegistrations = 0; +g_syscall_registration* syscallRegistrations = nullptr; void syscallHandle(g_task* task) { - uint32_t callId = task->state->eax; - void* syscallData = (void*) task->state->ebx; + uint64_t callId = task->state->rax; + void* syscallData = (void*) task->state->rdi; syscall(callId, syscallData); } @@ -54,7 +54,7 @@ void syscall(uint32_t callId, void* syscallData) } g_syscall_registration* reg = &syscallRegistrations[callId]; - if(reg->handler == 0) + if(reg->handler == nullptr) { logInfo("%! task %i tried to use unknown syscall %i", "syscall", task->id, callId); return; @@ -158,6 +158,7 @@ void syscallRegisterAll() _syscallRegister(G_SYSCALL_CALL_VM86, (g_syscall_handler) syscallCallVm86); _syscallRegister(G_SYSCALL_IRQ_CREATE_REDIRECT, (g_syscall_handler) syscallIrqCreateRedirect); _syscallRegister(G_SYSCALL_AWAIT_IRQ, (g_syscall_handler) syscallAwaitIrq, true); + _syscallRegister(G_SYSCALL_GET_EFI_FRAMEBUFFER, (g_syscall_handler) syscallGetEfiFramebuffer); // Kernquery _syscallRegister(G_SYSCALL_KERNQUERY, (g_syscall_handler) syscallKernQuery); diff --git a/kernel/src/kernel/calls/syscall_memory.cpp b/kernel/src/kernel/calls/syscall_memory.cpp index 65bd8fb0..ea250db0 100644 --- a/kernel/src/kernel/calls/syscall_memory.cpp +++ b/kernel/src/kernel/calls/syscall_memory.cpp @@ -24,6 +24,7 @@ #include "kernel/memory/page_reference_tracker.hpp" #include "kernel/tasking/tasking_memory.hpp" #include "kernel/system/interrupts/interrupts.hpp" +#include "shared/memory/constants.hpp" #include "shared/logger/logger.hpp" @@ -78,7 +79,8 @@ void syscallAllocateMemory(g_task* task, g_syscall_alloc_mem* data) failedPhysical = true; break; } - pagingMapPage(mapped + i * G_PAGE_SIZE, page, G_PAGE_TABLE_USER_DEFAULT, G_PAGE_USER_DEFAULT); + pagingMapPage(mapped + i * G_PAGE_SIZE, page, G_PAGE_TABLE_USER_DEFAULT,G_PAGE_TABLE_USER_DEFAULT, + G_PAGE_TABLE_USER_DEFAULT, G_PAGE_USER_DEFAULT); } if(failedPhysical) @@ -134,10 +136,10 @@ void syscallShareMemory(g_task* task, g_syscall_share_mem* data) g_virtual_address memory = (g_virtual_address) data->memory; uint32_t pages = G_PAGE_ALIGN_UP(data->size) / G_PAGE_SIZE; - if(memory > G_KERNEL_AREA_START || (memory + pages * G_PAGE_SIZE) > G_KERNEL_AREA_START) + if(memory > G_MEM_LOWER_HALF_END || (memory + pages * G_PAGE_SIZE) > G_MEM_LOWER_HALF_END) { logInfo("%! task %i was unable to share memory because addresses above %h are not allowed", "syscall", task->id, - G_KERNEL_AREA_START); + G_MEM_LOWER_HALF_END); return; } @@ -169,7 +171,7 @@ void syscallShareMemory(g_task* task, g_syscall_share_mem* data) mutexAcquire(&targetProcess->lock); targetProcess = targetTask->process; - g_physical_address back = taskingMemoryTemporarySwitchTo(targetProcess->pageDirectory); + g_physical_address back = taskingMemoryTemporarySwitchTo(targetProcess->pageSpace); pagingMapPage(virtualRangeBase + i * G_PAGE_SIZE, physicalAddr, G_PAGE_TABLE_USER_DEFAULT, G_PAGE_USER_DEFAULT); taskingMemoryTemporarySwitchBack(back); mutexRelease(&targetProcess->lock); diff --git a/kernel/src/kernel/calls/syscall_system.cpp b/kernel/src/kernel/calls/syscall_system.cpp index 9f32564e..6037c9db 100644 --- a/kernel/src/kernel/calls/syscall_system.cpp +++ b/kernel/src/kernel/calls/syscall_system.cpp @@ -27,6 +27,8 @@ #include "shared/logger/logger.hpp" #include "kernel/tasking/elf/elf_object.hpp" #include "shared/utils/string.hpp" +#include "kernel/memory/paging.hpp" +#include "shared/boot/limine.hpp" void _getBinaryNameWithoutExtension(g_task* task, char buf[], int len) { @@ -133,3 +135,16 @@ void syscallAwaitIrq(g_task* task, g_syscall_await_irq* data) } }); } + +void syscallGetEfiFramebuffer(g_task* task, g_syscall_get_efi_framebuffer* data) +{ + if(task->securityLevel > G_SECURITY_LEVEL_DRIVER) + return; + + auto framebuffer = limineGetFramebuffer(); + data->address = pagingVirtualToPhysical((g_address) framebuffer->address); + data->width = framebuffer->width; + data->height = framebuffer->height; + data->bpp = framebuffer->bpp; + data->pitch = framebuffer->pitch; +} diff --git a/kernel/src/kernel/calls/syscall_system.hpp b/kernel/src/kernel/calls/syscall_system.hpp index 9e921326..cf204f7a 100644 --- a/kernel/src/kernel/calls/syscall_system.hpp +++ b/kernel/src/kernel/calls/syscall_system.hpp @@ -36,4 +36,6 @@ void syscallIrqCreateRedirect(g_task* task, g_syscall_irq_create_redirect* data) void syscallAwaitIrq(g_task* task, g_syscall_await_irq* data); +void syscallGetEfiFramebuffer(g_task* task, g_syscall_get_efi_framebuffer* data); + #endif diff --git a/kernel/src/kernel/filesystem/filesystem.cpp b/kernel/src/kernel/filesystem/filesystem.cpp index 43c863ac..2a2be384 100644 --- a/kernel/src/kernel/filesystem/filesystem.cpp +++ b/kernel/src/kernel/filesystem/filesystem.cpp @@ -226,7 +226,10 @@ g_filesystem_find_result filesystemFind(g_fs_node* parent, const char* path) g_fs_node* lastFoundParent = node; g_fs_open_status status = G_FS_OPEN_SUCCESSFUL; - char* nameStart = (char*) path; + char* buf = (char*) heapAllocate(G_PATH_MAX); // TODO SLOW + stringCopy(buf, path); + + char* nameStart = buf; char* nameEnd = nameStart; while(nameStart) @@ -268,19 +271,20 @@ g_filesystem_find_result filesystemFind(g_fs_node* parent, const char* path) nameStart = nameEnd; } + heapFree(buf); return { status: status, node: node, foundAllButLast: ((nameEnd - nameStart) > 0), lastFoundParent: lastFoundParent, - fileNameStart: nameStart + fileNameStart: path + (nameStart - buf) }; } g_fs_open_status filesystemOpen(const char* path, g_file_flag_mode flags, g_task* task, g_fd* outFd) { - g_fs_node* origin; + g_fs_node* origin = nullptr; g_fs_open_status findOriginStatus = _filesystemChooseOrigin(path, task, origin); if(findOriginStatus != G_FS_OPEN_SUCCESSFUL) return findOriginStatus; diff --git a/kernel/src/kernel/filesystem/ramdisk.cpp b/kernel/src/kernel/filesystem/ramdisk.cpp index 8437f921..09348235 100644 --- a/kernel/src/kernel/filesystem/ramdisk.cpp +++ b/kernel/src/kernel/filesystem/ramdisk.cpp @@ -27,38 +27,24 @@ #include "shared/utils/string.hpp" #include "shared/logger/logger.hpp" -g_ramdisk* ramdiskMain = 0; +g_ramdisk* ramdiskMain = nullptr; -void ramdiskLoadFromModule(g_multiboot_module* module) +void ramdiskLoadFromBootloaderFile(limine_file* file) { if(ramdiskMain) panic("%! tried to initialize ramdisk multiple times", "kern"); - int pages = G_PAGE_ALIGN_UP(module->moduleEnd - module->moduleStart) / G_PAGE_SIZE; - - g_virtual_address newLocation = addressRangePoolAllocate(memoryVirtualRangePool, pages); - if(newLocation == 0) - panic("%! not enough virtual space for ramdisk remapping (%x required)", "kern", module->moduleEnd - module->moduleStart); - - for(int i = 0; i < pages; i++) - { - g_virtual_address virt = newLocation + i * G_PAGE_SIZE; - g_physical_address phys = pagingVirtualToPhysical(module->moduleStart + i * G_PAGE_SIZE); - pagingMapPage(virt, phys, G_PAGE_TABLE_KERNEL_DEFAULT, G_PAGE_KERNEL_DEFAULT); - } - module->moduleEnd = newLocation + (module->moduleEnd - module->moduleStart); - module->moduleStart = newLocation; - ramdiskMain = (g_ramdisk*) heapAllocate(sizeof(g_ramdisk)); - ramdiskParseContents(module); - logInfo("%! module loaded: %i MB", "ramdisk", (module->moduleEnd - module->moduleStart) / 1024 / 1024); - logDebug("%! relocated to kernel space: %h -> %h", "ramdisk", module->moduleStart, G_PAGE_ALIGN_UP(module->moduleEnd)); + ramdiskParseContents(file); + logInfo("%! module loaded: %i MB", "ramdisk", file->size / 1024 / 1024); + logDebug("%! relocated to kernel space: %h -> %h", "ramdisk", module->moduleStart, + G_PAGE_ALIGN_UP(module->moduleEnd)); } -void ramdiskParseContents(g_multiboot_module* module) +void ramdiskParseContents(limine_file* file) { - uint8_t* data = (uint8_t*) module->moduleStart; - g_address dataEnd = module->moduleEnd; + uint8_t* data = (uint8_t*) file->address; + g_address dataEnd = (g_address) file->address + file->size; ramdiskMain->root = new g_ramdisk_entry; ramdiskMain->root->id = 0; @@ -138,7 +124,6 @@ void ramdiskParseContents(g_multiboot_module* module) g_ramdisk_entry* ramdiskFindChild(g_ramdisk_entry* parent, const char* childName) { - g_ramdisk_entry* current = ramdiskMain->firstEntry; while(current) { diff --git a/kernel/src/kernel/filesystem/ramdisk.hpp b/kernel/src/kernel/filesystem/ramdisk.hpp index 7dfeb013..c2864362 100644 --- a/kernel/src/kernel/filesystem/ramdisk.hpp +++ b/kernel/src/kernel/filesystem/ramdisk.hpp @@ -25,27 +25,25 @@ #include #include "kernel/filesystem/ramdisk_entry.hpp" -#include "shared/multiboot/multiboot.hpp" +#include struct g_ramdisk { - g_ramdisk_entry* firstEntry; - g_ramdisk_entry* root; - uint32_t nextUnusedId = 0; + g_ramdisk_entry* firstEntry; + g_ramdisk_entry* root; + uint32_t nextUnusedId = 0; }; extern g_ramdisk* ramdiskMain; /** - * Creates a ramdisk instance for a multiboot module. The contents of the - * ramdisk are relocated into kernel memory. + * Creates a ramdisk instance from the file loaded by the bootloader. * - * @param module source multiboot module + * @param file file provided by bootloader * @return a ramdisk instance */ -void ramdiskLoadFromModule(g_multiboot_module* module); - -void ramdiskParseContents(g_multiboot_module* module); +void ramdiskLoadFromBootloaderFile(limine_file* file); +void ramdiskParseContents(limine_file* file); /** * Searches in the folder parent for a file/folder with the given name diff --git a/kernel/src/kernel/ipc/pipes.cpp b/kernel/src/kernel/ipc/pipes.cpp index c711e89c..99f9011e 100644 --- a/kernel/src/kernel/ipc/pipes.cpp +++ b/kernel/src/kernel/ipc/pipes.cpp @@ -143,21 +143,21 @@ g_fs_read_status pipeRead(g_fs_phys_id pipeId, uint8_t* buffer, uint64_t offset, length = (pipe->size >= length) ? length : pipe->size; - uint32_t lengthToEnd = ((uint32_t) pipe->buffer + pipe->capacity) - (uint32_t) pipe->readPosition; + size_t lengthToEnd = ((g_address) pipe->buffer + pipe->capacity) - (size_t) pipe->readPosition; if(length > lengthToEnd) { memoryCopy(buffer, pipe->readPosition, lengthToEnd); - uint32_t remaining = length - lengthToEnd; + size_t remaining = length - lengthToEnd; memoryCopy(&buffer[lengthToEnd], pipe->buffer, remaining); - pipe->readPosition = (uint8_t*) ((uint32_t) pipe->buffer + remaining); + pipe->readPosition = (uint8_t*) ((g_address) pipe->buffer + remaining); } else { memoryCopy(buffer, pipe->readPosition, length); - pipe->readPosition = (uint8_t*) ((uint32_t) pipe->readPosition + length); + pipe->readPosition = (uint8_t*) ((g_address) pipe->readPosition + length); } if(pipe->readPosition == pipe->buffer + pipe->capacity) @@ -190,28 +190,28 @@ g_fs_write_status pipeWrite(g_fs_phys_id pipeId, uint8_t* buffer, uint64_t offse mutexAcquire(&pipe->lock); - uint32_t space = (pipe->capacity - pipe->size); + size_t space = (pipe->capacity - pipe->size); g_fs_write_status status; if(space > 0) { length = (space >= length) ? length : space; - uint32_t lengthToEnd = ((uint32_t) pipe->buffer + pipe->capacity) - (uint32_t) pipe->writePosition; + size_t lengthToEnd = ((g_address) pipe->buffer + pipe->capacity) - (size_t) pipe->writePosition; if(length > lengthToEnd) { memoryCopy(pipe->writePosition, buffer, lengthToEnd); - uint32_t remaining = length - lengthToEnd; + size_t remaining = length - lengthToEnd; memoryCopy(pipe->buffer, &buffer[lengthToEnd], remaining); - pipe->writePosition = (uint8_t*) ((uint32_t) pipe->buffer + remaining); + pipe->writePosition = (uint8_t*) ((g_address) pipe->buffer + remaining); } else { memoryCopy(pipe->writePosition, buffer, length); - pipe->writePosition = (uint8_t*) ((uint32_t) pipe->writePosition + length); + pipe->writePosition = (uint8_t*) ((g_address) pipe->writePosition + length); } if(pipe->writePosition == pipe->buffer + pipe->capacity) diff --git a/kernel/src/kernel/kernel.cpp b/kernel/src/kernel/kernel.cpp index ae2077a3..f23cc572 100644 --- a/kernel/src/kernel/kernel.cpp +++ b/kernel/src/kernel/kernel.cpp @@ -19,6 +19,7 @@ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #include "kernel/kernel.hpp" +#include #include "kernel/calls/syscall.hpp" #include "kernel/filesystem/filesystem.hpp" #include "kernel/filesystem/ramdisk.hpp" @@ -35,48 +36,113 @@ #include "kernel/tasking/tasking.hpp" #include "shared/system/mutex.hpp" #include "shared/panic.hpp" -#include "shared/setup_information.hpp" #include "shared/video/console_video.hpp" #include "shared/video/pretty_boot.hpp" #include "shared/logger/logger.hpp" +#include "shared/boot/limine.hpp" static g_mutex bootstrapCoreLock; static g_mutex applicationCoreLock; -extern "C" void kernelMain(g_setup_information* setupInformation) +__attribute__((used, section(".limine_requests"))) +static volatile LIMINE_BASE_REVISION(3); + +__attribute__((used, section(".limine_requests"))) +volatile limine_framebuffer_request framebufferRequest = { + .id = LIMINE_FRAMEBUFFER_REQUEST, + .revision = 0 +}; + +__attribute__((used, section(".limine_requests"))) +volatile limine_memmap_request memoryMapRequest = { + .id = LIMINE_MEMMAP_REQUEST, + .revision = 0 +}; + +__attribute__((used, section(".limine_requests"))) +volatile limine_paging_mode_request pagingModeRequest = { + .id = LIMINE_PAGING_MODE_REQUEST, + .revision = 0, + .mode = LIMINE_PAGING_MODE_X86_64_4LVL +}; + +__attribute__((used, section(".limine_requests"))) +volatile limine_module_request moduleRequest = { + .id = LIMINE_MODULE_REQUEST, + .revision = 0, +}; + +__attribute__((used, section(".limine_requests"))) +volatile limine_rsdp_request rsdpRequest = { + .id = LIMINE_RSDP_REQUEST, + .revision = 0, +}; + +__attribute__((used, section(".limine_requests"))) +volatile limine_hhdm_request hhdmRequest = { + .id = LIMINE_HHDM_REQUEST, + .revision = 0, +}; + +__attribute__((used, section(".limine_requests_start"))) +static volatile LIMINE_REQUESTS_START_MARKER; + +__attribute__((used, section(".limine_requests_end"))) +static volatile LIMINE_REQUESTS_END_MARKER; + +void failEarly() { + asm("cli; hlt;"); +} + +extern "C" void kernelMain() +{ + if(LIMINE_BASE_REVISION_SUPPORTED == false) + failEarly(); + + if(framebufferRequest.response == nullptr || framebufferRequest.response->framebuffer_count < 1) + failEarly(); + + auto framebuffer = framebufferRequest.response->framebuffers[0]; + limineStoreFramebuffer(framebuffer); + consoleVideoInitialize(framebuffer); if(G_PRETTY_BOOT) prettyBootEnable(false); else consoleVideoClear(); + kernelLoggerInitialize(); + + if(pagingModeRequest.response->mode != LIMINE_PAGING_MODE_X86_64_4LVL) + panic("%! bootloader failed to boot in 4-level paging mode", "error"); - kernelLoggerInitialize(setupInformation); + // TODO Just use the value instead of failing if its different: + if(hhdmRequest.response->offset != G_MEM_HIGHER_HALF_DIRECT_MAP_OFFSET) + panic("%! higher half mapping not at expected offset %x but %x", "error", G_MEM_HIGHER_HALF_DIRECT_MAP_OFFSET, + hhdmRequest.response->offset); - memoryInitialize(setupInformation); + memoryInitialize(memoryMapRequest.response); - g_multiboot_module* ramdiskModule = multibootFindModule(setupInformation->multibootInformation, "/boot/ramdisk"); - if(!ramdiskModule) + auto ramdiskFile = limineFindModule(moduleRequest.response, "/boot/ramdisk"); + if(!ramdiskFile) { - G_PRETTY_BOOT_FAIL("Ramdisk not found (did you supply enough memory?"); - panic("%! ramdisk not found (did you supply enough memory?)", "kern"); + G_PRETTY_BOOT_FAIL("Ramdisk file not found"); + panic("%! ramdisk file not found", "kern"); } - ramdiskLoadFromModule(ramdiskModule); - - g_address initialPdPhys = setupInformation->initialPageDirectoryPhysical; - memoryUnmapSetupMemory(); + ramdiskLoadFromBootloaderFile(ramdiskFile); - kernelRunBootstrapCore(initialPdPhys); + // TODO unmap loader memory + kernelRunBootstrapCore(); __builtin_unreachable(); } -void kernelRunBootstrapCore(g_physical_address initialPdPhys) +void kernelRunBootstrapCore() { mutexInitializeGlobal(&bootstrapCoreLock, __func__); mutexInitializeGlobal(&applicationCoreLock, __func__); mutexAcquire(&bootstrapCoreLock); - systemInitializeBsp(initialPdPhys); + systemInitializeBsp((g_physical_address) rsdpRequest.response->address); clockInitialize(); filesystemInitialize(); pipeInitialize(); @@ -85,17 +151,17 @@ void kernelRunBootstrapCore(g_physical_address initialPdPhys) userMutexInitialize(); taskingInitializeBsp(); - logInfo("%! starting on %i cores", "kernel", processorGetNumberOfProcessors()); + logInfo("%! starting on %i core(s)", "kernel", processorGetNumberOfProcessors()); mutexRelease(&bootstrapCoreLock); - systemWaitForApplicationCores(); - systemMarkReady(); - auto initializationProcess = taskingCreateProcess(G_SECURITY_LEVEL_KERNEL); auto initializationTask = taskingCreateTask((g_virtual_address) kernelInitializationThread, initializationProcess, G_SECURITY_LEVEL_KERNEL); taskingAssign(taskingGetLocal(), initializationTask); + systemWaitForApplicationCores(); + systemMarkReady(); + interruptsEnable(); for(;;) asm("hlt"); @@ -108,6 +174,7 @@ void kernelRunApplicationCore() mutexAcquire(&applicationCoreLock); + logInfo("AP core running"); systemInitializeAp(); taskingInitializeAp(); @@ -152,6 +219,7 @@ void kernelInitializationThread() G_PRETTY_BOOT_STATUS_P(20); kernelSpawnService("/applications/pcidriver.bin", "", G_SECURITY_LEVEL_DRIVER); + G_PRETTY_BOOT_STATUS_P(20); kernelSpawnService("/applications/devicemanager.bin", "", G_SECURITY_LEVEL_DRIVER); G_PRETTY_BOOT_STATUS_P(40); @@ -159,8 +227,20 @@ void kernelInitializationThread() G_PRETTY_BOOT_STATUS_P(80); kernelSpawnService("/applications/windowserver.bin", "", G_SECURITY_LEVEL_APPLICATION); + // G_PRETTY_BOOT_STATUS_P(80); + // kernelSpawnService("/applications/terminal.bin", "--headless", G_SECURITY_LEVEL_DRIVER); G_PRETTY_BOOT_STATUS("initializing...", 100); + // logInfo("do stuff..."); + // for(;;) + // { + // auto task = taskingGetCurrentTask(); + // taskingWait(task, __func__, [task]() + // { + // clockWaitForTime(task->id, clockGetLocal()->time + 1000); + // }); + // logInfo("alive..."); + // } taskingExit(); } diff --git a/kernel/src/kernel/kernel.hpp b/kernel/src/kernel/kernel.hpp index e78306ff..824270cd 100644 --- a/kernel/src/kernel/kernel.hpp +++ b/kernel/src/kernel/kernel.hpp @@ -33,12 +33,12 @@ extern g_bitmap_page_allocator* kernelPhysicalAllocator; * bootstrap processor. The setup information structure contains information * about everything that the loader has prepared for the kernel. */ -extern "C" void kernelMain(g_setup_information* setupInformation); +extern "C" void kernelMain(); /** * Bootstrap processor (BSP) initialization sequence. */ -void kernelRunBootstrapCore(g_physical_address initialPdPhys); +void kernelRunBootstrapCore(); /** * Once the kernel is set up and all application processors are ready, this is the first thread diff --git a/kernel/src/kernel/logger/kernel_logger.cpp b/kernel/src/kernel/logger/kernel_logger.cpp index fc651e75..7831cfea 100644 --- a/kernel/src/kernel/logger/kernel_logger.cpp +++ b/kernel/src/kernel/logger/kernel_logger.cpp @@ -26,13 +26,13 @@ #include "shared/system/bios_data_area.hpp" #include "shared/debug/debug_interface.hpp" -void kernelLoggerInitialize(g_setup_information* info) +void kernelLoggerInitialize() { kernelLoggerInitializeComPorts(); - kernelLoggerPrintHeader(info); + kernelLoggerPrintHeader(); } -void kernelLoggerPrintHeader(g_setup_information* info) +void kernelLoggerPrintHeader() { if(!G_PRETTY_BOOT) consoleVideoClear(); @@ -40,11 +40,10 @@ void kernelLoggerPrintHeader(g_setup_information* info) logInfon(""); logInfon(""); logInfon(""); - consoleVideoSetColor(0x90); + consoleVideoSetColor(0xFF4444FF); logInfon("Ghost Kernel"); - consoleVideoSetColor(0x0F); + consoleVideoSetColor(0xFFFFFFFF); logInfo(" Version %i.%i.%i", G_VERSION_MAJOR, G_VERSION_MINOR, G_VERSION_PATCH); - logInfo(""); logInfo(" Copyright (C) 2022, Max Schl\x81ssel "); logInfo(""); logInfo("%! initializing core services", "kernel"); @@ -61,14 +60,10 @@ void kernelLoggerPrintHeader(g_setup_information* info) void kernelLoggerInitializeComPorts() { - g_com_port_information comPortInfo = biosDataArea->comPortInfo; - if(comPortInfo.com1 == 0) + if(serialPortIsAvailable(G_SERIAL_DEFAULT_COM1)) { - logInfo("%! COM1 port not available for serial debug output", "logger"); - return; + serialPortInitialize(G_SERIAL_DEFAULT_COM1, false); // Initialize in poll mode + loggerEnableSerial(true); + debugInterfaceInitialize(G_SERIAL_DEFAULT_COM1); } - - serialPortInitialize(comPortInfo.com1, false); - loggerEnableSerial(true); - debugInterfaceInitialize(comPortInfo.com1); } diff --git a/kernel/src/kernel/logger/kernel_logger.hpp b/kernel/src/kernel/logger/kernel_logger.hpp index b0cf25f3..4da1450b 100644 --- a/kernel/src/kernel/logger/kernel_logger.hpp +++ b/kernel/src/kernel/logger/kernel_logger.hpp @@ -21,11 +21,9 @@ #ifndef __KERNEL_LOGGER__ #define __KERNEL_LOGGER__ -#include "shared/setup_information.hpp" +void kernelLoggerInitialize(); -void kernelLoggerInitialize(g_setup_information* info); - -void kernelLoggerPrintHeader(g_setup_information* info); +void kernelLoggerPrintHeader(); void kernelLoggerInitializeComPorts(); diff --git a/kernel/src/kernel/memory/allocator.cpp b/kernel/src/kernel/memory/allocator.cpp index 3987727e..ef8bd165 100644 --- a/kernel/src/kernel/memory/allocator.cpp +++ b/kernel/src/kernel/memory/allocator.cpp @@ -31,26 +31,28 @@ */ void _memoryAllocatorMerge(g_allocator* allocator); -g_allocator_section_header* _memoryAllocatorAllocateSection(g_allocator* allocator, g_size totalSize, g_allocator_section_type type); +g_allocator_section_header* _memoryAllocatorAllocateSection(g_allocator* allocator, g_size totalSize, + g_allocator_section_type type); g_size _memoryAllocatorFreeSection(g_allocator* allocator, g_allocator_section_header* section); -g_size _memoryAllocatorFreeInBucket(g_allocator* allocator, g_allocator_section_bucket* bucket, void* mem); +g_size _memoryAllocatorFreeInBucket(g_allocator_section_bucket* bucket, void* mem); void* _memoryAllocatorAllocateInBucket(g_allocator* allocator, g_size size); -void* _memoryAllocatorAllocateInSpecificBucket(g_allocator* allocator, g_allocator_section_bucket* bucket); +void* _memoryAllocatorAllocateInSpecificBucket(g_allocator_section_bucket* bucket); #define _G_ALLOCATOR_BUCKET_BITMAP(bucket) ((uint8_t*) ((g_address) bucket + sizeof(g_allocator_section_bucket))) #define _G_ALLOCATOR_BUCKET_CONTENT(bucket) ((uint8_t*) ((g_address) bucket + sizeof(g_allocator_section_bucket) + bucket->bitmapSize)) -void memoryAllocatorInitialize(g_allocator* allocator, g_allocator_type type, g_virtual_address start, g_virtual_address end) +void memoryAllocatorInitialize(g_allocator* allocator, g_allocator_type type, g_virtual_address start, + g_virtual_address end) { mutexInitializeGlobal(&allocator->lock, __func__); allocator->type = type; - g_allocator_section_header* firstSection = (g_allocator_section_header*) start; + auto firstSection = (g_allocator_section_header*) start; firstSection->type = G_ALLOCATOR_SECTION_TYPE_FREE; firstSection->totalSize = end - start; firstSection->next = nullptr; - allocator->sections = (g_allocator_section_header*) firstSection; + allocator->sections = firstSection; } void* memoryAllocatorAllocate(g_allocator* allocator, g_size size) @@ -65,7 +67,8 @@ void* memoryAllocatorAllocate(g_allocator* allocator, g_size size) void* mem = nullptr; if(size > G_ALLOCATOR_MAX_FOR_BUCKETS) { - auto section = _memoryAllocatorAllocateSection(allocator, sizeof(g_allocator_section_header) + size, G_ALLOCATOR_SECTION_TYPE_CHUNK); + auto section = _memoryAllocatorAllocateSection(allocator, sizeof(g_allocator_section_header) + size, + G_ALLOCATOR_SECTION_TYPE_CHUNK); if(section) mem = (void*) ((g_address) section + sizeof(g_allocator_section_header)); } @@ -73,22 +76,22 @@ void* memoryAllocatorAllocate(g_allocator* allocator, g_size size) mem = _memoryAllocatorAllocateInBucket(allocator, size); mutexRelease(&allocator->lock); - return (void*) mem; + return mem; } g_size memoryAllocatorFree(g_allocator* allocator, void* mem) { mutexAcquire(&allocator->lock); - g_allocator_section_header* current = allocator->sections; + auto section = allocator->sections; do { - if((g_address) mem > (g_address) current && (g_address) mem < (g_address) current + current->totalSize) + if((g_address) mem > (g_address) section && (g_address) mem < (g_address) section + section->totalSize) break; - current = current->next; - } while(current); + section = section->next; + } while(section); - if(!current) + if(!section) { logInfo("%! attempted to free %x not managed by kernel allocator (type %i)", "critical", mem, allocator->type); mutexRelease(&allocator->lock); @@ -96,12 +99,13 @@ g_size memoryAllocatorFree(g_allocator* allocator, void* mem) } g_size size; - if(current->type == G_ALLOCATOR_SECTION_TYPE_CHUNK) - size = _memoryAllocatorFreeSection(allocator, current); - else if(current->type == G_ALLOCATOR_SECTION_TYPE_BUCKET) - size = _memoryAllocatorFreeInBucket(allocator, (g_allocator_section_bucket*) current, mem); + if(section->type == G_ALLOCATOR_SECTION_TYPE_CHUNK) + size = _memoryAllocatorFreeSection(allocator, section); + else if(section->type == G_ALLOCATOR_SECTION_TYPE_BUCKET) + size = _memoryAllocatorFreeInBucket((g_allocator_section_bucket*) section, mem); else - panic("%! attempt to free kernel memory in a section of type %i in allocator %i", "alloc", current->type, allocator->type); + panic("%! attempt to free kernel memory in a section of type %i in allocator %i", "alloc", section->type, + allocator->type); mutexRelease(&allocator->lock); return size; @@ -115,7 +119,7 @@ void memoryAllocatorExpand(g_allocator* allocator, g_size size) while(last->next) last = last->next; - g_allocator_section_header* next = (g_allocator_section_header*) ((g_address) last + last->totalSize); + auto next = (g_allocator_section_header*) ((g_address) last + last->totalSize); next->type = G_ALLOCATOR_SECTION_TYPE_FREE; next->totalSize = size; next->next = nullptr; @@ -126,7 +130,8 @@ void memoryAllocatorExpand(g_allocator* allocator, g_size size) mutexRelease(&allocator->lock); } -g_allocator_section_header* _memoryAllocatorAllocateSection(g_allocator* allocator, g_size totalSize, g_allocator_section_type type) +g_allocator_section_header* _memoryAllocatorAllocateSection(g_allocator* allocator, g_size totalSize, + g_allocator_section_type type) { g_allocator_section_header* current = allocator->sections; do @@ -143,12 +148,12 @@ g_allocator_section_header* _memoryAllocatorAllocateSection(g_allocator* allocat g_size remainder = current->totalSize - totalSize; if(remainder > sizeof(g_allocator_section_header) + G_ALLOCATOR_MAX_FOR_BUCKETS) { - g_allocator_section_header* next = (g_allocator_section_header*) ((g_address) current + totalSize); + auto next = (g_allocator_section_header*) ((g_address) current + totalSize); current->totalSize = totalSize; + next->next = current->next; current->next = next; next->type = G_ALLOCATOR_SECTION_TYPE_FREE; next->totalSize = remainder; - next->next = nullptr; } current->type = type; @@ -174,7 +179,8 @@ g_allocator_section_bucket* _memoryAllocatorAllocateNewBucket(g_allocator* alloc auto bitmapSize = (entryCount / 8); auto sectionTotalSize = sizeof(g_allocator_section_bucket) + bitmapSize + entryCount * size; - g_allocator_section_bucket* bucket = (g_allocator_section_bucket*) _memoryAllocatorAllocateSection(allocator, sectionTotalSize, G_ALLOCATOR_SECTION_TYPE_BUCKET); + auto bucket = (g_allocator_section_bucket*) _memoryAllocatorAllocateSection( + allocator, sectionTotalSize, G_ALLOCATOR_SECTION_TYPE_BUCKET); if(!bucket) return nullptr; @@ -188,7 +194,7 @@ g_allocator_section_bucket* _memoryAllocatorAllocateNewBucket(g_allocator* alloc return bucket; } -void* _memoryAllocatorAllocateInSpecificBucket(g_allocator* allocator, g_allocator_section_bucket* bucket) +void* _memoryAllocatorAllocateInSpecificBucket(g_allocator_section_bucket* bucket) { uint8_t* bucketBitmap = _G_ALLOCATOR_BUCKET_BITMAP(bucket); int byteIndex = -1; @@ -207,8 +213,13 @@ void* _memoryAllocatorAllocateInSpecificBucket(g_allocator* allocator, g_allocat uint8_t byte = bucketBitmap[byteIndex]; uint8_t bitIndex; for(uint8_t i = 0; i < 8; i++) + { if((byte & (1 << i)) == 0) + { bitIndex = i; + break; + } + } bucketBitmap[byteIndex] |= 1 << bitIndex; @@ -218,30 +229,33 @@ void* _memoryAllocatorAllocateInSpecificBucket(g_allocator* allocator, g_allocat void* _memoryAllocatorAllocateInBucket(g_allocator* allocator, g_size size) { - g_allocator_section_header* current = allocator->sections; + auto section = allocator->sections; do { - if(current->type == G_ALLOCATOR_SECTION_TYPE_BUCKET) + if(section->type == G_ALLOCATOR_SECTION_TYPE_BUCKET) { - g_allocator_section_bucket* bucket = (g_allocator_section_bucket*) current; + auto bucket = (g_allocator_section_bucket*) section; if(bucket->entrySize == size) { - void* result = _memoryAllocatorAllocateInSpecificBucket(allocator, bucket); + void* result = _memoryAllocatorAllocateInSpecificBucket(bucket); if(result) return result; } } - current = current->next; - } while(current); + section = section->next; + } while(section); g_allocator_section_bucket* bucket = _memoryAllocatorAllocateNewBucket(allocator, size); - return _memoryAllocatorAllocateInSpecificBucket(allocator, bucket); + if(!bucket) + return nullptr; + + return _memoryAllocatorAllocateInSpecificBucket(bucket); } -g_size _memoryAllocatorFreeInBucket(g_allocator* allocator, g_allocator_section_bucket* bucket, void* mem) +g_size _memoryAllocatorFreeInBucket(g_allocator_section_bucket* bucket, void* mem) { - g_address contentAddress = (g_address) _G_ALLOCATOR_BUCKET_CONTENT(bucket); + auto contentAddress = (g_address) _G_ALLOCATOR_BUCKET_CONTENT(bucket); auto entryIndex = ((g_address) mem - contentAddress) / bucket->entrySize; uint8_t* bitmap = _G_ALLOCATOR_BUCKET_BITMAP(bucket); @@ -251,17 +265,17 @@ g_size _memoryAllocatorFreeInBucket(g_allocator* allocator, g_allocator_section_ void _memoryAllocatorMerge(g_allocator* allocator) { - g_allocator_section_header* current = (g_allocator_section_header*) allocator->sections; - while(current && current->next) + auto section = allocator->sections; + while(section && section->next) { - if(current->type == G_ALLOCATOR_SECTION_TYPE_FREE && current->next->type == G_ALLOCATOR_SECTION_TYPE_FREE) + if(section->type == G_ALLOCATOR_SECTION_TYPE_FREE && section->next->type == G_ALLOCATOR_SECTION_TYPE_FREE) { - current->totalSize += current->next->totalSize; - current->next = current->next->next; + section->totalSize += section->next->totalSize; + section->next = section->next->next; } else { - current = current->next; + section = section->next; } } -} \ No newline at end of file +} diff --git a/kernel/src/kernel/memory/gdt.cpp b/kernel/src/kernel/memory/gdt.cpp index 4b27952d..3d390619 100644 --- a/kernel/src/kernel/memory/gdt.cpp +++ b/kernel/src/kernel/memory/gdt.cpp @@ -19,69 +19,111 @@ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #include "kernel/memory/gdt.hpp" +#include "kernel/utils/debug.hpp" +#include "shared/logger/logger.hpp" #include "kernel/memory/heap.hpp" #include "kernel/system/processor/processor.hpp" +#include "shared/memory/memory.hpp" -static g_gdt_list_entry** gdtList; +static g_gdt** gdtList; -void gdtPrepare() +void _gdtWriteEntry(g_gdt_descriptor* entry, uint64_t base, uint64_t limit, uint8_t access, uint8_t granularity); +void _gdtWriteTssEntry(g_gdt_tss_descriptor* entry, uint64_t base, uint64_t limit, uint8_t access, uint8_t granularity); + +void gdtInitialize() { uint32_t cores = processorGetNumberOfProcessors(); - gdtList = (g_gdt_list_entry**) heapAllocate(sizeof(g_gdt_list_entry*) * cores); + gdtList = (g_gdt**) heapAllocate(sizeof(g_gdt*) * cores); for(uint32_t i = 0; i < cores; i++) - gdtList[i] = (g_gdt_list_entry*) heapAllocate(sizeof(g_gdt_list_entry)); + { + // TODO still no aligned allocator + auto gdtMemory = heapAllocateClear(sizeof(g_gdt) * 2); + gdtList[i] = (g_gdt*) G_ALIGN_UP((g_address) gdtMemory, 0x10); + } } -void gdtInitialize() +void gdtInitializeLocal() { - g_gdt_list_entry* localGdt = gdtList[processorGetCurrentId()]; - - localGdt->ptr.limit = (sizeof(g_gdt_entry) * G_GDT_NUM_ENTRIES) - 1; - localGdt->ptr.base = (uint32_t) &localGdt->entry; + g_gdt* localGdt = gdtList[processorGetCurrentId()]; + localGdt->ptr.limit = sizeof(g_gdt_descriptor) * G_GDT_BASE_LEN + sizeof(g_gdt_tss_descriptor) - 1; + localGdt->ptr.base = (g_address) &localGdt->entry; // Null descriptor, position 0x00 - gdtCreateGate(&localGdt->entry[0], 0, 0, 0, 0); + _gdtWriteEntry(&localGdt->entry[0], 0, 0, 0, 0); // Kernel code segment descriptor, position 0x08 - gdtCreateGate(&localGdt->entry[1], 0, 0xFFFFFFFF, G_ACCESS_BYTE__KERNEL_CODE_SEGMENT, 0xCF); + _gdtWriteEntry(&localGdt->entry[1], 0, 0xFFFFFFFF, G_ACCESS_BYTE__KERNEL_CODE_SEGMENT, + G_GDT_GRANULARITY_4KB | G_GDT_GRANULARITY_64BIT); // Kernel data segment descriptor, position 0x10 - gdtCreateGate(&localGdt->entry[2], 0, 0xFFFFFFFF, G_ACCESS_BYTE__KERNEL_DATA_SEGMENT, 0xCF); + _gdtWriteEntry(&localGdt->entry[2], 0, 0xFFFFFFFF, G_ACCESS_BYTE__KERNEL_DATA_SEGMENT, + G_GDT_GRANULARITY_4KB | G_GDT_GRANULARITY_64BIT); // User code segment descriptor, position 0x18 - gdtCreateGate(&localGdt->entry[3], 0, 0xFFFFFFFF, G_ACCESS_BYTE__USER_CODE_SEGMENT, 0xCF); + _gdtWriteEntry(&localGdt->entry[3], 0, 0xFFFFFFFF, G_ACCESS_BYTE__USER_CODE_SEGMENT, + G_GDT_GRANULARITY_4KB | G_GDT_GRANULARITY_64BIT); // User data segment descriptor, position 0x20 - gdtCreateGate(&localGdt->entry[4], 0, 0xFFFFFFFF, G_ACCESS_BYTE__USER_DATA_SEGMENT, 0xCF); + _gdtWriteEntry(&localGdt->entry[4], 0, 0xFFFFFFFF, G_ACCESS_BYTE__USER_DATA_SEGMENT, + G_GDT_GRANULARITY_4KB | G_GDT_GRANULARITY_64BIT); // TSS descriptor, position 0x28 - gdtCreateGate(&localGdt->entry[5], (uint32_t) &localGdt->tss, sizeof(g_tss), G_ACCESS_BYTE__TSS_386_SEGMENT, 0x40); - localGdt->tss.ss0 = G_GDT_DESCRIPTOR_KERNEL_DATA; // kernel data segment - localGdt->tss.esp0 = 0; // will later be initialized - - // User thread pointer segment 0x30 - gdtCreateGate(&localGdt->entry[6], 0, 0xFFFFFFFF, G_ACCESS_BYTE__USER_DATA_SEGMENT, 0xCF); - - // Kernel thread pointer segment 0x38 - gdtCreateGate(&localGdt->entry[7], 0, 0xFFFFFFFF, G_ACCESS_BYTE__KERNEL_DATA_SEGMENT, 0xCF); + _gdtWriteTssEntry(&localGdt->entryTss, (g_address) &localGdt->tss, sizeof(g_tss) - 1, + G_ACCESS_BYTE__TSS_386_SEGMENT, 0); + memorySetBytes(&localGdt->tss, 0, sizeof(g_tss)); + localGdt->tss.rsp0 = 0; + + // Load the GDT & TSS + asm volatile("lgdt %0" : : "m" (localGdt->ptr)); + asm volatile( + "movw $0x10, %%ax;" + "movw %%ax, %%ds;" + "movw %%ax, %%es;" + "movw %%ax, %%fs;" + "movw %%ax, %%gs;" + "movw %%ax, %%ss;" + "pushq $0x08;" + "pushq $reloadCS;" + "lretq;" + "reloadCS:" + : : : "ax" + ); + asm volatile("ltr %0"::"r"((uint16_t) G_GDT_DESCRIPTOR_TSS) : "memory"); +} - _loadGdt((uint32_t) &localGdt->ptr); - _loadTss(G_GDT_DESCRIPTOR_TSS); +void gdtSetTssRsp0(g_address rsp0) +{ + gdtList[processorGetCurrentId()]->tss.rsp0 = rsp0; } -void gdtSetTssEsp0(uint32_t esp0) +g_address gdtGetTssRsp0() { - gdtList[processorGetCurrentId()]->tss.esp0 = esp0; + return gdtList[processorGetCurrentId()]->tss.rsp0; } void gdtSetTlsAddresses(g_user_threadlocal* userThreadLocal, g_kernel_threadlocal* kernelThreadLocal) { - uint32_t processor = processorGetCurrentId(); + // TODO define constant IA32_FS_Base = 0xC0000100 and IA32_GS_BASE = 0xC0000101 + auto userAddress = (g_address) userThreadLocal; + processorWriteMsr(0xC0000100, userAddress & 0xFFFFFFFF, userAddress >> 32); + + auto kernelAddress = (g_address) kernelThreadLocal; + processorWriteMsr(0xC0000101, kernelAddress & 0xFFFFFFFF, kernelAddress >> 32); +} - g_gdt_list_entry* userLocalEntry = gdtList[processor]; - gdtCreateGate(&userLocalEntry->entry[6], (g_virtual_address) userThreadLocal, 0xFFFFFFFF, G_ACCESS_BYTE__USER_DATA_SEGMENT, 0xCF); +void _gdtWriteEntry(g_gdt_descriptor* entry, uint64_t base, uint64_t limit, uint8_t access, uint8_t granularity) +{ + entry->baseLow = (base & 0xFFFF); + entry->baseMiddle = (base >> 16) & 0xFF; + entry->baseHigh = (base >> 24) & 0xFF; + entry->limitLow = (limit & 0xFFFF); + entry->granularity = ((limit >> 16) & 0x0F) | (granularity & 0xF0); + entry->access = access; +} - g_gdt_list_entry* kernelLocalEntry = gdtList[processor]; - gdtCreateGate(&kernelLocalEntry->entry[7], (g_virtual_address) kernelThreadLocal, 0xFFFFFFFF, G_ACCESS_BYTE__KERNEL_DATA_SEGMENT, 0xCF); +void _gdtWriteTssEntry(g_gdt_tss_descriptor* entry, uint64_t base, uint64_t limit, uint8_t access, uint8_t granularity) +{ + _gdtWriteEntry(&entry->main, base, limit, access, granularity); + entry->baseUpper = (base >> 32) & 0xFFFFFFFF; } diff --git a/kernel/src/kernel/memory/gdt.hpp b/kernel/src/kernel/memory/gdt.hpp index 997384bd..2934f552 100644 --- a/kernel/src/kernel/memory/gdt.hpp +++ b/kernel/src/kernel/memory/gdt.hpp @@ -22,40 +22,139 @@ #define __KERNEL_GDT__ #include "kernel/tasking/tasking.hpp" -#include "shared/memory/gdt.hpp" #include "shared/memory/tss.hpp" #include #include -#define G_GDT_NUM_ENTRIES 8 +/** + * Macro to create the ACCESS byte for a GDT entry to a code or data segment + * + * Parameters: + * readWrite if code read allowed, if data write allowed + * codeOrData determines if its a code (1) or a data (0) segment + * privilege Privilege level (Ring 0 - Ring 3) + * present 1 if present + * + * Bits: Values: Info: + * 0 0 Accessed bit, free for developers use + * 1 parameter readWrite read if code segment, or write if data segment + * 2 0 Direction bit or conforming bit) + * 3 parameter codeOrData Entry is a code (1) or data (0) segment + * 4 0 Entry is for Code/Data (1) or Gate/TSS (0) + * 5 - 6 parameter privilege Ring 0 - Ring 3 + * 7 parameter present Must be 1 for active entry + */ +#define G_ACCESS_BYTE__FOR__CODE_OR_DATA(readWrite, codeOrData, privilege, present) \ + (0 | (readWrite << 1) | (0 << 2) | (codeOrData << 3) | (1 << 4) | (privilege << 5) | (present << 7)) + +/** + * Macro to create the ACCESS byte for a GDT entry to a Gate/TSS + * + * Parameters: + * segmentType e.g. 0x9 for 386-TSS + * privilege Privilege level (Ring 0 - Ring 3) + * present 1 if present + * + * Bits: Values: Info: + * 0 - 3 parameter segmentType Segment type + * 4 0 Entry is for Code/Data (1) or Gate/TSS (0) + * 5 - 6 parameter privilege Ring 0 - Ring 3 + * 7 parameter present Must be 1 for active entry + */ +#define G_ACCESS_BYTE__FOR__GATE_OR_TSS(segmentType, privilege, present) \ + (segmentType | (0 << 4) | (privilege << 5) | (present << 7)) -struct g_gdt_list_entry +/** + * Common descriptor access flags + */ +#define G_ACCESS_BYTE__KERNEL_CODE_SEGMENT G_ACCESS_BYTE__FOR__CODE_OR_DATA(1, 1, 0, 1) +#define G_ACCESS_BYTE__KERNEL_DATA_SEGMENT G_ACCESS_BYTE__FOR__CODE_OR_DATA(1, 0, 0, 1) +#define G_ACCESS_BYTE__USER_CODE_SEGMENT G_ACCESS_BYTE__FOR__CODE_OR_DATA(1, 1, 3, 1) +#define G_ACCESS_BYTE__USER_DATA_SEGMENT G_ACCESS_BYTE__FOR__CODE_OR_DATA(1, 0, 3, 1) +#define G_ACCESS_BYTE__TSS_386_SEGMENT G_ACCESS_BYTE__FOR__GATE_OR_TSS(0x9, 0, 1) + +/** + * Granularity bits + */ +#define G_GDT_GRANULARITY_4KB (1 << 7) // 1 = 4KB granularity, 0 = byte granularity +#define G_GDT_GRANULARITY_32BIT (1 << 6) // 1 = 32-bit protected mode, 0 = 16-bit +#define G_GDT_GRANULARITY_64BIT (1 << 5) // 1 = 64-bit mode, 0 = compatibility mode +#define G_GDT_GRANULARITY_AVAILABLE (1 << 4) // Available for system use + +/** + * Constants for our defined descriptor indexes + */ +#define G_GDT_DESCRIPTOR_KERNEL_CODE 0x08 +#define G_GDT_DESCRIPTOR_KERNEL_DATA 0x10 +#define G_GDT_DESCRIPTOR_USER_CODE 0x18 +#define G_GDT_DESCRIPTOR_USER_DATA 0x20 +#define G_GDT_DESCRIPTOR_TSS 0x28 + +#define G_SEGMENT_SELECTOR_RING0 0 // 00 +#define G_SEGMENT_SELECTOR_RING3 3 // 11 + +/** + * Number of entries in the GDT, not including the additional TSS part + */ +#define G_GDT_BASE_LEN 5 + +/** + * Structure of a GDT entry + */ +struct g_gdt_descriptor +{ + uint16_t limitLow; + uint16_t baseLow; + uint8_t baseMiddle; + uint8_t access; + uint8_t granularity; + uint8_t baseHigh; +} __attribute__((packed)); + +struct g_gdt_tss_descriptor { - g_gdt_pointer ptr; - g_gdt_entry entry[G_GDT_NUM_ENTRIES]; - g_tss tss; -}; + g_gdt_descriptor main; + uint32_t baseUpper; + uint32_t reserved0; +} __attribute__((packed)); /** - * Prepares the global GDT structures. + * Structure of the GDT pointer */ -void gdtPrepare(); +struct g_gdt_pointer +{ + uint16_t limit; + uint64_t base; +} __attribute__((packed)); /** - * Initializes the GDT for this core. + * + */ +struct g_gdt +{ + g_gdt_pointer ptr; + __attribute__((aligned(16))) g_gdt_descriptor entry[G_GDT_BASE_LEN]; + g_gdt_tss_descriptor entryTss; + + __attribute__((aligned(16))) g_tss tss; +} __attribute__((packed)); + +/** + * Prepares the global GDT structures. */ void gdtInitialize(); /** - * Retrieves the GDT for the core with the given id. + * Initializes the GDT for this core. */ -g_gdt_list_entry* gdtGetForCore(uint32_t coreId); +void gdtInitializeLocal(); /** - * Sets the ESP0 of the TSS of the current core the given address. + * Sets the RSP0 of the TSS of the current core the given address. * When switching from Ring 3 to Ring 0, this ESP is used as the new stack. */ -void gdtSetTssEsp0(g_virtual_address esp0); +void gdtSetTssRsp0(g_virtual_address rsp0); +g_address gdtGetTssRsp0(); /** * For thread local storage, it is necessary to write two addresses into our GDT so that we can do @@ -63,4 +162,5 @@ void gdtSetTssEsp0(g_virtual_address esp0); */ void gdtSetTlsAddresses(g_user_threadlocal* userThreadLocal, g_kernel_threadlocal* kernelThreadLocal); + #endif diff --git a/kernel/src/kernel/memory/heap.cpp b/kernel/src/kernel/memory/heap.cpp index d9a8064f..44121991 100644 --- a/kernel/src/kernel/memory/heap.cpp +++ b/kernel/src/kernel/memory/heap.cpp @@ -22,7 +22,7 @@ #include "kernel/memory/allocator.hpp" #include "kernel/memory/memory.hpp" #include "kernel/memory/paging.hpp" -#include "kernel/system/interrupts/interrupts.hpp" +#include "shared/memory/constants.hpp" #include "shared/panic.hpp" #include "shared/system/mutex.hpp" @@ -35,22 +35,35 @@ static bool heapInitialized = false; static g_mutex heapLock; bool _heapExpand(); +void _heapMapInitialArea(); -void heapInitialize(g_virtual_address start, g_virtual_address end) +void heapInitialize() { if(heapInitialized) panic("%! tried to initialized kernel heap twice", "kernheap"); + _heapMapInitialArea(); mutexInitializeGlobal(&heapLock, __func__); + memoryAllocatorInitialize(&heapAllocator, G_ALLOCATOR_TYPE_HEAP, heapStart, heapEnd); - memoryAllocatorInitialize(&heapAllocator, G_ALLOCATOR_TYPE_HEAP, start, end); - heapStart = start; - heapEnd = end; - - logDebug("%! initialized with area: %h - %h", "kernheap", start, end); + logDebug("%! initialized with area: %h - %h", "heap", heapStart, heapEnd); heapInitialized = true; } +void _heapMapInitialArea() +{ + heapStart = G_MEM_HEAP_START; + heapEnd = heapStart + G_MEM_HEAP_INITIAL_SIZE; + + g_address virt = heapStart; + while(virt < heapEnd) + { + g_physical_address addr = bitmapPageAllocatorAllocate(&memoryPhysicalAllocator); + pagingMapPage(virt, addr, G_PAGE_TABLE_KERNEL_DEFAULT, G_PAGE_KERNEL_DEFAULT); + virt += G_PAGE_SIZE; + } +} + void* heapAllocate(uint32_t size) { mutexAcquire(&heapLock); @@ -68,7 +81,7 @@ void* heapAllocate(uint32_t size) } panic("%! failed to allocate kernel memory", "kernheap"); - return 0; + return nullptr; } heapAmountInUse += size; @@ -110,13 +123,7 @@ uint32_t heapGetUsedAmount() bool _heapExpand() { - if(heapEnd + G_KERNEL_HEAP_EXPAND_STEP > G_KERNEL_HEAP_END) - { - logDebug("%! out of virtual memory area to map", "kernheap"); - return false; - } - - for(g_virtual_address virt = heapEnd; virt < heapEnd + G_KERNEL_HEAP_EXPAND_STEP; virt += G_PAGE_SIZE) + for(g_virtual_address virt = heapEnd; virt < heapEnd + G_MEM_KERN_HEAP_EXPAND_STEP; virt += G_PAGE_SIZE) { g_physical_address phys = memoryPhysicalAllocate(true); if(phys == 0) @@ -128,8 +135,8 @@ bool _heapExpand() pagingMapPage(virt, phys, G_PAGE_TABLE_KERNEL_DEFAULT, G_PAGE_KERNEL_DEFAULT); } - memoryAllocatorExpand(&heapAllocator, G_KERNEL_HEAP_EXPAND_STEP); - heapEnd += G_KERNEL_HEAP_EXPAND_STEP; + memoryAllocatorExpand(&heapAllocator, G_MEM_KERN_HEAP_EXPAND_STEP); + heapEnd += G_MEM_KERN_HEAP_EXPAND_STEP; logDebug("%! expanded to end %h (%ikb in use)", "kernheap", heapEnd, heapAmountInUse / 1024); diff --git a/kernel/src/kernel/memory/heap.hpp b/kernel/src/kernel/memory/heap.hpp index 4c3f004e..905398e2 100644 --- a/kernel/src/kernel/memory/heap.hpp +++ b/kernel/src/kernel/memory/heap.hpp @@ -21,13 +21,13 @@ #ifndef __KERNEL_HEAP__ #define __KERNEL_HEAP__ -#include "shared/memory/constants.hpp" #include /** - * Initializes the kernel heap using the given range of memory. + * Initializes the kernel heap. This maps an initial memory area and + * then performs an initialization of a memory allocator on this area. */ -void heapInitialize(g_virtual_address start, g_virtual_address end); +void heapInitialize(); /** * Allocates a number of bytes on the kernel heap. diff --git a/kernel/src/kernel/memory/memory.cpp b/kernel/src/kernel/memory/memory.cpp index 5acb9574..c4488084 100644 --- a/kernel/src/kernel/memory/memory.cpp +++ b/kernel/src/kernel/memory/memory.cpp @@ -23,49 +23,28 @@ #include "kernel/filesystem/filesystem.hpp" #include "kernel/kernel.hpp" #include "kernel/memory/heap.hpp" -#include "kernel/memory/lower_heap.hpp" +#include "shared/memory/constants.hpp" #include "kernel/memory/page_reference_tracker.hpp" #include "kernel/memory/paging.hpp" #include "kernel/tasking/task.hpp" #include "shared/logger/logger.hpp" -g_address_range_pool* memoryVirtualRangePool = 0; +g_address_range_pool* memoryVirtualRangePool = nullptr; -void _memoryRelocatePhysicalBitmap(g_setup_information* setupInformation) +void memoryInitialize(limine_memmap_response* memoryMap) { - uint32_t bitmapPages = ((setupInformation->bitmapArrayEnd - setupInformation->bitmapArrayStart) / G_PAGE_SIZE); - g_virtual_address bitmapVirtual = addressRangePoolAllocate(memoryVirtualRangePool, bitmapPages); + logInfo("%! initializing kernel memory with map at %x", "mem", memoryMap); - for(uint32_t i = 0; i < bitmapPages; i++) - { - g_offset off = (i * G_PAGE_SIZE); - pagingMapPage(bitmapVirtual + off, setupInformation->bitmapArrayStart + off, G_PAGE_TABLE_KERNEL_DEFAULT, - G_PAGE_KERNEL_DEFAULT); - } - bitmapPageAllocatorRelocate(&memoryPhysicalAllocator, bitmapVirtual); -} - -void memoryInitialize(g_setup_information* setupInformation) -{ - bitmapPageAllocatorInitialize(&memoryPhysicalAllocator, (g_bitmap_header*) setupInformation->bitmapArrayStart); + bitmapPageAllocatorInitialize(&memoryPhysicalAllocator, memoryMap); logInfo("%! available: %i MiB", "memory", (memoryPhysicalAllocator.freePageCount * G_PAGE_SIZE) / 1024 / 1024); - heapInitialize(setupInformation->heapStart, setupInformation->heapEnd); - lowerHeapInitialize(G_LOWER_HEAP_MEMORY_START, G_LOWER_HEAP_MEMORY_END); + heapInitialize(); memoryVirtualRangePool = (g_address_range_pool*) heapAllocate(sizeof(g_address_range_pool)); addressRangePoolInitialize(memoryVirtualRangePool); - addressRangePoolAddRange(memoryVirtualRangePool, G_KERNEL_VIRTUAL_RANGES_START, G_KERNEL_VIRTUAL_RANGES_END); + addressRangePoolAddRange(memoryVirtualRangePool, G_MEM_KERN_VIRT_RANGES_START, G_MEM_KERN_VIRT_RANGES_END); pageReferenceTrackerInitialize(); - - _memoryRelocatePhysicalBitmap(setupInformation); -} - -void memoryUnmapSetupMemory() -{ - for(g_virtual_address addr = G_LOWER_MEMORY_END; addr < G_KERNEL_AREA_START; addr += G_PAGE_SIZE) - pagingUnmapPage(addr); } g_physical_address memoryPhysicalAllocate(bool untracked) diff --git a/kernel/src/kernel/memory/memory.hpp b/kernel/src/kernel/memory/memory.hpp index 6d5287cd..aa66f69f 100644 --- a/kernel/src/kernel/memory/memory.hpp +++ b/kernel/src/kernel/memory/memory.hpp @@ -25,16 +25,14 @@ #include "kernel/memory/address_range_pool.hpp" #include "kernel/memory/paging.hpp" #include "shared/memory/memory.hpp" -#include "shared/setup_information.hpp" +#include class g_task; class g_process; extern g_address_range_pool* memoryVirtualRangePool; -void memoryInitialize(g_setup_information* setupInformation); - -void memoryUnmapSetupMemory(); +void memoryInitialize(limine_memmap_response* memoryMap); /** * Allocates a physical memory page. @@ -49,7 +47,7 @@ void memoryPhysicalFree(g_physical_address page); /** * Allocates and maps a memory range with the given number of pages. */ - g_virtual_address memoryAllocateKernel(int32_t pages); +g_virtual_address memoryAllocateKernel(int32_t pages); /** * Frees a memory range allocated with . diff --git a/kernel/src/kernel/memory/paging.cpp b/kernel/src/kernel/memory/paging.cpp index 002c5c31..8f6cbb66 100644 --- a/kernel/src/kernel/memory/paging.cpp +++ b/kernel/src/kernel/memory/paging.cpp @@ -19,17 +19,39 @@ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #include "kernel/memory/paging.hpp" +#include "shared/logger/logger.hpp" #include "shared/memory/constants.hpp" -g_physical_address pagingVirtualToPhysical(g_virtual_address addr) +g_physical_address pagingVirtualToPageEntry(g_virtual_address addr) { - uint32_t ti = G_TABLE_IN_DIRECTORY_INDEX(addr); - uint32_t pi = G_PAGE_IN_TABLE_INDEX(addr); + auto pml4 = (g_address*) G_MEM_PHYS_TO_VIRT(pagingGetCurrentSpace()); + uint64_t pml4Index = G_PML4_INDEX(addr); + uint64_t pdptAddr = pml4[pml4Index] & ~G_PAGE_ALIGN_MASK; + if(!pdptAddr) + return 0; - g_page_directory directory = (g_page_directory) G_RECURSIVE_PAGE_DIRECTORY_ADDRESS; - if(directory[ti] == 0) + auto pdpt = (g_address*) G_MEM_PHYS_TO_VIRT(pdptAddr); + uint64_t pdptIndex = G_PDPT_INDEX(addr); + uint64_t pdAddr = pdpt[pdptIndex] & ~G_PAGE_ALIGN_MASK; + if(!pdAddr) return 0; - g_page_table table = ((g_page_table) G_RECURSIVE_PAGE_DIRECTORY_AREA) + (0x400 * ti); - return table[pi] & ~G_PAGE_ALIGN_MASK; + auto pd = (g_address*) G_MEM_PHYS_TO_VIRT(pdAddr); + uint64_t pdIndex = G_PD_INDEX(addr); + uint64_t pdValue = pd[pdIndex]; + uint64_t ptAddr = pdValue & ~G_PAGE_ALIGN_MASK; + if(!ptAddr) + return 0; + + if(pdValue & G_PAGE_LARGE_PAGE_FLAG) + return pdValue & ~G_PAGE_ALIGN_MASK; + + auto pt = (g_address*) G_MEM_PHYS_TO_VIRT(ptAddr); + uint64_t ptIndex = G_PT_INDEX(addr); + return pt[ptIndex]; +} + +g_physical_address pagingVirtualToPhysical(g_virtual_address addr) +{ + return pagingVirtualToPageEntry(addr) & ~G_PAGE_ALIGN_MASK; } diff --git a/kernel/src/kernel/memory/paging.hpp b/kernel/src/kernel/memory/paging.hpp index fd5b3bbf..bb9cfb4c 100644 --- a/kernel/src/kernel/memory/paging.hpp +++ b/kernel/src/kernel/memory/paging.hpp @@ -36,4 +36,6 @@ */ g_physical_address pagingVirtualToPhysical(g_virtual_address addr); +g_physical_address pagingVirtualToPageEntry(g_virtual_address addr); + #endif diff --git a/kernel/src/kernel/system/acpi/acpi.cpp b/kernel/src/kernel/system/acpi/acpi.cpp index 10bc9bc4..468cff69 100644 --- a/kernel/src/kernel/system/acpi/acpi.cpp +++ b/kernel/src/kernel/system/acpi/acpi.cpp @@ -24,10 +24,11 @@ #include "shared/logger/logger.hpp" #include "shared/panic.hpp" #include "shared/utils/string.hpp" +#include "shared/memory/constants.hpp" #include -static g_acpi_table_header* acpiRoot = 0; -static g_acpi_entry* acpiTables = 0; +static g_acpi_table_header* acpiRoot = nullptr; +static g_acpi_entry* acpiTables = nullptr; static bool acpiRootIsXsdt = false; g_acpi_entry* acpiGetEntryWithSignature(const char* signature) @@ -44,9 +45,11 @@ g_acpi_entry* acpiGetEntryWithSignature(const char* signature) return nullptr; } -void acpiInitialize() +void acpiInitialize(g_physical_address rsdpPhys) { - g_rsdp_descriptor* rsdp = rsdpFind(); + auto rsdpPage = G_PAGE_ALIGN_DOWN(rsdpPhys); + pagingMapPage(G_MEM_PHYS_TO_VIRT(rsdpPage), rsdpPage,G_PAGE_TABLE_KERNEL_DEFAULT,G_PAGE_KERNEL_DEFAULT); + auto rsdp = (g_rsdp_descriptor*) G_MEM_PHYS_TO_VIRT(rsdpPhys); if(!rsdp) panic("%! failed to find RSDP", "acpi"); @@ -54,67 +57,46 @@ void acpiInitialize() for(uint32_t i = 0; i < acpiGetRSDTentryCount(); i++) { - g_physical_address entry = acpiGetRSDTentry(i); - if(entry != 0) - { - g_acpi_table_header* sdt = acpiMapSDT(entry); + g_physical_address sdtPhys = acpiGetRSDTentry(i); + if(!sdtPhys) + continue; - // Could not be mapped? Skip - if(sdt == 0) - continue; + g_acpi_table_header* sdt = acpiMapSDT(sdtPhys); + if(!sdt) + continue; - // Create the entry - g_acpi_entry* entry = new g_acpi_entry(); - entry->header = sdt; - entry->next = acpiTables; - acpiTables = entry; - } + auto entry = new g_acpi_entry(); + entry->header = sdt; + entry->next = acpiTables; + acpiTables = entry; } } void acpiPrepareRootSDT(g_rsdp_descriptor* rsdp) { - - g_physical_address rootTableLocation = 0; - + g_physical_address rootTablePhys = 0; acpiRootIsXsdt = false; // If ACPI 2.0 or higher, try to use the XSDT if(rsdp->revision > 0) { - g_rsdp_descriptor_20* rsdp20 = (g_rsdp_descriptor_20*) rsdp; + auto rsdp20 = (g_rsdp_descriptor_20*) rsdp; if(rsdp20->xsdtAddress != 0) { -#if __x86_64__ - rootTableLocation = rsdp20->xsdtAddress; + rootTablePhys = rsdp20->xsdtAddress; logDebug("%! found XSDT in 64bit range", "acpi"); acpiRootIsXsdt = true; -#elif __i386__ - if(rsdp20->xsdtAddress < 0xFFFFFFFF) - { - acpiRootIsXsdt = true; - logDebug("%! found XSDT in 32bit range", "acpi"); - rootTableLocation = rsdp20->xsdtAddress; - } - else - { - acpiRootIsXsdt = false; - logDebug("%! found XSDT, but range too high for 32bits, attempting to use RSDT", "acpi"); - } -#endif } } // No XSDT? Use RSDT if(!acpiRootIsXsdt) - { - rootTableLocation = rsdp->rsdtAddress; - } + rootTablePhys = rsdp->rsdtAddress; - if(!rootTableLocation) + if(!rootTablePhys) panic("%! failed to find ACPI root table", "acpi"); - g_acpi_table_header* header = acpiMapSDT(rootTableLocation); + g_acpi_table_header* header = acpiMapSDT(rootTablePhys); if(!header) panic("%! could not map root system descriptor table", "acpi"); @@ -124,7 +106,7 @@ void acpiPrepareRootSDT(g_rsdp_descriptor* rsdp) bool acpiValidateSDT(g_acpi_table_header* header) { uint8_t sum = 0; - uint8_t* tableBytes = reinterpret_cast(header); + auto tableBytes = reinterpret_cast(header); for(uint32_t i = 0; i < header->length; i++) sum += tableBytes[i]; @@ -136,26 +118,26 @@ uint32_t acpiGetLengthOfUnmappedSDT(g_physical_address tableLocation) { g_physical_address physStart = G_PAGE_ALIGN_DOWN(tableLocation); g_virtual_address virtualBase = addressRangePoolAllocate( - memoryVirtualRangePool, 2); + memoryVirtualRangePool, 2); // TODO may as well direct map to higher half if(!pagingMapPage(virtualBase, physStart, G_PAGE_TABLE_KERNEL_DEFAULT, - G_PAGE_KERNEL_DEFAULT)) + G_PAGE_KERNEL_DEFAULT)) { logWarn("%! could not create virtual mapping (1) for SDT %h", "acpi", - tableLocation); + tableLocation); return 0; } if(!pagingMapPage(virtualBase + G_PAGE_SIZE, physStart + G_PAGE_SIZE, - G_PAGE_TABLE_KERNEL_DEFAULT, G_PAGE_KERNEL_DEFAULT)) + G_PAGE_TABLE_KERNEL_DEFAULT, G_PAGE_KERNEL_DEFAULT)) { logWarn("%! could not create virtual mapping (2) for SDT %h", "acpi", - tableLocation); + tableLocation); return 0; } uint32_t mappingOffset = tableLocation - physStart; - g_acpi_table_header* header = (g_acpi_table_header*) (virtualBase + mappingOffset); + auto header = (g_acpi_table_header*) (virtualBase + mappingOffset); uint32_t length = header->length; pagingUnmapPage(virtualBase); @@ -171,15 +153,15 @@ g_acpi_table_header* acpiMapSDT(g_physical_address tableLocation) if(tableLength == 0) { logWarn("%! could not map SDT at phys %h, could not get table length", - "acpi", tableLocation); - return 0; + "acpi", tableLocation); + return nullptr; } if(tableLength > G_SDT_MAXIMUM_BYTES) { logWarn("%! SDT at %h was skipped due to illegal length (%h)", "acpi", - tableLocation, tableLength); - return 0; + tableLocation, tableLength); + return nullptr; } // Down/upalign physical range @@ -192,68 +174,56 @@ g_acpi_table_header* acpiMapSDT(g_physical_address tableLocation) // Calculate amount of physical pages and allocate virtual range uint32_t pages = (physEnd - physStart) / G_PAGE_SIZE; g_virtual_address virtualBase = addressRangePoolAllocate( - memoryVirtualRangePool, pages); + memoryVirtualRangePool, pages); // Could not find a virtual range of that size if(!virtualBase) { logWarn( - "%! could not find a free virtual range to map an SDT of size %i pages", - "acpi", pages); - return 0; + "%! could not find a free virtual range to map an SDT of size %i pages", + "acpi", pages); + return nullptr; } // Map the pages - for(g_virtual_address off = 0; off < (physEnd - physStart); off += - G_PAGE_SIZE) + for(g_virtual_address off = 0; off < (physEnd - physStart); off += G_PAGE_SIZE) { pagingMapPage(virtualBase + off, physStart + off, - G_PAGE_TABLE_KERNEL_DEFAULT, G_PAGE_KERNEL_DEFAULT); + G_PAGE_TABLE_KERNEL_DEFAULT, G_PAGE_KERNEL_DEFAULT); } // Get the header pointer - g_acpi_table_header* header = (g_acpi_table_header*) (virtualBase + mappingOffset); + auto header = (g_acpi_table_header*) (virtualBase + mappingOffset); // Validate the table if(!acpiValidateSDT(header)) { logWarn("%! descriptor table was not valid", "acpi"); - return 0; + return nullptr; } - // Now return the tables header return header; } uint32_t acpiGetRSDTentryCount() { - uint32_t entryBytes = acpiRoot->length - sizeof(g_acpi_table_header); if(acpiRootIsXsdt) { return entryBytes / 8; } - else - { - return entryBytes / 4; - } + return entryBytes / 4; } g_physical_address acpiGetRSDTentry(uint32_t index) { - g_virtual_address startOfEntries = ((g_virtual_address) acpiRoot) + sizeof(g_acpi_table_header); if(acpiRootIsXsdt) { return ((uint64_t*) startOfEntries)[index]; } - else - { - return ((uint32_t*) startOfEntries)[index]; - } - - return 0; + return ((uint32_t*) startOfEntries)[index]; } bool acpiEntryHasSignature(g_acpi_entry* entry, const char* signature) diff --git a/kernel/src/kernel/system/acpi/acpi.hpp b/kernel/src/kernel/system/acpi/acpi.hpp index 90dc9487..963456a0 100644 --- a/kernel/src/kernel/system/acpi/acpi.hpp +++ b/kernel/src/kernel/system/acpi/acpi.hpp @@ -69,7 +69,7 @@ struct g_acpi_entry /** * Initializes ACPI by reading the tables */ -void acpiInitialize(); +void acpiInitialize(g_physical_address rsdp); /** * Prepares the root SDT (RSTD or XSDT) by mapping the required diff --git a/kernel/src/kernel/system/interrupts/apic/lapic.cpp b/kernel/src/kernel/system/interrupts/apic/lapic.cpp index cb110280..190cfa26 100644 --- a/kernel/src/kernel/system/interrupts/apic/lapic.cpp +++ b/kernel/src/kernel/system/interrupts/apic/lapic.cpp @@ -90,8 +90,8 @@ void lapicCreateMapping() // "APIC registers are memory-mapped to a 4-KByte region of the processor’s physical // address space with an initial starting address of FEE00000H." - x86 System Programming Manual, 10.4.1 - pagingMapPage(virtualBase, physicalBase, G_PAGE_TABLE_KERNEL_DEFAULT, - G_PAGE_KERNEL_DEFAULT | G_PAGE_CACHE_DISABLED); + pagingMapPage(virtualBase, physicalBase,G_PAGE_TABLE_KERNEL_DEFAULT, G_PAGE_TABLE_KERNEL_DEFAULT, + G_PAGE_TABLE_KERNEL_DEFAULT,G_PAGE_KERNEL_UNCACHED); } uint32_t lapicReadId() diff --git a/kernel/src/kernel/system/interrupts/exceptions.cpp b/kernel/src/kernel/system/interrupts/exceptions.cpp index b580aad9..5dc89cbd 100644 --- a/kernel/src/kernel/system/interrupts/exceptions.cpp +++ b/kernel/src/kernel/system/interrupts/exceptions.cpp @@ -19,6 +19,9 @@ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #include "kernel/system/interrupts/exceptions.hpp" + +#include + #include "kernel/memory/memory.hpp" #include "kernel/memory/page_reference_tracker.hpp" #include "kernel/memory/paging.hpp" @@ -28,9 +31,6 @@ #include "kernel/tasking/tasking.hpp" #include "kernel/tasking/tasking_memory.hpp" #include "shared/logger/logger.hpp" -#include "shared/panic.hpp" - -#define DEBUG_PRINT_STACK_TRACE 1 /** * Names of the exceptions @@ -61,9 +61,9 @@ static const char* EXCEPTION_NAMES[] = { "reserved exception", "reserved exception" // reserved exceptions }; -uint32_t exceptionsGetCR2() +g_address exceptionsGetCR2() { - uint32_t addr; + g_address addr; asm volatile("mov %%cr2, %0" : "=r"(addr)); return addr; @@ -71,9 +71,11 @@ uint32_t exceptionsGetCR2() bool exceptionsHandleDivideError(g_task* task) { - uint8_t* faulting_instruction = (uint8_t*) task->state->eip; + if(!task) + return false; - uint8_t opcode = faulting_instruction[0]; + auto faultyInstruction = (uint8_t*) task->state->rip; + uint8_t opcode = faultyInstruction[0]; int skip = 1; if( @@ -82,7 +84,7 @@ bool exceptionsHandleDivideError(g_task* task) ) { skip = 2; - uint8_t modrm = faulting_instruction[1]; + uint8_t modrm = faultyInstruction[1]; uint8_t mod = (modrm >> 6) & 0x3; if(mod == 1) skip += 1; @@ -90,135 +92,188 @@ bool exceptionsHandleDivideError(g_task* task) skip += 4; } - task->state->eip += skip; + task->state->rip += skip; - logInfo("%! Divide error in task %i, skipping to EIP: %x", "exception", task->id, task->state->eip); + logInfo("%! divide error in task %i at %x, skipping to RIP: %x", "exception", task->id, faultyInstruction, + task->state->rip); return true; } -/** - * Dumps the current CPU state to the log file - */ -void exceptionsDumpTask(g_task* task) +g_elf_object* exceptionsFindResponsibleObject(g_task* task, g_address rip) { - auto state = task->state; - g_process* process = task->process; - logInfo("%! %s in task %i (process %i)", "exception", EXCEPTION_NAMES[state->intr], task->id, process->main->id); + g_elf_object* object = nullptr; - if(state->intr == 0x0E) + auto iter = hashmapIteratorStart(task->process->object->loadedObjects); + while(hashmapIteratorHasNext(&iter)) { - // Page fault - logInfo("%# accessed address: %h", exceptionsGetCR2()); + auto nextObject = hashmapIteratorNext(&iter)->value; + if(rip >= nextObject->startAddress && rip < nextObject->endAddress) + { + object = nextObject; + break; + } } - logInfo("%# eip: %h eflags: %h", state->eip, state->eflags); - logInfo("%# eax: %h ebx: %h", state->eax, state->ebx); - logInfo("%# ecx: %h edx: %h", state->ecx, state->edx); - logInfo("%# esp: %h ebp: %h", state->esp, state->ebp); - logInfo("%# intr: %h error: %h", state->intr, state->error); - logInfo("%# task stack: %h - %h", task->stack.start, task->stack.end); - logInfo("%# intr stack: %h - %h", task->interruptStack.start, task->interruptStack.end); + hashmapIteratorEnd(&iter); - auto iter = hashmapIteratorStart(task->process->object->loadedObjects); - while(hashmapIteratorHasNext(&iter)) + return object; +} + +Elf64_Sym* exceptionsFindFunctionSymbol(g_elf_object* object, g_address rip) +{ + if(object->root) { - auto object = hashmapIteratorNext(&iter)->value; + // TODO: Symbol lookup only works well for shared libs so far, for some reason + return nullptr; + } - logInfo("%# obj %x-%x: %s", object->startAddress, object->endAddress, object->name); + Elf64_Sym* bestMatch = nullptr; + g_address localRip = rip - object->baseAddress; - if(state->eip >= object->startAddress && state->eip < object->endAddress) + for(uint64_t symbolIndex = 0; symbolIndex < object->dynamicSymbolTableSize; symbolIndex++) + { + auto& symbol = object->dynamicSymbolTable[symbolIndex]; + + if(ELF64_ST_TYPE(symbol.st_info) == STT_FUNC) { - if(object == task->process->object) + if(localRip >= symbol.st_value && + localRip < symbol.st_value + symbol.st_size) { - logInfo("%# caused in executable object"); + return &symbol; } - else + + if(localRip >= symbol.st_value && + (!bestMatch || symbol.st_value > bestMatch->st_value)) { - logInfo("%# caused in object '%s' at offset %x", object->name, state->eip - object->baseAddress); + bestMatch = &symbol; } - break; } } - hashmapIteratorEnd(&iter); -#if DEBUG_PRINT_STACK_TRACE - g_address* ebp = reinterpret_cast(state->ebp); + return bestMatch; +} + +void exceptionsPrintCallAtRip(g_task* task, g_address rip) +{ + auto object = exceptionsFindResponsibleObject(task, rip); + auto function = object ? exceptionsFindFunctionSymbol(object, rip) : nullptr; + + if(object && function) + { + auto functionName = function->st_name ? &object->dynamicStringTable[function->st_name] : "?"; + logInfo("%# %h (%s <%s> %h)", rip, object->name, functionName, rip - object->baseAddress); + } + else if(object) + { + logInfo("%# %h (%s %h)", rip, object->name, rip - object->baseAddress); + } + else + { + logInfo("%# %h", rip); + } +} + +void exceptionsPrintStackTrace(g_task* task, volatile g_processor_state* state) +{ logInfo("%# stack trace:"); - for(int frame = 0; frame < 8; ++frame) + exceptionsPrintCallAtRip(task, state->rip); + + auto rbp = reinterpret_cast(state->rbp); + for(int frame = 0; frame < 25; ++frame) { - g_address eip = ebp[1]; - if(eip < 0x1000) + g_address rip = rbp[1]; + if(rip < 0x1000) { break; } - ebp = reinterpret_cast(ebp[0]); - logInfo("%# %h", eip); + rbp = reinterpret_cast(rbp[0]); + + exceptionsPrintCallAtRip(task, rip); } -#endif } -bool exceptionsHandlePageFault(g_task* task) +/** + * Dumps the current CPU state to the log file + */ +void exceptionsDumpState(g_task* task, volatile g_processor_state* state) { - g_virtual_address accessed = exceptionsGetCR2(); - - if(taskingMemoryHandleStackOverflow(task, accessed)) - return true; - - if(memoryOnDemandHandlePageFault(task, accessed)) - return true; - - g_physical_address physPage = pagingVirtualToPhysical(G_PAGE_ALIGN_DOWN(accessed)); - logInfo("%! task %i (core %i) EIP: %x (accessed %h, mapped page %h)", "pagefault", task->id, - processorGetCurrentId(), task->state->eip, accessed, physPage); + g_process* process = task ? task->process : nullptr; + logInfo("%! (task %i, process %i) %s", "exception", task ? task->id : G_TID_NONE, + process ? process->main->id : G_TID_NONE, EXCEPTION_NAMES[state->intr]); - exceptionsDumpTask(task); - - if(task->type == G_TASK_TYPE_VITAL) - { - return false; - } - if(task->securityLevel == G_SECURITY_LEVEL_KERNEL) + if(state->intr == 0x0E) { - task->status = G_TASK_STATUS_DEAD; + // Page fault + logInfo("%# accessed address: %h", exceptionsGetCR2()); } - else + logInfo("%# INTR: %h ERROR: %h", state->intr, state->error); + logInfo("%# RIP: %h RFLAGS: %h", state->rip, state->rflags); + logInfo("%# CS: %h SS: %h", state->cs, state->ss); + logInfo("%# RSP: %h RBP: %h", state->rbp, state->rbp); + logInfo("%# RAX: %h RBX: %h %RCX: %h RDX: %h", state->rax, state->rbx, state->rcx, state->rdx); + if(task) { - // TODO Somehow give the user task a chance to do something - task->status = G_TASK_STATUS_DEAD; + logInfo("%# task stack: %h - %h", task->stack.start, task->stack.end); + logInfo("%# intr stack: %h - %h", task->interruptStack.start, task->interruptStack.end); + + logInfo("%# loaded objects:"); + auto iter = hashmapIteratorStart(task->process->object->loadedObjects); + while(hashmapIteratorHasNext(&iter)) + { + auto object = hashmapIteratorNext(&iter)->value; + + logInfo("%# %x-%x: %s", object->startAddress, object->endAddress, object->name); + } + hashmapIteratorEnd(&iter); } - taskingSchedule(); - return true; + + exceptionsPrintStackTrace(task, state); } -bool exceptionsHandleGeneralProtectionFault(g_task* task) +bool exceptionsHandlePageFault(g_task* task, volatile g_processor_state* state) { - if(task->type == G_TASK_TYPE_VM86) - { + g_virtual_address accessed = exceptionsGetCR2(); + g_physical_address pageEntryValue = pagingVirtualToPageEntry(G_PAGE_ALIGN_DOWN(accessed)); - g_virtual_monitor_handling_result result = vm86MonitorHandleGpf(task); + if(task) + { + if(taskingMemoryHandleStackOverflow(task, accessed)) + return true; - if(result == VIRTUAL_MONITOR_HANDLING_RESULT_SUCCESSFUL) - { + if(memoryOnDemandHandlePageFault(task, accessed)) return true; - } - else if(result == VIRTUAL_MONITOR_HANDLING_RESULT_FINISHED) - { + + logInfo("%! (task %i, core %i) RIP: %x (accessed %h, mapping value: %h)", "pagefault", task->id, + processorGetCurrentId(), state->rip, accessed, pageEntryValue); + + exceptionsDumpState(task, state); + + if(task->type == G_TASK_TYPE_VITAL) + return false; + + if(task->securityLevel == G_SECURITY_LEVEL_KERNEL) task->status = G_TASK_STATUS_DEAD; - taskingSchedule(); - return true; - } - else if(result == VIRTUAL_MONITOR_HANDLING_RESULT_UNHANDLED_OPCODE) - { - logInfo("%! %i unable to handle gpf for vm86 task", "exception", processorGetCurrentId()); + else + // TODO Somehow give the user task a chance to do something task->status = G_TASK_STATUS_DEAD; - taskingSchedule(); - return true; - } + + taskingSchedule(); + return true; } - exceptionsDumpTask(task); + logInfo("%! RIP: %x (accessed %h, mapping value: %h)", "pagefault", processorGetCurrentId(), state->rip, accessed, + pageEntryValue); + return false; +} + +bool exceptionsHandleGeneralProtectionFault(g_task* task, volatile g_processor_state* state) +{ + exceptionsDumpState(task, state); + + if(!task) + return false; logInfo("%! #%i task %i killed due to general protection fault at EIP %h", "exception", processorGetCurrentId(), - task->id, task->state->eip); + task->id, task->state->rip); task->status = G_TASK_STATUS_DEAD; taskingSchedule(); return true; @@ -227,20 +282,17 @@ bool exceptionsHandleGeneralProtectionFault(g_task* task) bool exceptionsKillTask(g_task* task) { logInfo("%! task %i killed due to exception %i (error %i) at EIP %h", "exception", task->id, task->state->intr, - task->state->error, task->state->eip); + task->state->error, task->state->rip); task->status = G_TASK_STATUS_DEAD; taskingSchedule(); return true; } -void exceptionsHandle(g_task* task) +void exceptionsHandle(g_task* task, volatile g_processor_state* state) { bool resolved = false; - if(!task) - panic("%! unresolved exception before initializing tasking system", "exceptions"); - - switch(task->state->intr) + switch(state->intr) { case 0x00: { @@ -251,13 +303,13 @@ void exceptionsHandle(g_task* task) case 0x0E: { // Page fault - resolved = exceptionsHandlePageFault(task); + resolved = exceptionsHandlePageFault(task, state); break; } case 0x0D: { // General protection fault - resolved = exceptionsHandleGeneralProtectionFault(task); + resolved = exceptionsHandleGeneralProtectionFault(task, state); break; } case 0x06: @@ -270,9 +322,9 @@ void exceptionsHandle(g_task* task) if(!resolved) { - logInfo("%*%! task %i caused unresolved exception %i (error %i) at EIP: %h ESP: %h", 0x0C, "exception", - task->id, task->state->intr, - task->state->error, task->state->eip, task->state->esp); + logInfo("%*%! (task %i) unresolved exception %i (error %i) at RIP: %h RSP: %h", 0x0C, "exception", + task ? task->id : G_TID_NONE, state->intr, + state->error, state->rip, state->rsp); for(;;) { asm("hlt"); diff --git a/kernel/src/kernel/system/interrupts/exceptions.hpp b/kernel/src/kernel/system/interrupts/exceptions.hpp index d8ab5e14..cb36c8e0 100644 --- a/kernel/src/kernel/system/interrupts/exceptions.hpp +++ b/kernel/src/kernel/system/interrupts/exceptions.hpp @@ -23,6 +23,6 @@ #include "kernel/tasking/tasking.hpp" -void exceptionsHandle(g_task* task); +void exceptionsHandle(g_task* task, volatile g_processor_state* state); #endif diff --git a/kernel/src/kernel/system/interrupts/idt.cpp b/kernel/src/kernel/system/interrupts/idt.cpp index f1d3485c..a7258eee 100644 --- a/kernel/src/kernel/system/interrupts/idt.cpp +++ b/kernel/src/kernel/system/interrupts/idt.cpp @@ -19,9 +19,9 @@ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #include "kernel/system/interrupts/idt.hpp" -#include "kernel/system/processor/processor.hpp" #include "shared/logger/logger.hpp" -#include "shared/memory/gdt_macros.hpp" +#include "kernel/memory/gdt.hpp" +#include "ghost/memory/types.h" /** * IDT pointer structure @@ -33,19 +33,28 @@ g_idt_pointer idtPointer; */ __attribute__((aligned(8))) g_idt_entry idt[256]; -void idtCreateGate(uint32_t index, void* base, uint8_t flags) +void idtCreateGate(uint32_t index, void* base, uint8_t flags, uint8_t ist) { - idt[index].baseLow = ((uint32_t) base) & 0xFFFF; - idt[index].baseHigh = (((uint32_t) base) >> 16) & 0xFFFF; + uint64_t baseAddr = (uint64_t) base; + idt[index].baseLow = baseAddr & 0xFFFF; + idt[index].baseMid = (baseAddr >> 16) & 0xFFFF; + idt[index].baseHigh = (baseAddr >> 32) & 0xFFFFFFFF; idt[index].kernelSegment = G_GDT_DESCRIPTOR_KERNEL_CODE; - idt[index].zero = 0; + idt[index].reserved = 0; + idt[index].ist = ist & 0x7; // Only use the 3 lowest bits for IST idt[index].flags = flags; } -void idtPrepare() +void idtCreateGate(uint32_t index, void* base, uint8_t flags) +{ + idtCreateGate(index, base, flags, 0); // Default IST value is 0 +} + + +void idtInitialize() { idtPointer.limit = (sizeof(g_idt_entry) * 256) - 1; - idtPointer.base = (uint32_t) &idt; + idtPointer.base = (g_address) &idt; uint8_t* idtp = (uint8_t*) (&idt); for(uint32_t i = 0; i < sizeof(g_idt_entry) * 256; i++) @@ -54,11 +63,13 @@ void idtPrepare() } } -void idtLoad() +void idtInitializeLocal() { - // Load the IDT - logDebug("%! descriptor table lays at %h", "idt", &idt); - logDebug("%! pointer at %h, base %h, limit %h", "idt", &idtPointer, idtPointer.base, idtPointer.limit); - _loadIdt((uint32_t) &idtPointer); - logDebug("%! loaded on core %i", "idt", processorGetCurrentId()); + auto idtPointerAddr = (g_address) &idtPointer; + asm volatile ( + "lidt (%0)" + : + : "r" (idtPointerAddr) + : "memory" + ); } diff --git a/kernel/src/kernel/system/interrupts/idt.hpp b/kernel/src/kernel/system/interrupts/idt.hpp index 28605ec6..f4407abf 100644 --- a/kernel/src/kernel/system/interrupts/idt.hpp +++ b/kernel/src/kernel/system/interrupts/idt.hpp @@ -34,34 +34,35 @@ #define G_IDT_FLAGS_PRIVILEGE_RING3 0b01100000 #define G_IDT_FLAGS_GATE_TYPE_TASK 0b00000101 -#define G_IDT_FLAGS_GATE_TYPE_INTERRUPT_16 0b00000110 -#define G_IDT_FLAGS_GATE_TYPE_INTERRUPT_32 0b00001110 -#define G_IDT_FLAGS_GATE_TYPE_TRAP_16 0b00000111 -#define G_IDT_FLAGS_GATE_TYPE_TRAP_32 0b00001111 +#define G_IDT_FLAGS_GATE_TYPE_INTERRUPT_64 0b00001110 +#define G_IDT_FLAGS_GATE_TYPE_TRAP_64 0b00001111 -#define G_IDT_FLAGS_INTERRUPT_GATE_KERNEL (G_IDT_FLAGS_SEGMENT_PRESENT | G_IDT_FLAGS_GATE_TYPE_INTERRUPT_32 | G_IDT_FLAGS_PRIVILEGE_RING0) -#define G_IDT_FLAGS_INTERRUPT_GATE_USER (G_IDT_FLAGS_SEGMENT_PRESENT | G_IDT_FLAGS_GATE_TYPE_INTERRUPT_32 | G_IDT_FLAGS_PRIVILEGE_RING3) +// Combined flags for common uses +#define G_IDT_FLAGS_INTERRUPT_GATE_KERNEL (G_IDT_FLAGS_SEGMENT_PRESENT | G_IDT_FLAGS_GATE_TYPE_INTERRUPT_64 | G_IDT_FLAGS_PRIVILEGE_RING0) +#define G_IDT_FLAGS_INTERRUPT_GATE_USER (G_IDT_FLAGS_SEGMENT_PRESENT | G_IDT_FLAGS_GATE_TYPE_INTERRUPT_64 | G_IDT_FLAGS_PRIVILEGE_RING3) /** - * Structure of the IDT pointer + * Structure of the IDT pointer for x86_64 */ struct g_idt_pointer { - uint16_t limit; - uint32_t base; + uint16_t limit; + uint64_t base; }__attribute__((packed)); /** - * Structure of an IDT entry + * Structure of an IDT entry for x86_64 */ struct g_idt_entry { - uint16_t baseLow; - uint16_t kernelSegment; - uint8_t zero; - uint8_t flags; - uint16_t baseHigh; + uint16_t baseLow; + uint16_t kernelSegment; + uint8_t ist; + uint8_t flags; + uint16_t baseMid; + uint32_t baseHigh; + uint32_t reserved; }__attribute__((packed)); /** @@ -75,14 +76,14 @@ extern "C" void _loadIdt(uint32_t idtPointerAddress); /** * Installs the interrupt descriptor table. */ -void idtPrepare(); +void idtInitialize(); /** * Installs the interrupt descriptor table. * * @reentrancy the same table is loaded on each core, therefore no locking necessary */ -void idtLoad(); +void idtInitializeLocal(); /** * Fills the given values into the given IDT entry diff --git a/kernel/src/kernel/system/interrupts/idt_mounter.asm b/kernel/src/kernel/system/interrupts/idt_mounter.asm deleted file mode 100644 index a139ba57..00000000 --- a/kernel/src/kernel/system/interrupts/idt_mounter.asm +++ /dev/null @@ -1,45 +0,0 @@ -;* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * -;* * -;* Ghost, a micro-kernel based operating system for the x86 architecture * -;* Copyright (C) 2015, Max Schlüssel * -;* * -;* This program 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. * -;* * -;* This program 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 this program. If not, see . * -;* * -;* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - - -BITS 32 - -global _loadIdt - -; -; void _loadIdt(uint32_t idtPointerAddress) -; -; Mounts the interrupt descriptor table -; -; Parameters: -; idtPointerAddress ebp + 8 -; -_loadIdt: - ; Prologue - push ebp - mov ebp, esp - - ; Load IDT - mov eax, [ebp + 8] - lidt [eax] - - ; Epilogue - pop ebp - ret diff --git a/kernel/src/kernel/system/interrupts/interrupt_routines.asm b/kernel/src/kernel/system/interrupts/interrupt_routines.asm index 7ace4d88..ef4aad9c 100644 --- a/kernel/src/kernel/system/interrupts/interrupt_routines.asm +++ b/kernel/src/kernel/system/interrupts/interrupt_routines.asm @@ -18,14 +18,12 @@ ;* * ;* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -BITS 32 +BITS 64 ; ; C handler functions ; extern _interruptHandler - ; ; Handler routine ; @@ -37,15 +35,15 @@ interruptRoutine: ; ; [Ring 3 -> Ring 0] ; push ss - ; push esp - ; push eflags + ; push rsp + ; push rflags ; push cs - ; push eip + ; push rip ; ; [Ring 0 -> Ring 0] - ; push eflags + ; push rflags ; push cs - ; push eip + ; push rip ; ; This is the reason we give the stack pointer to our interrupt handler. ; The interrupt handler will then return the stack that we can pop the @@ -53,72 +51,85 @@ interruptRoutine: ; ; Store general purpose - push edi - push esi - push ebp - push ebx - push edx - push ecx - push eax + push rax + push rcx + push rdx + push rbx + push rbp + push rsi + push rdi + + push r8 + push r9 + push r10 + push r11 + push r12 + push r13 + push r14 + push r15 ; Store segments - push ds - push es - push fs - push gs + mov ax, ds + push rax + mov ax, es + push rax + + ; Switch to kernel segments + mov ax, 0x10 + mov ds, ax + mov es, ax - ; Switch to kernel segments - mov ax, 0x10 - mov ds, ax - mov es, ax - mov fs, ax - mov ss, ax - ; Segment points to kernel thread-local data - mov ax, 0x38 - mov gs, ax + ; Stack pointer argument + mov rdi, rsp + ; Call handler + call _interruptHandler + ; Set stack pointer from return value + mov rsp, rax - ; Stack pointer argument - push esp - ; Call handler - call _interruptHandler - ; Set stack from return value - mov esp, eax + ; Restore segments + pop rax + mov ds, ax + pop rax + mov es, ax - ; Restore segments - pop gs - pop fs - pop es - pop ds + ; Restore all registers + pop r15 + pop r14 + pop r13 + pop r12 + pop r11 + pop r10 + pop r9 + pop r8 - ; Restore general purpose - pop eax - pop ecx - pop edx - pop ebx - pop ebp - pop esi - pop edi + pop rdi + pop rsi + pop rbp + pop rbx + pop rdx + pop rcx + pop rax - ; Skip intr and error in Registers struct - add esp, 8 + ; Skip past the error code and interrupt number + add rsp, 16 ; - ; Now we return and on IRET the processor again pops specific registers. - ; If we switch to a kernel-level task, ESP and SS will not be popped. + ; Now we return and on IRETQ the processor again pops specific registers. + ; If we switch to a kernel-level task, RSP and SS will not be popped. ; ; [Ring 0 -> Ring 0] - ; pop eip + ; pop rip ; pop cs - ; pop eflags + ; pop rflags ; ; [Ring 0 -> Ring 3] - ; pop eip + ; pop rip ; pop cs - ; pop eflags - ; pop esp + ; pop rflags + ; pop rsp ; pop ss ; - iret + iretq ; Handling routine macros diff --git a/kernel/src/kernel/system/interrupts/interrupts.cpp b/kernel/src/kernel/system/interrupts/interrupts.cpp index de648338..6f325c21 100644 --- a/kernel/src/kernel/system/interrupts/interrupts.cpp +++ b/kernel/src/kernel/system/interrupts/interrupts.cpp @@ -19,6 +19,7 @@ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #include "kernel/system/interrupts/interrupts.hpp" +#include "kernel/memory/gdt.hpp" #include "shared/logger/logger.hpp" #include "kernel/calls/syscall.hpp" #include "kernel/system/interrupts/apic/ioapic.hpp" @@ -37,8 +38,8 @@ void _interruptsSendEndOfInterrupt(uint8_t irq); void interruptsInitializeBsp() { - idtPrepare(); - idtLoad(); + idtInitialize(); + idtInitializeLocal(); interruptsInstallRoutines(); requestsInitialize(); @@ -60,7 +61,7 @@ void interruptsInitializeBsp() void interruptsInitializeAp() { - idtLoad(); + idtInitializeLocal(); lapicInitialize(); } @@ -72,7 +73,7 @@ extern "C" volatile g_processor_state* _interruptHandler(volatile g_processor_st if(state->intr < 0x20) // Exception { - exceptionsHandle(task); + exceptionsHandle(task, state); } else if(state->intr == 0x80) // Syscall { @@ -106,6 +107,7 @@ extern "C" volatile g_processor_state* _interruptHandler(volatile g_processor_st panic("%! attempted to switch to null task (%x) or state (%x)", "system", newTask, newTask->state); if(newTask != task) taskingRestoreState(newTask); + return newTask->state; } diff --git a/kernel/src/kernel/system/processor/processor.asm b/kernel/src/kernel/system/processor/processor.asm index accabca4..727de508 100644 --- a/kernel/src/kernel/system/processor/processor.asm +++ b/kernel/src/kernel/system/processor/processor.asm @@ -1,6 +1,6 @@ ;* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * ;* * -;* Ghost, a micro-kernel based operating system for the x86 architecture * +;* Ghost, a micro-kernel based operating system for the x86_64 architecture * ;* Copyright (C) 2015, Max Schlüssel * ;* * ;* This program is free software: you can redistribute it and/or modify * @@ -19,7 +19,7 @@ ;* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ -BITS 32 +BITS 64 global _checkForCPUID global _enableSSE @@ -29,23 +29,23 @@ global _enableSSE ; ; Checks if the CPUID instruction is available. This is implemented in ; pure assembly, because C/C++ could cause race conditions due to the -; ability of the compiler to modify the EFLAGS when it needs to. +; ability of the compiler to modify the RFLAGS when it needs to. ; _checkForCPUID: - pushfd - pop eax - mov ecx, eax - xor eax, 0x200000 - push eax - popfd - pushfd - pop eax - xor eax, ecx - shr eax, 21 - and eax, 1 - push ecx - popfd - ret + pushfq + pop rax + mov rcx, rax + xor rax, 0x200000 + push rax + popfq + pushfq + pop rax + xor rax, rcx + shr rax, 21 + and rax, 1 + push rcx + popfq + ret ; ; void enableSSE() @@ -56,23 +56,23 @@ _enableSSE: fninit fclex - push dword 0x037F - fldcw [esp] ; load default control word - add esp, 4 + push qword 0x037F + fldcw [rsp] ; load default control word + add rsp, 8 - mov eax, cr0 - and eax, ~(1 << 2) ; clear CR0.EM coprocessor emulation - or eax, (1 << 1) ; set CR0.MP monitor coprocessor - mov cr0, eax + mov rax, cr0 + and rax, ~(1 << 2) ; clear CR0.EM coprocessor emulation + or rax, (1 << 1) ; set CR0.MP monitor coprocessor + mov cr0, rax - mov eax, cr4 - or eax, (1 << 9) ; set CR4.OSFXSR - or eax, (1 << 10) ; set CR4.OSXMMEXCPT - mov cr4, eax + mov rax, cr4 + or rax, (1 << 9) ; set CR4.OSFXSR + or rax, (1 << 10) ; set CR4.OSXMMEXCPT + mov cr4, rax - push dword 0x1F80 - ldmxcsr [esp] ; load default settings to MXCSR - add esp, 4 + push qword 0x1F80 + ldmxcsr [rsp] ; load default settings to MXCSR + add rsp, 8 - ret + ret diff --git a/kernel/src/kernel/system/processor/processor.cpp b/kernel/src/kernel/system/processor/processor.cpp index cd949651..37d9395b 100644 --- a/kernel/src/kernel/system/processor/processor.cpp +++ b/kernel/src/kernel/system/processor/processor.cpp @@ -23,7 +23,7 @@ #include "kernel/system/interrupts/apic/lapic.hpp" #include "kernel/system/system.hpp" #include "shared/logger/logger.hpp" -#include "shared/memory/gdt_macros.hpp" +#include "kernel/memory/gdt.hpp" #include "shared/panic.hpp" static g_processor* processors = nullptr; @@ -148,6 +148,9 @@ void processorAdd(uint32_t apicId, uint32_t processorHardwareId) uint16_t processorGetNumberOfProcessors() { + if(!G_SMP_ENABLED) + return 1; + if(!processors) panic("%! tried to retrieve number of cores before initializing system on BSP", "kern"); return processorsAvailable; @@ -160,13 +163,10 @@ uint32_t processorGetCurrentId() if(!systemIsReady()) return processorGetCurrentIdFromApic(); - // Kernel thread-local data is in segment 0x38 - // GS:0x0 is relative address within - uint32_t processor; - asm volatile("mov $" STR(G_GDT_DESCRIPTOR_KERNELTHREADLOCAL) ", %%eax\n" - "mov %%eax, %%gs\n" - "mov %%gs:0x0, %0" - : "=r"(processor)::"eax"); + // GS points to valid + // 0x0 is relative address within struct + uint64_t processor; + asm volatile("mov %%gs:0x0, %0" : "=r" (processor)); return processor; } @@ -280,9 +280,9 @@ void processorWriteMsr(uint32_t msr, uint32_t lo, uint32_t hi) : "a"(lo), "d"(hi), "c"(msr)); } -uint32_t processorReadEflags() +uint64_t processorReadEflags() { - uint32_t eflags; + uint64_t eflags; asm volatile("pushf\n" "pop %0" : "=g"(eflags)); diff --git a/kernel/src/kernel/system/processor/processor.hpp b/kernel/src/kernel/system/processor/processor.hpp index c10a6045..d20e1865 100644 --- a/kernel/src/kernel/system/processor/processor.hpp +++ b/kernel/src/kernel/system/processor/processor.hpp @@ -227,7 +227,7 @@ void processorWriteMsr(uint32_t msr, uint32_t lo, uint32_t hi); /** * Reads the EFLAGS register. */ -uint32_t processorReadEflags(); +uint64_t processorReadEflags(); /** * Saves the FPU state to the target diff --git a/kernel/src/kernel/system/processor/processor_state.hpp b/kernel/src/kernel/system/processor/processor_state.hpp index 918fc5c3..95dc5c14 100644 --- a/kernel/src/kernel/system/processor/processor_state.hpp +++ b/kernel/src/kernel/system/processor/processor_state.hpp @@ -29,46 +29,38 @@ struct g_processor_state { // Pushed by the interrupt request/routine handler - uint32_t gs; - uint32_t fs; - uint32_t es; - uint32_t ds; + uint64_t es; + uint64_t ds; - uint32_t eax; - uint32_t ecx; - uint32_t edx; - uint32_t ebx; - uint32_t ebp; - uint32_t esi; - uint32_t edi; + uint64_t r15; + uint64_t r14; + uint64_t r13; + uint64_t r12; + uint64_t r11; + uint64_t r10; + uint64_t r9; + uint64_t r8; + + uint64_t rdi; + uint64_t rsi; + uint64_t rbp; + uint64_t rbx; + uint64_t rdx; + uint64_t rcx; + uint64_t rax; // Pushed by ISR handler if available - uint32_t intr; - uint32_t error; + uint64_t intr; + uint64_t error; // Pushed by the processor - uint32_t eip; - uint32_t cs; - uint32_t eflags; + uint64_t rip; + uint64_t cs; + uint64_t rflags; // Only pushed/popped on Ring 3 <-> Ring 0 switches - uint32_t esp; - uint32_t ss; -}__attribute__((packed)); - -/** - * Image of the stack on interrupt from a VM86 task - */ -struct g_processor_state_vm86 -{ - // The default contents are still pushed - g_processor_state defaultFrame; - - // Additionally pushed by the processor before the other stuff - uint32_t es; - uint32_t ds; - uint32_t fs; - uint32_t gs; + uint64_t rsp; + uint64_t ss; }__attribute__((packed)); #endif diff --git a/kernel/src/kernel/system/processor/virtual_8086_monitor.cpp b/kernel/src/kernel/system/processor/virtual_8086_monitor.cpp index 0ea2b541..5b505725 100644 --- a/kernel/src/kernel/system/processor/virtual_8086_monitor.cpp +++ b/kernel/src/kernel/system/processor/virtual_8086_monitor.cpp @@ -28,237 +28,6 @@ g_virtual_monitor_handling_result vm86MonitorHandleGpf(g_task* task) { - g_processor_state_vm86* ctx = (g_processor_state_vm86*) task->state; - uint8_t* ip = (uint8_t*) G_SEGOFF_TO_LINEAR(ctx->defaultFrame.cs, ctx->defaultFrame.eip); - uint16_t* sp = (uint16_t*) G_SEGOFF_TO_LINEAR(ctx->defaultFrame.ss, ctx->defaultFrame.esp); - uint32_t* esp = (uint32_t*) sp; - - bool operands32 = false; - bool address32 = false; - - while (true) { - - switch (ip[0]) { - /** - * Enables 32bit operands for the next instructions - */ - case 0x66: { - operands32 = true; - ++ip; - ++ctx->defaultFrame.eip; - break; - } - - /** - * Enables 32bit addresses for the next instruction - */ - case 0x67: { - address32 = true; - ++ip; - ++ctx->defaultFrame.eip; - break; - } - - /** - * Instruction 0x9C: - * PUSHF - * - * Pushes the CPU's eflags - */ - case 0x9C: { - - if (operands32) { - ctx->defaultFrame.esp = ((ctx->defaultFrame.esp & 0xffff) - 4) & 0xffff; - esp--; - esp[0] = ctx->defaultFrame.eflags & G_VALID_FLAGS; - - if (task->vm86Data->cpuIf) { - esp[0] |= G_EFLAG_IF; - } else { - esp[0] &= ~G_EFLAG_IF; - } - } else { - ctx->defaultFrame.esp = ((ctx->defaultFrame.esp & 0xffff) - 2) & 0xffff; - sp--; - sp[0] = (uint16_t) ctx->defaultFrame.eflags; - - if (task->vm86Data->cpuIf) { - sp[0] |= G_EFLAG_IF; - } else { - sp[0] &= ~G_EFLAG_IF; - } - } - - ++ctx->defaultFrame.eip; - return VIRTUAL_MONITOR_HANDLING_RESULT_SUCCESSFUL; - } - - /** - * Instruction 0x9D: - * POPF - * - * Pops the CPU's eflags - */ - case 0x9D: { - - if (operands32) { - ctx->defaultFrame.eflags = G_EFLAG_IF | G_EFLAG_VM | (esp[0] & G_VALID_FLAGS); - task->vm86Data->cpuIf = (esp[0] & G_EFLAG_IF) != 0; - ctx->defaultFrame.esp = ((ctx->defaultFrame.esp & 0xffff) + 4) & 0xffff; - } else { - ctx->defaultFrame.eflags = G_EFLAG_IF | G_EFLAG_VM | sp[0]; - task->vm86Data->cpuIf = (sp[0] & G_EFLAG_IF) != 0; - ctx->defaultFrame.esp = ((ctx->defaultFrame.esp & 0xffff) + 2) & 0xffff; - } - - ++ctx->defaultFrame.eip; - return VIRTUAL_MONITOR_HANDLING_RESULT_SUCCESSFUL; - } - - /** - * Instruction 0xCD: - * INT x - * - * Calls an interrupt - */ - case 0xCD: { - sp -= 3; - ctx->defaultFrame.esp = ((ctx->defaultFrame.esp & 0xffff) - 6) & 0xffff; - - sp[0] = (uint16_t) (ctx->defaultFrame.eip + 2); - sp[1] = ctx->defaultFrame.cs; - sp[2] = (uint16_t) ctx->defaultFrame.eflags; - - if (task->vm86Data->cpuIf) { - sp[2] |= G_EFLAG_IF; - } else { - sp[2] &= ~G_EFLAG_IF; - } - - ctx->defaultFrame.cs = G_FP_SEG(ivt->entry[ip[1]]); - ctx->defaultFrame.eip = G_FP_OFF(ivt->entry[ip[1]]); - - ++task->vm86Data->interruptRecursionLevel; - - return VIRTUAL_MONITOR_HANDLING_RESULT_SUCCESSFUL; - } - - /** - * Instruction 0xCF: - * IRET - * - * Returns from an interrupt - */ - case 0xCF: { - ctx->defaultFrame.eip = sp[0]; - ctx->defaultFrame.cs = sp[1]; - ctx->defaultFrame.eflags = G_EFLAG_IF | G_EFLAG_VM | sp[2]; - task->vm86Data->cpuIf = ((sp[2] & G_EFLAG_IF) != 0); - - ctx->defaultFrame.esp = ((ctx->defaultFrame.esp & 0xffff) + 6) & 0xffff; - - if (task->vm86Data->interruptRecursionLevel == 0) { - task->vm86Data->out->ax = ctx->defaultFrame.eax; - task->vm86Data->out->bx = ctx->defaultFrame.ebx; - task->vm86Data->out->cx = ctx->defaultFrame.ecx; - task->vm86Data->out->dx = ctx->defaultFrame.edx; - - task->vm86Data->out->di = ctx->defaultFrame.edi; - task->vm86Data->out->si = ctx->defaultFrame.esi; - task->vm86Data->out->ds = ctx->ds; - task->vm86Data->out->es = ctx->es; - - return VIRTUAL_MONITOR_HANDLING_RESULT_FINISHED; - } - - --task->vm86Data->interruptRecursionLevel; - return VIRTUAL_MONITOR_HANDLING_RESULT_SUCCESSFUL; - } - - /** - * Instruction 0xFA: - * CLI - * - * Disables interrupts - */ - case 0xFA: { - task->vm86Data->cpuIf = false; - ++ctx->defaultFrame.eip; - return VIRTUAL_MONITOR_HANDLING_RESULT_SUCCESSFUL; - } - - /** - * Instruction 0xFB: - * STI - * - * Enables interrupts - */ - case 0xFB: { - task->vm86Data->cpuIf = true; - ++ctx->defaultFrame.eip; - return VIRTUAL_MONITOR_HANDLING_RESULT_SUCCESSFUL; - } - - /* Instruction 0xEE: - * OUT dx, al - * - * Output byte in AL to I/O port address in DX. - */ - case 0xEE: { - ioPortWriteByte((uint16_t) ctx->defaultFrame.edx, (uint8_t) ctx->defaultFrame.eax); - ++ctx->defaultFrame.eip; - return VIRTUAL_MONITOR_HANDLING_RESULT_SUCCESSFUL; - } - - /* Instruction 0xEF: - * OUT dx, ax - * - * Output word in AX to I/O port address in DX. - */ - case 0xEF: { - ioPortWriteShort((uint16_t) ctx->defaultFrame.edx, (uint16_t) ctx->defaultFrame.eax); - ++ctx->defaultFrame.eip; - return VIRTUAL_MONITOR_HANDLING_RESULT_SUCCESSFUL; - } - - /** - * Instruction 0xEC: - * IN al, dx - * - * Input byte from I/O port in DX into AL. - */ - case 0xEC: { - uint8_t res = ioPortReadByte((uint16_t) ctx->defaultFrame.edx); - ctx->defaultFrame.eax &= ~(0xFF); - ctx->defaultFrame.eax |= res; - ++ctx->defaultFrame.eip; - return VIRTUAL_MONITOR_HANDLING_RESULT_SUCCESSFUL; - } - - /** - * Instruction 0xED: - * IN al, dx - * - * Input word from I/O port in DX into AX. - */ - case 0xED: { - uint16_t res = ioPortReadShort((uint16_t) ctx->defaultFrame.edx); - ctx->defaultFrame.eax &= ~(0xFFFF); - ctx->defaultFrame.eax |= res; - ++ctx->defaultFrame.eip; - return VIRTUAL_MONITOR_HANDLING_RESULT_SUCCESSFUL; - } - - /** - * Unhandled operation - */ - default: { - logInfo("%! unhandled opcode %h at linear location %h", "vm86", (uint32_t ) ip[0], ip); - return VIRTUAL_MONITOR_HANDLING_RESULT_UNHANDLED_OPCODE; - } - } - } - - // Not reached + // TODO this is no longer supported return VIRTUAL_MONITOR_HANDLING_RESULT_UNHANDLED_OPCODE; } diff --git a/kernel/src/kernel/system/smp.cpp b/kernel/src/kernel/system/smp.cpp index 90ed4846..791708f9 100644 --- a/kernel/src/kernel/system/smp.cpp +++ b/kernel/src/kernel/system/smp.cpp @@ -24,33 +24,53 @@ #include "kernel/memory/memory.hpp" #include "kernel/filesystem/ramdisk.hpp" #include "kernel/kernel.hpp" - +#include "shared/memory/constants.hpp" #include "shared/logger/logger.hpp" +#include "kernel/memory/paging.hpp" bool smpInitialized = false; void smpInitialize(g_physical_address initialPageDirectoryPhysical) { + // TODO: For all physical allocations below we must make sure that the memory is in 32 bit address range + + // Identity-map lower memory + for(g_address phys = 0; phys < G_SMP_STARTUP_AREA_END; phys += G_PAGE_SIZE) + { + pagingMapPage(phys, phys, G_PAGE_TABLE_KERNEL_DEFAULT, G_PAGE_KERNEL_DEFAULT); + logInfo("Identitiy map %x to %x: %x", phys, phys, pagingVirtualToPhysical(phys)); + } + + // Map it so we can write it here + g_virtual_address mappedLower = addressRangePoolAllocate(memoryVirtualRangePool, + G_PAGE_ALIGN_UP(G_SMP_STARTUP_AREA_END) / G_PAGE_SIZE); + for(g_address phys = 0; phys < G_SMP_STARTUP_AREA_END; phys += G_PAGE_SIZE) + { + pagingMapPage(mappedLower + phys, phys, G_PAGE_TABLE_KERNEL_DEFAULT, G_PAGE_KERNEL_DEFAULT); + } + // Write values to lower memory for use within startup code - *((uint32_t*) G_SMP_STARTUP_AREA_PAGEDIR) = initialPageDirectoryPhysical; - *((uint32_t*) G_SMP_STARTUP_AREA_AP_ENTRY) = (g_virtual_address) kernelRunApplicationCore; - *((uint32_t*) G_SMP_STARTUP_AREA_AP_COUNTER) = 0; + *((g_address*) (mappedLower + G_SMP_STARTUP_AREA_PAGEDIR)) = initialPageDirectoryPhysical; + *((g_address*) (mappedLower + G_SMP_STARTUP_AREA_AP_ENTRY)) = (g_virtual_address) kernelRunApplicationCore; + *((g_size*) (mappedLower + G_SMP_STARTUP_AREA_AP_COUNTER)) = 0; - logDebug("%! initial page directory for APs: %h", "smp", *((uint32_t*) G_SMP_STARTUP_AREA_PAGEDIR)); - logDebug("%! kernel entry point for APs: %h", "smp", *((uint32_t*) G_SMP_STARTUP_AREA_AP_ENTRY)); - logDebug("%! initial AP counter value: %i", "smp", *((uint32_t*) G_SMP_STARTUP_AREA_AP_COUNTER)); + logInfo("%! initial page directory for APs: %h, %x", "smp", + *((g_address*) (mappedLower+G_SMP_STARTUP_AREA_PAGEDIR)), + initialPageDirectoryPhysical); + logInfo("%! kernel entry point for APs: %h", "smp", *((g_address*) (mappedLower+G_SMP_STARTUP_AREA_AP_ENTRY))); + logInfo("%! initial AP counter value: %i", "smp", *((uint32_t*) (mappedLower+G_SMP_STARTUP_AREA_AP_COUNTER))); // Create enough stacks for all APs - g_physical_address* stackArray = (g_physical_address*) G_SMP_STARTUP_AREA_AP_STACK_ARRAY; + auto stackArray = (g_physical_address*) (mappedLower + G_SMP_STARTUP_AREA_AP_STACK_ARRAY); for(uint32_t i = 0; i < processorGetNumberOfProcessors(); i++) { - g_physical_address stackPhysical = memoryPhysicalAllocate(); if(stackPhysical == 0) { logInfo("%*%! could not allocate physical page for AP stack", 0x0C, "smp"); return; } + g_virtual_address stackVirtual = addressRangePoolAllocate(memoryVirtualRangePool, 1); if(stackPhysical == 0) { @@ -63,18 +83,19 @@ void smpInitialize(g_physical_address initialPageDirectoryPhysical) g_virtual_address stackTop = (stackVirtual + G_PAGE_SIZE); stackArray[i] = stackTop; - logDebug("%! created AP stack (%h) placed at %h", "smp", stackArray[i], &stackArray[i]); + logInfo("%! created AP stack (%h -> %h) placed at %h", "smp", stackArray[i], stackPhysical, + ((g_address)&stackArray[i]) - mappedLower); } // Copy start object from ramdisk to lower memory - const char* ap_startup_location = "system/lib/apstartup.o"; - g_ramdisk_entry* startupObject = ramdiskFindAbsolute(ap_startup_location); - if(startupObject == 0) + const char* apStartupPath = "system/lib/apstartup.o"; + g_ramdisk_entry* startupObject = ramdiskFindAbsolute(apStartupPath); + if(startupObject == nullptr) { - logInfo("%*%! could not initialize due to missing apstartup object at '%s'", 0x0C, "smp", ap_startup_location); + logInfo("%*%! could not initialize due to missing apstartup object at '%s'", 0x0C, "smp", apStartupPath); return; } - memoryCopy((uint8_t*) G_SMP_STARTUP_AREA_CODE_START, (uint8_t*) startupObject->data, startupObject->dataSize); + memoryCopy((uint8_t*) (mappedLower + G_SMP_STARTUP_AREA_CODE_START), startupObject->data, startupObject->dataSize); smpInitialized = true; @@ -88,6 +109,8 @@ void smpInitialize(g_physical_address initialPageDirectoryPhysical) } core = core->next; } + + logInfo("%! initial AP counter value: %i", "smp", *((uint32_t*) (mappedLower+G_SMP_STARTUP_AREA_AP_COUNTER))); } void smpInitializeCore(g_processor* cpu) diff --git a/kernel/src/kernel/system/system.cpp b/kernel/src/kernel/system/system.cpp index 995d6733..2ec6494a 100644 --- a/kernel/src/kernel/system/system.cpp +++ b/kernel/src/kernel/system/system.cpp @@ -28,32 +28,34 @@ #include "kernel/system/smp.hpp" #include "shared/panic.hpp" #include "shared/logger/logger.hpp" +#include "shared/memory/paging.hpp" static int applicationCoresWaiting; static bool bspInitialized = false; static bool systemReady = false; -void systemInitializeBsp(g_physical_address initialPdPhys) +void systemInitializeBsp(g_physical_address rsdp) { processorInitializeBsp(); - acpiInitialize(); + acpiInitialize(rsdp); apicDetect(); hpetInitialize(); if(!processorListAvailable()) panic("%! no processors found", "system"); - gdtPrepare(); gdtInitialize(); + gdtInitializeLocal(); interruptsInitializeBsp(); syscallRegisterAll(); + processorFinalizeSetup(); auto numCores = processorGetNumberOfProcessors(); if(numCores > 1) - smpInitialize(initialPdPhys); + smpInitialize(pagingGetCurrentSpace()); applicationCoresWaiting = numCores - 1; bspInitialized = true; @@ -61,7 +63,7 @@ void systemInitializeBsp(g_physical_address initialPdPhys) void systemInitializeAp() { - gdtInitialize(); + gdtInitializeLocal(); interruptsInitializeAp(); processorFinalizeSetup(); } diff --git a/kernel/src/kernel/system/system.hpp b/kernel/src/kernel/system/system.hpp index c49ac149..d6096061 100644 --- a/kernel/src/kernel/system/system.hpp +++ b/kernel/src/kernel/system/system.hpp @@ -26,9 +26,9 @@ /** * Sets up all the basic system components that are required to initialize * higher level parts of the kernel. If multiple cores are available, the - * initial physical page directory address is passed to their bootstrap code. + * initialization of these is started. */ -void systemInitializeBsp(g_physical_address initialPdPhys); +void systemInitializeBsp(g_physical_address rsdp); /** * Sets up the remaining components which need local initialization on each core. diff --git a/kernel/src/kernel/system/timing/hpet.cpp b/kernel/src/kernel/system/timing/hpet.cpp index cc890588..b3bc4cd8 100644 --- a/kernel/src/kernel/system/timing/hpet.cpp +++ b/kernel/src/kernel/system/timing/hpet.cpp @@ -34,16 +34,20 @@ void hpetInitialize() { _hpetFindAndMap(); - // Read correct frequency - uint64_t capabilities = mmio[HPET_GEN_CAP_REG / 8]; - uint32_t clockPeriod = (capabilities >> 32) & 0xFFFFFFFF; - frequency = (1000000000000000.0 / clockPeriod); - periodsPerSecond = 1.0 / frequency; + // TODO this crashes in QEMU + if(mmio && false) + { + // Read correct frequency + uint64_t capabilities = mmio[HPET_GEN_CAP_REG / 8]; + uint32_t clockPeriod = (capabilities >> 32) & 0xFFFFFFFF; + frequency = (1000000000000000.0 / clockPeriod); // TODO now on x86_64 do it properly + periodsPerSecond = 1.0 / frequency; - // Make sure it is enabled - mmio[HPET_GEN_CONFIG_REG / 8] |= 1; + // Make sure it is enabled + mmio[HPET_GEN_CONFIG_REG / 8] |= 1; - available = true; + available = true; + } } void _hpetFindAndMap() @@ -63,8 +67,11 @@ void _hpetFindAndMap() } auto virtBase = addressRangePoolAllocate(memoryVirtualRangePool, 1); - pagingMapPage(virtBase, hpet->baseAddress.address, G_PAGE_TABLE_KERNEL_DEFAULT, G_PAGE_TABLE_KERNEL_DEFAULT, - G_PAGE_KERNEL_UNCACHED); + if(!pagingMapPage(virtBase, hpet->baseAddress.address, G_PAGE_TABLE_KERNEL_DEFAULT, G_PAGE_KERNEL_UNCACHED)) + { + logInfo("%! failed to map", "hpet"); + return; + } mmio = (volatile uint64_t*) virtBase; } diff --git a/kernel/src/kernel/tasking/elf/elf_loader.cpp b/kernel/src/kernel/tasking/elf/elf_loader.cpp index 1aea28ca..38141b0b 100644 --- a/kernel/src/kernel/tasking/elf/elf_loader.cpp +++ b/kernel/src/kernel/tasking/elf/elf_loader.cpp @@ -80,7 +80,7 @@ g_virtual_address elfUserProcessCreateInfo(g_process* process, g_elf_object* roo uint32_t totalRequired = sizeof(g_process_info) + sizeof(g_object_info) * objectCount + stringTableSize; // Map required memory all loaded objects - uint32_t areaStart = imageEnd; + g_address areaStart = imageEnd; uint32_t pages = G_PAGE_ALIGN_UP(totalRequired) / G_PAGE_SIZE; for(uint32_t i = 0; i < pages; i++) { @@ -127,55 +127,45 @@ g_virtual_address elfUserProcessCreateInfo(g_process* process, g_elf_object* roo return imageEnd + G_PAGE_ALIGN_UP(totalRequired); } -g_spawn_validation_details elfReadAndValidateHeader(g_fd file, Elf32_Ehdr* headerBuffer, bool root) +g_spawn_validation_details elfReadAndValidateHeader(g_fd file, Elf64_Ehdr* headerBuffer, bool root) { - if(!filesystemReadToMemory(file, 0, (uint8_t*) headerBuffer, sizeof(Elf32_Ehdr))) + if(!filesystemReadToMemory(file, 0, (uint8_t*) headerBuffer, sizeof(Elf64_Ehdr))) { logInfo("%! failed to spawn file %i due to io error", "elf", file); - return G_SPAWN_VALIDATION_ELF32_IO_ERROR; + return G_SPAWN_VALIDATION_ELF_IO_ERROR; } return elfValidateHeader(headerBuffer, root); } -g_spawn_validation_details elfValidateHeader(Elf32_Ehdr* header, bool root) +g_spawn_validation_details elfValidateHeader(Elf64_Ehdr* header, bool root) { if((header->e_ident[EI_MAG0] != ELFMAG0) || // 0x7F (header->e_ident[EI_MAG1] != ELFMAG1) || // E (header->e_ident[EI_MAG2] != ELFMAG2) || // L (header->e_ident[EI_MAG3] != ELFMAG3)) // F { - return G_SPAWN_VALIDATION_ELF32_NOT_ELF; + return G_SPAWN_VALIDATION_ELF_NOT_ELF; } // Check executable flag if(root && header->e_type != ET_EXEC) - { - return G_SPAWN_VALIDATION_ELF32_NOT_EXECUTABLE; - } + return G_SPAWN_VALIDATION_ELF_NOT_EXECUTABLE; // Must be i386 architecture compatible - if(header->e_machine != EM_386) - { - return G_SPAWN_VALIDATION_ELF32_NOT_I386; - } + if(header->e_machine != EM_X86_64) + return G_SPAWN_VALIDATION_ELF_NOT_I386; - // Must be 32 bit - if(header->e_ident[EI_CLASS] != ELFCLASS32) - { - return G_SPAWN_VALIDATION_ELF32_NOT_32BIT; - } + // Must be 64 bit + if(header->e_ident[EI_CLASS] != ELFCLASS64) + return G_SPAWN_VALIDATION_ELF_NOT_64BIT; // Must be little endian if(header->e_ident[EI_DATA] != ELFDATA2LSB) - { - return G_SPAWN_VALIDATION_ELF32_NOT_LITTLE_ENDIAN; - } + return G_SPAWN_VALIDATION_ELF_NOT_LITTLE_ENDIAN; // Must comply to current ELF standard if(header->e_version != EV_CURRENT) - { - return G_SPAWN_VALIDATION_ELF32_NOT_STANDARD_ELF; - } + return G_SPAWN_VALIDATION_ELF_NOT_STANDARD_ELF; return G_SPAWN_VALIDATION_SUCCESSFUL; } diff --git a/kernel/src/kernel/tasking/elf/elf_loader.hpp b/kernel/src/kernel/tasking/elf/elf_loader.hpp index 2ea5b398..ab15a8a3 100644 --- a/kernel/src/kernel/tasking/elf/elf_loader.hpp +++ b/kernel/src/kernel/tasking/elf/elf_loader.hpp @@ -46,11 +46,11 @@ g_virtual_address elfUserProcessCreateInfo(g_process* process, g_elf_object* exe /** * Reads and validates an ELF header from a file. */ -g_spawn_validation_details elfReadAndValidateHeader(g_fd file, Elf32_Ehdr* headerBuffer, bool executable); +g_spawn_validation_details elfReadAndValidateHeader(g_fd file, Elf64_Ehdr* headerBuffer, bool executable); /** * Validates the given ELF header. */ -g_spawn_validation_details elfValidateHeader(Elf32_Ehdr* header, bool executable); +g_spawn_validation_details elfValidateHeader(Elf64_Ehdr* header, bool executable); #endif diff --git a/kernel/src/kernel/tasking/elf/elf_object.cpp b/kernel/src/kernel/tasking/elf/elf_object.cpp index 6a0475f4..a91600c3 100644 --- a/kernel/src/kernel/tasking/elf/elf_object.cpp +++ b/kernel/src/kernel/tasking/elf/elf_object.cpp @@ -24,14 +24,15 @@ #include "kernel/tasking/elf/elf_tls.hpp" #include "shared/utils/string.hpp" #include "shared/logger/logger.hpp" +#include "kernel/utils/debug.hpp" g_elf_object_load_result elfObjectLoad(g_elf_object* parentObject, const char* name, g_fd file, g_virtual_address base) { - g_elf_object_load_result res; - res.status = G_SPAWN_STATUS_SUCCESSFUL; + g_elf_object_load_result result{}; + result.status = G_SPAWN_STATUS_SUCCESSFUL; // Create ELF object - g_elf_object* object = (g_elf_object*) heapAllocateClear(sizeof(g_elf_object)); + auto object = (g_elf_object*) heapAllocateClear(sizeof(g_elf_object)); object->name = stringDuplicate(name); object->parent = parentObject; object->baseAddress = base; @@ -44,17 +45,17 @@ g_elf_object_load_result elfObjectLoad(g_elf_object* parentObject, const char* n object->nextObjectId = 0; object->symbolLookupOrderList = 0; } - res.object = object; + result.object = object; logDebug("%! loading object '%s' (%i) to %h (fd %i)", "elf", name, object->id, base, file); // Check ELF header - res.validation = elfReadAndValidateHeader(file, &object->header, object->root); - if(res.validation != G_SPAWN_VALIDATION_SUCCESSFUL) + result.validation = elfReadAndValidateHeader(file, &object->header, object->root); + if(result.validation != G_SPAWN_VALIDATION_SUCCESSFUL) { - logInfo("%! validation failed with status %i when loading object %s", "elf", res.validation, name); - res.status = object->root ? G_SPAWN_STATUS_FORMAT_ERROR : G_SPAWN_STATUS_DEPENDENCY_ERROR; - return res; + logInfo("%! validation failed with status %i when loading object %s", "elf", result.validation, name); + result.status = object->root ? G_SPAWN_STATUS_FORMAT_ERROR : G_SPAWN_STATUS_DEPENDENCY_ERROR; + return result; } // Add to list of already loaded dependencies @@ -70,15 +71,15 @@ g_elf_object_load_result elfObjectLoad(g_elf_object* parentObject, const char* n rootObject->symbolLookupOrderList = object; // Load each program header - for(uint32_t p = 0; p < object->header.e_phnum; p++) + for(Elf64_Half p = 0; p < object->header.e_phnum; p++) { - Elf32_Phdr phdr; - uint32_t phdrOffset = object->header.e_phoff + object->header.e_phentsize * p; + Elf64_Phdr phdr; + g_address phdrOffset = object->header.e_phoff + object->header.e_phentsize * p; - if(!filesystemReadToMemory(file, phdrOffset, (uint8_t*) &phdr, sizeof(Elf32_Phdr))) + if(!filesystemReadToMemory(file, phdrOffset, (uint8_t*) &phdr, sizeof(Elf64_Phdr))) { logInfo("%! failed to read segment header from file %i", "elf", file); - res.status = G_SPAWN_STATUS_IO_ERROR; + result.status = G_SPAWN_STATUS_IO_ERROR; break; } @@ -93,14 +94,15 @@ g_elf_object_load_result elfObjectLoad(g_elf_object* parentObject, const char* n auto loadResult = elfObjectLoadLoadSegment(file, phdr, base); if(loadResult != G_SPAWN_STATUS_SUCCESSFUL) { - res.status = loadResult; + result.status = loadResult; logInfo("%! unable to load PT_LOAD segment from file", "elf"); break; } } else { - memoryOnDemandMapFile(taskingGetCurrentTask()->process, file, phdr.p_offset, fileStart, phdr.p_filesz, phdr.p_memsz); + memoryOnDemandMapFile(taskingGetCurrentTask()->process, file, phdr.p_offset, fileStart, phdr.p_filesz, + phdr.p_memsz); } if(object->startAddress == 0 || alignedStart < object->startAddress) @@ -111,8 +113,8 @@ g_elf_object_load_result elfObjectLoad(g_elf_object* parentObject, const char* n } else if(phdr.p_type == PT_TLS) { - res.status = elfTlsLoadData(file, phdr, object); - if(res.status != G_SPAWN_STATUS_SUCCESSFUL) + result.status = elfTlsLoadData(file, phdr, object); + if(result.status != G_SPAWN_STATUS_SUCCESSFUL) { logInfo("%! unable to load PT_TLS segment from file", "elf"); break; @@ -120,34 +122,34 @@ g_elf_object_load_result elfObjectLoad(g_elf_object* parentObject, const char* n } else if(phdr.p_type == PT_DYNAMIC) { - object->dynamicSection = (Elf32_Dyn*) (base + phdr.p_vaddr); + object->dynamicSection = (Elf64_Dyn*) (base + phdr.p_vaddr); logDebug("%! object has dynamic information %h", "elf", object->dynamicSection); } } // Do analyzation and linking - if(res.status == G_SPAWN_STATUS_SUCCESSFUL) + if(result.status == G_SPAWN_STATUS_SUCCESSFUL) { elfObjectInspect(object); auto depRes = elfObjectLoadDependencies(object); if(depRes.status == G_SPAWN_STATUS_SUCCESSFUL) { - res.nextFreeBase = depRes.nextFreeBase; + result.nextFreeBase = depRes.nextFreeBase; } else { - res.status = depRes.status; - return res; + result.status = depRes.status; + return result; } elfObjectApplyRelocations(file, object); } - return res; + return result; } -g_spawn_status elfObjectLoadLoadSegment(g_fd file, Elf32_Phdr phdr, g_virtual_address base) +g_spawn_status elfObjectLoadLoadSegment(g_fd file, Elf64_Phdr phdr, g_virtual_address base) { g_address fileStart = base + phdr.p_vaddr; g_offset fileSize = phdr.p_filesz; @@ -189,64 +191,64 @@ void elfObjectInspect(g_elf_object* object) return; // Find tables that we need - Elf32_Dyn* it = object->dynamicSection; + Elf64_Dyn* it = object->dynamicSection; while(it->d_tag) { switch(it->d_tag) { - case DT_STRTAB: - object->dynamicStringTable = (char*) (object->baseAddress + it->d_un.d_ptr); - break; - case DT_STRSZ: - object->dynamicStringTableSize = it->d_un.d_val; - break; - case DT_HASH: - object->dynamicSymbolHashTable = (Elf32_Word*) (object->baseAddress + it->d_un.d_ptr); + case DT_STRTAB: + object->dynamicStringTable = (char*) (object->baseAddress + it->d_un.d_ptr); + break; + case DT_STRSZ: + object->dynamicStringTableSize = it->d_un.d_val; + break; + case DT_HASH: + object->dynamicSymbolHashTable = (Elf64_Word*) (object->baseAddress + it->d_un.d_ptr); // The number of symbol table entries should equal nchain; so symbol table indexes also select chain table entries. - object->dynamicSymbolTableSize = object->dynamicSymbolHashTable[1]; - break; - case DT_SYMTAB: - object->dynamicSymbolTable = (Elf32_Sym*) (object->baseAddress + it->d_un.d_ptr); - break; - case DT_INIT: - object->init = (void (*)())(object->baseAddress + it->d_un.d_ptr); - break; - case DT_FINI: - object->fini = (void (*)())(object->baseAddress + it->d_un.d_ptr); - break; - case DT_PREINIT_ARRAY: - object->preinitArray = (void (**)())(object->baseAddress + it->d_un.d_ptr); - break; - case DT_PREINIT_ARRAYSZ: - object->preinitArraySize = it->d_un.d_val / sizeof(uintptr_t); - break; - case DT_INIT_ARRAY: - object->initArray = (void (**)())(object->baseAddress + it->d_un.d_ptr); - break; - case DT_INIT_ARRAYSZ: - object->initArraySize = it->d_un.d_val / sizeof(uintptr_t); - break; - case DT_FINI_ARRAY: - object->finiArray = (void (**)())(object->baseAddress + it->d_un.d_ptr); - break; - case DT_FINI_ARRAYSZ: - object->finiArraySize = it->d_un.d_val / sizeof(uintptr_t); - break; + object->dynamicSymbolTableSize = object->dynamicSymbolHashTable[1]; + break; + case DT_SYMTAB: + object->dynamicSymbolTable = (Elf64_Sym*) (object->baseAddress + it->d_un.d_ptr); + break; + case DT_INIT: + object->init = (void (*)()) (object->baseAddress + it->d_un.d_ptr); + break; + case DT_FINI: + object->fini = (void (*)()) (object->baseAddress + it->d_un.d_ptr); + break; + case DT_PREINIT_ARRAY: + object->preinitArray = (void (**)()) (object->baseAddress + it->d_un.d_ptr); + break; + case DT_PREINIT_ARRAYSZ: + object->preinitArraySize = it->d_un.d_val / sizeof(uintptr_t); + break; + case DT_INIT_ARRAY: + object->initArray = (void (**)()) (object->baseAddress + it->d_un.d_ptr); + break; + case DT_INIT_ARRAYSZ: + object->initArraySize = it->d_un.d_val / sizeof(uintptr_t); + break; + case DT_FINI_ARRAY: + object->finiArray = (void (**)()) (object->baseAddress + it->d_un.d_ptr); + break; + case DT_FINI_ARRAYSZ: + object->finiArraySize = it->d_un.d_val / sizeof(uintptr_t); + break; } it++; } // Read dependencies - object->dependencies = 0; + object->dependencies = nullptr; it = object->dynamicSection; while(it->d_tag) { if(it->d_tag == DT_NEEDED) { - g_elf_dependency* dep = (g_elf_dependency*) heapAllocate(sizeof(g_elf_dependency)); - dep->name = stringDuplicate(object->dynamicStringTable + it->d_un.d_val); - dep->next = object->dependencies; - object->dependencies = dep; + auto dependency = (g_elf_dependency*) heapAllocate(sizeof(g_elf_dependency)); + dependency->name = stringDuplicate(object->dynamicStringTable + it->d_un.d_val); + dependency->next = object->dependencies; + object->dependencies = dependency; } it++; } @@ -259,23 +261,25 @@ void elfObjectInspect(g_elf_object* object) rootObject = rootObject->parent; uint32_t pos = 0; - Elf32_Sym* it = object->dynamicSymbolTable; + Elf64_Sym* symbol = object->dynamicSymbolTable; while(pos < object->dynamicSymbolTableSize) { - const char* symbol = (const char*) (object->dynamicStringTable + it->st_name); - if(it->st_shndx) + const char* symbolName = object->dynamicStringTable + symbol->st_name; + + if(symbol->st_shndx) { - g_elf_symbol_info symbolInfo; + g_elf_symbol_info symbolInfo{}; symbolInfo.object = object; - symbolInfo.absolute = object->baseAddress + it->st_value; - symbolInfo.value = it->st_value; - hashmapPut(object->localSymbols, symbol, symbolInfo); + symbolInfo.absolute = object->baseAddress + symbol->st_value; + symbolInfo.value = symbol->st_value; - if(hashmapGetEntry(rootObject->globalSymbols, symbol) == 0) - hashmapPut(rootObject->globalSymbols, symbol, symbolInfo); + hashmapPut(object->localSymbols, symbolName, symbolInfo); + + if(hashmapGetEntry(rootObject->globalSymbols, symbolName) == nullptr) + hashmapPut(rootObject->globalSymbols, symbolName, symbolInfo); } - it++; + symbol++; pos++; } } @@ -283,29 +287,30 @@ void elfObjectInspect(g_elf_object* object) g_elf_object_load_result elfObjectLoadDependencies(g_elf_object* object) { - g_elf_object_load_result res; - res.status = G_SPAWN_STATUS_SUCCESSFUL; - res.nextFreeBase = object->endAddress; + g_elf_object_load_result result{}; + result.status = G_SPAWN_STATUS_SUCCESSFUL; + result.nextFreeBase = object->endAddress; for(g_elf_dependency* dependency = object->dependencies; - dependency; - dependency = dependency->next) + dependency; + dependency = dependency->next) { if(elfObjectIsDependencyLoaded(object, dependency->name)) continue; - auto depRes = elfObjectLoadDependency(object, dependency->name, res.nextFreeBase); - res.nextFreeBase = depRes.nextFreeBase; + auto dependencyResult = elfObjectLoadDependency(object, dependency->name, result.nextFreeBase); + result.nextFreeBase = dependencyResult.nextFreeBase; - if(depRes.status != G_SPAWN_STATUS_SUCCESSFUL) + if(dependencyResult.status != G_SPAWN_STATUS_SUCCESSFUL) { - res.status = depRes.status; - logInfo("%! -> failed to load dependency %s with status %i", "elf", dependency->name, depRes.status); + result.status = dependencyResult.status; + logInfo("%! -> failed to load dependency %s with status %i", "elf", dependency->name, + dependencyResult.status); break; } } - return res; + return result; } void elfObjectApplyRelocations(g_fd file, g_elf_object* object) @@ -316,44 +321,43 @@ void elfObjectApplyRelocations(g_fd file, g_elf_object* object) for(uint32_t p = 0; p < object->header.e_shnum * object->header.e_shentsize; p += object->header.e_shentsize) { - Elf32_Shdr shdr; + Elf64_Shdr shdr; if(!filesystemReadToMemory(file, object->header.e_shoff + p, (uint8_t*) &shdr, object->header.e_shentsize)) { logInfo("%! failed to read section header from file", "elf"); break; } - if(shdr.sh_type != SHT_REL) - { + if(shdr.sh_type != SHT_RELA) continue; - } - Elf32_Rel* entry = (Elf32_Rel*) (object->baseAddress + shdr.sh_addr); - while(entry < (Elf32_Rel*) (object->baseAddress + shdr.sh_addr + shdr.sh_size)) + auto entry = (Elf64_Rela*) (object->baseAddress + shdr.sh_addr); + while(entry < (Elf64_Rela*) (object->baseAddress + shdr.sh_addr + shdr.sh_size)) { - uint32_t symbolIndex = ELF32_R_SYM(entry->r_info); - uint8_t type = ELF32_R_TYPE(entry->r_info); + uint32_t symbolIndex = ELF64_R_SYM(entry->r_info); + uint8_t type = ELF64_R_TYPE(entry->r_info); g_address cS; g_address cP = object->baseAddress + entry->r_offset; - Elf32_Word symbolSize; - const char* symbolName = 0; - g_elf_symbol_info symbolInfo; + Elf64_Word symbolSize; + const char* symbolName = nullptr; + g_elf_symbol_info symbolInfo{}; // Symbol lookup - if(type == R_386_32 || type == R_386_PC32 || - type == R_386_GLOB_DAT || type == R_386_JMP_SLOT || - type == R_386_GOTOFF || type == R_386_TLS_TPOFF || - type == R_386_TLS_DTPMOD32 || type == R_386_TLS_DTPOFF32 || - type == R_386_COPY) + if(type == R_X86_64_32 || type == R_X86_64_64 || type == R_X86_64_PC32 || + type == R_X86_64_GLOB_DAT || type == R_X86_64_JUMP_SLOT || + type == R_X86_64_GOT32 || type == R_X86_64_TPOFF64 || + type == R_X86_64_DTPMOD64 || type == R_X86_64_DTPOFF32 || type == R_X86_64_DTPOFF64 || type == + R_X86_64_RELATIVE || + type == R_X86_64_COPY || type == R_X86_64_TPOFF32) { - Elf32_Sym* symbol = &object->dynamicSymbolTable[symbolIndex]; + Elf64_Sym* symbol = &object->dynamicSymbolTable[symbolIndex]; symbolName = &object->dynamicStringTable[symbol->st_name]; symbolSize = symbol->st_size; bool symbolFound = false; - if(type == R_386_COPY) + if(type == R_X86_64_COPY) { auto symbolLookupEntry = rootObject->symbolLookupOrderList; while(symbolLookupEntry) @@ -384,67 +388,76 @@ void elfObjectApplyRelocations(g_fd file, g_elf_object* object) } else { - if(ELF32_ST_BIND(symbol->st_info) != STB_WEAK) - logDebug("%! missing symbol '%s' (%h, bind: %i)", "elf", symbolName, cP, ELF32_ST_BIND(symbol->st_info)); + if(ELF64_ST_BIND(symbol->st_info) != STB_WEAK) + logDebug("%! missing symbol '%s' (%h, bind: %i)", "elf", symbolName, cP, + ELF64_ST_BIND(symbol->st_info)); cS = 0; } } - if(type == R_386_32) + if(type == R_X86_64_32) { int32_t cA = *((int32_t*) cP); - *((uint32_t*) cP) = cS + cA; + *((uint32_t*) cP) = (uint32_t) (cS + cA); } - else if(type == R_386_PC32) + else if(type == R_X86_64_PC32) { int32_t cA = *((int32_t*) cP); - *((uint32_t*) cP) = cS + cA - cP; + *((uint32_t*) cP) = (uint32_t) ((uint64_t) cS + cA - (uint64_t) cP); } - else if(type == R_386_COPY) + else if(type == R_X86_64_COPY) { if(cS) memoryCopy((void*) cP, (void*) cS, symbolSize); } - else if(type == R_386_GLOB_DAT) + else if(type == R_X86_64_GLOB_DAT || type == R_X86_64_JUMP_SLOT) { - *((uint32_t*) cP) = cS; + *((uint64_t*) cP) = cS; } - else if(type == R_386_JMP_SLOT) + else if(type == R_X86_64_RELATIVE) { - *((uint32_t*) cP) = cS; + uint64_t cB = object->baseAddress; + int64_t cA = *((int64_t*) cP); + *((uint64_t*) cP) = cB + cA; } - else if(type == R_386_RELATIVE) + else if(type == R_X86_64_64) { - uint32_t cB = object->baseAddress; - int32_t cA = *((int32_t*) cP); - *((uint32_t*) cP) = cB + cA; + int64_t cA = *((int64_t*) cP); + *((uint64_t*) cP) = cS + cA; + } + else if(type == R_X86_64_TPOFF64) + { + if(cS) + *((uint64_t*) cP) = symbolInfo.object->tlsPart.offset - rootObject->tlsMaster.userThreadOffset + + symbolInfo.value; } - else if(type == R_386_TLS_TPOFF) + else if(type == R_X86_64_TPOFF32) { - /** - * For TLS_TPOFF we insert the offset relative to the g_user_threadlocal which is put - * into the segment referenced in GS. - */ if(cS) - *((uint32_t*) cP) = symbolInfo.object->tlsPart.offset - rootObject->tlsMaster.userThreadOffset + symbolInfo.value; + *((uint32_t*) cP) = (uint32_t) ( + symbolInfo.object->tlsPart.offset - rootObject->tlsMaster.userThreadOffset + + symbolInfo.value); } - else if(type == R_386_TLS_DTPMOD32) + else if(type == R_X86_64_DTPMOD64) { - /** - * DTPMOD32 expects the module ID to be written which will be passed to ___tls_get_addr. - */ if(cS) - *((uint32_t*) cP) = symbolInfo.object->id; + *((uint64_t*) cP) = symbolInfo.object->id; } - else if(type == R_386_TLS_DTPOFF32) + else if(type == R_X86_64_DTPOFF64) { - /** - * DTPOFF32 expects the symbol offset to be written which will be passed to ___tls_get_addr. - */ if(cS) - *((uint32_t*) cP) = symbolInfo.object->tlsPart.offset - rootObject->tlsMaster.userThreadOffset + symbolInfo.value; + *((uint64_t*) cP) = symbolInfo.object->tlsPart.offset - rootObject->tlsMaster.userThreadOffset + + symbolInfo.value; } + else if(type == R_X86_64_DTPOFF32) + { + if(cS) + *((uint32_t*) cP) = (uint32_t) ( + symbolInfo.object->tlsPart.offset - rootObject->tlsMaster.userThreadOffset + + symbolInfo.value); + } + entry++; } @@ -489,7 +502,7 @@ g_elf_object_load_result elfObjectLoadDependency(g_elf_object* parentObject, con { g_fd fd = elfObjectOpenDependency(name); if(fd == G_FD_NONE) - return {status : G_SPAWN_STATUS_IO_ERROR}; + return {status: G_SPAWN_STATUS_IO_ERROR}; return elfObjectLoad(parentObject, name, fd, base); } @@ -509,7 +522,8 @@ g_fd elfObjectOpenDependency(const char* name) } g_fd fd; - g_fs_open_status openStatus = filesystemOpenNodeFd(findRes.node, G_FILE_FLAG_MODE_BINARY | G_FILE_FLAG_MODE_READ, taskingGetCurrentTask()->process->id, &fd); + g_fs_open_status openStatus = filesystemOpenNodeFd(findRes.node, G_FILE_FLAG_MODE_BINARY | G_FILE_FLAG_MODE_READ, + taskingGetCurrentTask()->process->id, &fd); if(openStatus != G_FS_OPEN_SUCCESSFUL) { logInfo("%! unable to open dependency %s", "elf", absolutePath); diff --git a/kernel/src/kernel/tasking/elf/elf_object.hpp b/kernel/src/kernel/tasking/elf/elf_object.hpp index 0ced29ca..e4d26071 100644 --- a/kernel/src/kernel/tasking/elf/elf_object.hpp +++ b/kernel/src/kernel/tasking/elf/elf_object.hpp @@ -44,7 +44,7 @@ struct g_elf_symbol_info }; /** - * Structure of an ELF32 object in memory. + * Structure of an ELF64 object in memory. */ struct g_elf_object { @@ -54,7 +54,7 @@ struct g_elf_object bool root; char* name; - Elf32_Ehdr header; + Elf64_Ehdr header; g_elf_dependency* dependencies; g_virtual_address startAddress; @@ -96,12 +96,12 @@ struct g_elf_object g_elf_object* symbolLookupOrderListNext; // In-address-space memory pointers - Elf32_Dyn* dynamicSection; + Elf64_Dyn* dynamicSection; const char* dynamicStringTable; - Elf32_Word dynamicStringTableSize; - Elf32_Sym* dynamicSymbolTable; - Elf32_Word dynamicSymbolTableSize; - Elf32_Word* dynamicSymbolHashTable; + Elf64_Word dynamicStringTableSize; + Elf64_Sym* dynamicSymbolTable; + Elf64_Word dynamicSymbolTableSize; + Elf64_Word* dynamicSymbolHashTable; // Initialization and destruction information void (*init)(); @@ -130,7 +130,7 @@ g_elf_object_load_result elfObjectLoad(g_elf_object* parentObject, const char* n /** * Loads a PT_LOAD segment using the header information, relative to the base address. */ -g_spawn_status elfObjectLoadLoadSegment(g_fd file, Elf32_Phdr phdr, g_virtual_address base); +g_spawn_status elfObjectLoadLoadSegment(g_fd file, Elf64_Phdr phdr, g_virtual_address base); /** * Applies relocations on the given object. diff --git a/kernel/src/kernel/tasking/elf/elf_tls.cpp b/kernel/src/kernel/tasking/elf/elf_tls.cpp index 949888e2..305132fb 100644 --- a/kernel/src/kernel/tasking/elf/elf_tls.cpp +++ b/kernel/src/kernel/tasking/elf/elf_tls.cpp @@ -23,13 +23,13 @@ #include "kernel/tasking/elf/elf_loader.hpp" #include "shared/logger/logger.hpp" -g_spawn_status elfTlsLoadData(g_fd file, Elf32_Phdr phdr, g_elf_object* object) +g_spawn_status elfTlsLoadData(g_fd file, Elf64_Phdr phdr, g_elf_object* object) { uint32_t bytesToCopy = phdr.p_filesz; // Read TLS content to a buffer - uint8_t* tlsContentBuffer = (uint8_t*) heapAllocate(bytesToCopy); - if(!filesystemReadToMemory(file, phdr.p_offset, (uint8_t*) tlsContentBuffer, bytesToCopy)) + auto tlsContentBuffer = (uint8_t*) heapAllocate(bytesToCopy); + if(!filesystemReadToMemory(file, phdr.p_offset, tlsContentBuffer, bytesToCopy)) { logInfo("%! unable to read TLS segment from file", "elf"); heapFree(tlsContentBuffer); @@ -85,7 +85,8 @@ void elfTlsCreateMasterImage(g_fd file, g_process* process, g_elf_object* rootOb { g_elf_object* object = hashmapIteratorNext(&it)->value; if(object->tlsPart.content) - memoryCopy((uint8_t*) (tlsStart + object->tlsPart.offset), object->tlsPart.content, object->tlsPart.copysize); + memoryCopy((uint8_t*) (tlsStart + object->tlsPart.offset), object->tlsPart.content, + object->tlsPart.copysize); } hashmapIteratorEnd(&it); @@ -93,5 +94,5 @@ void elfTlsCreateMasterImage(g_fd file, g_process* process, g_elf_object* rootOb process->tlsMaster.location = tlsStart; process->tlsMaster.size = size; process->tlsMaster.userThreadOffset = rootObject->tlsMaster.userThreadOffset; - logDebug("%! created TLS master: %h, size: %h", "elf", process->tlsMaster.location, process->tlsMaster.size); + logDebug("%! created TLS master: %h, size: %h, uTO: %x", "elf", process->tlsMaster.location, process->tlsMaster.size, process->tlsMaster.userThreadOffset); } diff --git a/kernel/src/kernel/tasking/elf/elf_tls.hpp b/kernel/src/kernel/tasking/elf/elf_tls.hpp index 3a71f829..51b397d0 100644 --- a/kernel/src/kernel/tasking/elf/elf_tls.hpp +++ b/kernel/src/kernel/tasking/elf/elf_tls.hpp @@ -28,7 +28,7 @@ * Loads the TLS master for this object into a buffer. Then, the offset where this TLS data * will be loaded into the TLS master image is calculated and put into the object. */ -g_spawn_status elfTlsLoadData(g_fd file, Elf32_Phdr header, g_elf_object* object); +g_spawn_status elfTlsLoadData(g_fd file, Elf64_Phdr header, g_elf_object* object); /** * Creates the TLS master image. The positions for each part of this image where already specified diff --git a/kernel/src/kernel/tasking/task.hpp b/kernel/src/kernel/tasking/task.hpp index a4268f6f..cfd6f036 100644 --- a/kernel/src/kernel/tasking/task.hpp +++ b/kernel/src/kernel/tasking/task.hpp @@ -229,7 +229,7 @@ struct g_process g_task* main; g_task_entry* tasks; - g_physical_address pageDirectory; + g_physical_address pageSpace; g_address_range_pool* virtualRangePool; struct diff --git a/kernel/src/kernel/tasking/tasking.cpp b/kernel/src/kernel/tasking/tasking.cpp index bc5ae95a..bcb659a1 100644 --- a/kernel/src/kernel/tasking/tasking.cpp +++ b/kernel/src/kernel/tasking/tasking.cpp @@ -19,6 +19,7 @@ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #include "kernel/tasking/tasking.hpp" +#include "shared/memory/constants.hpp" #include "kernel/tasking/clock.hpp" #include "kernel/filesystem/filesystem_process.hpp" #include "kernel/ipc/message_queues.hpp" @@ -306,14 +307,14 @@ void taskingRestoreState(g_task* task) } else { - pagingSwitchToSpace(task->process->pageDirectory); + pagingSwitchToSpace(task->process->pageSpace); } - // For TLS: write thread-local addresses to GDT + // For TLS: write thread-local addresses gdtSetTlsAddresses(task->threadLocal.userThreadLocal, task->threadLocal.kernelThreadLocal); - // Set TSS ESP0 for ring 3 tasks to return onto - gdtSetTssEsp0(task->interruptStack.end); + // Set TSS RSP0 for ring 3 tasks to return onto + gdtSetTssRsp0(task->interruptStack.end); // Restore FPU state if(task->fpu.stored) @@ -339,12 +340,18 @@ g_process* taskingCreateProcess(g_security_level securityLevel) mutexInitializeGlobal(&process->lock, __func__); - process->pageDirectory = taskingMemoryCreatePageDirectory(securityLevel); + process->pageSpace = taskingMemoryCreatePageSpace(); + if(!process->pageSpace) + { + logInfo("%! failed to create new address space to create process", "tasking"); + return nullptr; + } process->virtualRangePool = (g_address_range_pool*) heapAllocate(sizeof(g_address_range_pool)); addressRangePoolInitialize(process->virtualRangePool); addressRangePoolAddRange(process->virtualRangePool, G_USER_VIRTUAL_RANGES_START, G_USER_VIRTUAL_RANGES_END); + logDebug("%! new process %i, address space %x", "tasking", process->id, process->pageSpace); return process; } @@ -355,7 +362,7 @@ void taskingDestroyProcess(g_process* process) filesystemProcessRemove(process->id); - taskingMemoryDestroyPageDirectory(process->pageDirectory); + taskingMemoryDestroyPageSpace(process->pageSpace); addressRangePoolDestroy(process->virtualRangePool); heapFree(process->virtualRangePool); @@ -375,12 +382,16 @@ g_task* taskingCreateTask(g_virtual_address eip, g_process* process, g_security_ _taskingInitializeTask(task, process, level); task->type = G_TASK_TYPE_DEFAULT; - g_physical_address returnDirectory = taskingMemoryTemporarySwitchTo(task->process->pageDirectory); + g_physical_address returnSpace = taskingMemoryTemporarySwitchTo(task->process->pageSpace); taskingMemoryInitialize(task); taskingStateReset(task, eip, level); - taskingMemoryTemporarySwitchBack(returnDirectory); + logDebug("%! created task %i, intr stack: %x-%x, stack: %x-%x", "tasking", task->id, task->interruptStack.start, + task->interruptStack.end, task->stack.start, task->stack.end); + logDebug("%# state: RIP: %x, RSP: %x, CS: %h, SS: %h, RFLAGS: %h", task->state->rip, task->state->rsp, task->state->cs, task->state->ss, task->state->rflags); + + taskingMemoryTemporarySwitchBack(returnSpace); taskingProcessAddToTaskList(process, task); hashmapPut(taskGlobalMap, task->id, task); @@ -390,22 +401,7 @@ g_task* taskingCreateTask(g_virtual_address eip, g_process* process, g_security_ g_task* taskingCreateTaskVm86(g_process* process, uint32_t intr, g_vm86_registers in, g_vm86_registers* out) { - g_task* task = (g_task*) heapAllocateClear(sizeof(g_task)); - _taskingInitializeTask(task, process, G_SECURITY_LEVEL_KERNEL); - task->type = G_TASK_TYPE_VM86; - - g_physical_address returnDirectory = taskingMemoryTemporarySwitchTo(task->process->pageDirectory); - - taskingMemoryInitialize(task); - taskingStateResetVm86(task, in, intr); - task->vm86Data = (g_task_information_vm86*) heapAllocateClear(sizeof(g_task_information_vm86)); - task->vm86Data->out = out; - - taskingMemoryTemporarySwitchBack(returnDirectory); - - taskingProcessAddToTaskList(process, task); - hashmapPut(taskGlobalMap, task->id, task); - return task; + panic("no vm86"); } void taskingDestroyTask(g_task* task) @@ -419,7 +415,7 @@ void taskingDestroyTask(g_task* task) waitQueueWake(&task->waitersJoin); // Switch to task space - g_physical_address returnDirectory = taskingMemoryTemporarySwitchTo(task->process->pageDirectory); + g_physical_address returnDirectory = taskingMemoryTemporarySwitchTo(task->process->pageSpace); messageQueueTaskRemoved(task->id); taskingMemoryDestroy(task); diff --git a/kernel/src/kernel/tasking/tasking_memory.cpp b/kernel/src/kernel/tasking/tasking_memory.cpp index 96969373..01026550 100644 --- a/kernel/src/kernel/tasking/tasking_memory.cpp +++ b/kernel/src/kernel/tasking/tasking_memory.cpp @@ -24,14 +24,15 @@ #include "kernel/memory/memory.hpp" #include "kernel/memory/page_reference_tracker.hpp" #include "kernel/system/processor/processor.hpp" +#include "shared/memory/constants.hpp" #include "shared/logger/logger.hpp" #include "shared/panic.hpp" -bool taskingMemoryExtendHeap(g_task* task, int32_t amount, uint32_t* outAddress) +bool taskingMemoryExtendHeap(g_task* task, int32_t amount, g_address* outAddress) { g_process* process = task->process; mutexAcquire(&process->lock); - g_physical_address returnDirectory = taskingMemoryTemporarySwitchTo(task->process->pageDirectory); + g_physical_address returnDirectory = taskingMemoryTemporarySwitchTo(task->process->pageSpace); // Initialize the heap if necessary if(process->heap.brk == 0) @@ -51,39 +52,40 @@ bool taskingMemoryExtendHeap(g_task* task, int32_t amount, uint32_t* outAddress) g_virtual_address newBrk = oldBrk + amount; // Heap expansion is limited + // TODO limit heap expansion again? bool success = false; - if(newBrk >= G_USER_MAXIMUM_HEAP_BREAK) + // if(newBrk >= G_USER_MAXIMUM_HEAP_BREAK) + // { + // logInfo("%! process %i went out of memory during sbrk", "syscall", process->main->id); + // *outAddress = -1; + // } + // else + // { + // Expand if necessary + g_virtual_address virt_above; + while(newBrk > (virt_above = process->heap.start + process->heap.pages * G_PAGE_SIZE)) { - logInfo("%! process %i went out of memory during sbrk", "syscall", process->main->id); - *outAddress = -1; + g_physical_address phys = memoryPhysicalAllocate(); + pagingMapPage(virt_above, phys, G_PAGE_TABLE_USER_DEFAULT, G_PAGE_USER_DEFAULT); + ++process->heap.pages; } - else - { - // Expand if necessary - g_virtual_address virt_above; - while(newBrk > (virt_above = process->heap.start + process->heap.pages * G_PAGE_SIZE)) - { - g_physical_address phys = memoryPhysicalAllocate(); - pagingMapPage(virt_above, phys, G_PAGE_TABLE_USER_DEFAULT, G_PAGE_USER_DEFAULT); - ++process->heap.pages; - } - // Shrink if possible - g_virtual_address virtAligned; - while(newBrk < (virtAligned = process->heap.start + process->heap.pages * G_PAGE_SIZE - G_PAGE_SIZE)) - { - g_physical_address phys = pagingVirtualToPhysical(virtAligned); - pagingUnmapPage(virtAligned); - memoryPhysicalFree(phys); - - --process->heap.pages; - } + // Shrink if possible + g_virtual_address virtAligned; + while(newBrk < (virtAligned = process->heap.start + process->heap.pages * G_PAGE_SIZE - G_PAGE_SIZE)) + { + g_physical_address phys = pagingVirtualToPhysical(virtAligned); + pagingUnmapPage(virtAligned); + memoryPhysicalFree(phys); - process->heap.brk = newBrk; - *outAddress = oldBrk; - success = true; + --process->heap.pages; } + process->heap.brk = newBrk; + *outAddress = oldBrk; + success = true; + // } + taskingMemoryTemporarySwitchBack(returnDirectory); mutexRelease(&process->lock); return success; @@ -125,7 +127,7 @@ void taskingMemoryInitializeUtility(g_task* task) void taskingMemoryInitializeStacks(g_task* task) { // Interrupt stack for ring 3 & VM86 tasks - if(task->securityLevel != G_SECURITY_LEVEL_KERNEL || task->type == G_TASK_TYPE_VM86) + if(task->securityLevel != G_SECURITY_LEVEL_KERNEL) { task->interruptStack = taskingMemoryCreateStack(memoryVirtualRangePool, G_PAGE_TABLE_KERNEL_DEFAULT, G_PAGE_KERNEL_DEFAULT, G_TASKING_MEMORY_INTERRUPT_STACK_PAGES); @@ -139,8 +141,8 @@ void taskingMemoryInitializeStacks(g_task* task) // Create task stack if(task->type == G_TASK_TYPE_VM86) { - uint32_t stackSize = G_PAGE_SIZE; - task->stack.start = (uint32_t) lowerHeapAllocate(stackSize); + size_t stackSize = G_PAGE_SIZE; + task->stack.start = (g_address) lowerHeapAllocate(stackSize); task->stack.end = task->stack.start + stackSize; } else if(task->securityLevel == G_SECURITY_LEVEL_KERNEL) @@ -163,7 +165,7 @@ g_stack taskingMemoryCreateStack(g_address_range_pool* addressRangePool, uint32_ // Only allocate and map the last page of the stack; when the process faults, lazy-allocate more physical space. // The first page of the allocated virtual range is used as a "guard page" and makes the process fault when accessed. g_physical_address pagePhys = memoryPhysicalAllocate(); - uint32_t stackEnd = stackVirt + pages * G_PAGE_SIZE; + g_address stackEnd = stackVirt + pages * G_PAGE_SIZE; pagingMapPage(stackEnd - G_PAGE_SIZE, pagePhys, tableFlags, pageFlags); g_stack stack; @@ -235,64 +237,51 @@ void taskingMemoryDestroyStack(g_address_range_pool* addressRangePool, g_stack& addressRangePoolFree(addressRangePool, stack.start); } -g_physical_address taskingMemoryCreatePageDirectory(g_security_level securityLevel) +g_physical_address taskingMemoryCreatePageSpace() { - g_page_directory directoryCurrent = (g_page_directory) G_RECURSIVE_PAGE_DIRECTORY_ADDRESS; + auto currentPml4 = (g_address*) G_MEM_PHYS_TO_VIRT(pagingGetCurrentSpace()); - g_physical_address directoryPhys = memoryPhysicalAllocate(); - g_virtual_address directoryTempVirt = addressRangePoolAllocate(memoryVirtualRangePool, 1); - g_page_directory directoryTemp = (g_page_directory) directoryTempVirt; - pagingMapPage(directoryTempVirt, directoryPhys); + g_physical_address newPml4Phys = memoryPhysicalAllocate(); + auto newPml4 = (g_address*) G_MEM_PHYS_TO_VIRT(newPml4Phys); - // Copy kernel table mappings - for(uint32_t ti = 0; ti < 1024; ti++) + // Copy all higher-level mappings + for(size_t i = 0; i < 512; i++) { - if((directoryCurrent[ti] & G_PAGE_TABLE_USERSPACE) == 0) - directoryTemp[ti] = directoryCurrent[ti]; + if(i >= 256 && currentPml4[i]) + newPml4[i] = currentPml4[i]; else - directoryTemp[ti] = 0; + newPml4[i] = 0; } - // Copy mappings for the lowest 4 MiB - if(securityLevel < G_SECURITY_LEVEL_APPLICATION) - directoryTemp[0] = directoryCurrent[0]; - else - directoryTemp[0] = 0; - - // Recursive self-map - directoryTemp[1023] = directoryPhys | G_PAGE_TABLE_KERNEL_DEFAULT; - - // Unmap locally and free temporary range - pagingUnmapPage(directoryTempVirt); - addressRangePoolFree(memoryVirtualRangePool, directoryTempVirt); - - return directoryPhys; + return newPml4Phys; } -void taskingMemoryDestroyPageDirectory(g_physical_address directory) +void taskingMemoryDestroyPageSpace(g_physical_address directory) { g_physical_address returnDirectory = taskingMemoryTemporarySwitchTo(directory); // Clear mappings and free physical space above 4 MiB - g_page_directory directoryCurrent = (g_page_directory) G_RECURSIVE_PAGE_DIRECTORY_ADDRESS; - for(uint32_t ti = 1; ti < 1024; ti++) - { - if(!(directoryCurrent[ti] & G_PAGE_TABLE_USERSPACE)) - continue; - - g_page_table tableMapped = ((g_page_table) G_RECURSIVE_PAGE_DIRECTORY_AREA) + (0x400 * ti); - for(uint32_t pi = 0; pi < 1024; pi++) - { - if(tableMapped[pi] == 0) - continue; - - g_physical_address page = G_PAGE_ALIGN_DOWN(tableMapped[pi]); - memoryPhysicalFree(page); - } - - g_physical_address table = G_PAGE_ALIGN_DOWN(directoryCurrent[ti]); - memoryPhysicalFree(table); - } + // TODO + logInfo("%! taskingMemoryDestroyPageSpace not implemented", "todo"); + // g_page_directory directoryCurrent = (g_page_directory) G_RECURSIVE_PAGE_DIRECTORY_ADDRESS; + // for(uint32_t ti = 1; ti < 1024; ti++) + // { + // if(!(directoryCurrent[ti] & G_PAGE_USER_FLAG)) + // continue; + // + // g_page_table tableMapped = ((g_page_table) G_RECURSIVE_PAGE_DIRECTORY_AREA) + (0x400 * ti); + // for(uint32_t pi = 0; pi < 1024; pi++) + // { + // if(tableMapped[pi] == 0) + // continue; + // + // g_physical_address page = G_PAGE_ALIGN_DOWN(tableMapped[pi]); + // memoryPhysicalFree(page); + // } + // + // g_physical_address table = G_PAGE_ALIGN_DOWN(directoryCurrent[ti]); + // memoryPhysicalFree(table); + // } taskingMemoryTemporarySwitchBack(returnDirectory); @@ -304,7 +293,7 @@ void taskingMemoryInitializeTls(g_task* task) // Kernel thread-local storage if(!task->threadLocal.kernelThreadLocal) { - g_kernel_threadlocal* kernelThreadLocal = (g_kernel_threadlocal*) heapAllocate(sizeof(g_kernel_threadlocal)); + auto kernelThreadLocal = (g_kernel_threadlocal*) heapAllocate(sizeof(g_kernel_threadlocal)); kernelThreadLocal->processor = processorGetCurrentId(); task->threadLocal.kernelThreadLocal = kernelThreadLocal; } @@ -318,6 +307,8 @@ void taskingMemoryInitializeTls(g_task* task) // Allocate required virtual range uint32_t requiredSize = process->tlsMaster.size; uint32_t requiredPages = G_PAGE_ALIGN_UP(requiredSize) / G_PAGE_SIZE; + if(requiredPages < 1) + requiredPages = 1; g_virtual_address tlsStart = addressRangePoolAllocate(process->virtualRangePool, requiredPages); g_virtual_address tlsEnd = tlsStart + requiredPages * G_PAGE_SIZE; diff --git a/kernel/src/kernel/tasking/tasking_memory.hpp b/kernel/src/kernel/tasking/tasking_memory.hpp index 91f3e8fa..80559627 100644 --- a/kernel/src/kernel/tasking/tasking_memory.hpp +++ b/kernel/src/kernel/tasking/tasking_memory.hpp @@ -30,7 +30,7 @@ /** * Extends the heap of the task by an amount. */ -bool taskingMemoryExtendHeap(g_task* task, int32_t amount, uint32_t* outAddress); +bool taskingMemoryExtendHeap(g_task* task, int32_t amount, g_address* outAddress); /** * Creates the stacks and other utility memory for a newly created task. @@ -81,20 +81,17 @@ void taskingMemoryDestroyUtility(g_task* task); void taskingMemoryDestroyStack(g_address_range_pool* addressRangePool, g_stack& stack); /** - * Creates a new page directory to use for a new process. Clones the kernel space - * into the page directory, maps the lower memory and adds recursive mapping. + * Creates a new paging space to use for a new process. Clones the kernel space + * into the address space. * - * @param securityLevel - * security level to apply to the process address space - * - * @return the physical address of the directory + * @return the physical address of the PML4 */ -g_physical_address taskingMemoryCreatePageDirectory(g_security_level securityLevel); +g_physical_address taskingMemoryCreatePageSpace(); /** * Destory the page directory of a process. */ -void taskingMemoryDestroyPageDirectory(g_physical_address directory); +void taskingMemoryDestroyPageSpace(g_physical_address directory); /** * Initializes the tasks thread-local-storage. Creates a copy of the master TLS for this task. diff --git a/kernel/src/kernel/tasking/tasking_state.cpp b/kernel/src/kernel/tasking/tasking_state.cpp index 8e56c4e6..df0412f8 100644 --- a/kernel/src/kernel/tasking/tasking_state.cpp +++ b/kernel/src/kernel/tasking/tasking_state.cpp @@ -22,44 +22,22 @@ #include "kernel/memory/gdt.hpp" #include "kernel/system/interrupts/ivt.hpp" -void taskingStateResetVm86(g_task* task, g_vm86_registers in, uint32_t intr) -{ - g_processor_state_vm86* state = (g_processor_state_vm86*) (task->interruptStack.end - sizeof(g_processor_state_vm86)); - task->state = (g_processor_state*) state; - - memorySetBytes(state, 0, sizeof(g_processor_state_vm86)); - state->defaultFrame.eax = in.ax; - state->defaultFrame.ebx = in.bx; - state->defaultFrame.ecx = in.cx; - state->defaultFrame.edx = in.dx; - state->defaultFrame.ebp = 0; - state->defaultFrame.esi = in.si; - state->defaultFrame.edi = in.di; - - state->defaultFrame.eip = G_FP_OFF(ivt->entry[intr]); - state->defaultFrame.cs = G_FP_SEG(ivt->entry[intr]); - state->defaultFrame.eflags = 0x20202; - state->defaultFrame.ss = ((G_PAGE_ALIGN_DOWN(task->stack.start) + G_PAGE_SIZE) >> 4); - - state->gs = 0x00; - state->fs = 0x00; - state->es = in.es; - state->ds = in.ds; -} - -void taskingStateReset(g_task* task, g_address eip, g_security_level entryLevel) +void taskingStateReset(g_task* task, g_address rip, g_security_level entryLevel) { g_processor_state* state; - if(entryLevel == G_SECURITY_LEVEL_KERNEL && task->securityLevel > G_SECURITY_LEVEL_KERNEL) + if(task->securityLevel > G_SECURITY_LEVEL_KERNEL) state = (g_processor_state*) (task->interruptStack.end - sizeof(g_processor_state)); else state = (g_processor_state*) (task->stack.end - sizeof(g_processor_state)); - task->state = state; memorySetBytes((void*) task->state, 0, sizeof(g_processor_state)); - state->eflags = 0x200; - state->esp = (g_virtual_address) task->state; + state->rflags = 0x20202; + + if(entryLevel > G_SECURITY_LEVEL_KERNEL) + state->rsp = task->stack.end - 0x8; // TODO Find out why BOTH this and alignment in crt0 is required + else + state->rsp = (g_virtual_address) task->state; if(entryLevel == G_SECURITY_LEVEL_KERNEL) { @@ -67,7 +45,6 @@ void taskingStateReset(g_task* task, g_address eip, g_security_level entryLevel) state->ss = G_GDT_DESCRIPTOR_KERNEL_DATA | G_SEGMENT_SELECTOR_RING0; state->ds = G_GDT_DESCRIPTOR_KERNEL_DATA | G_SEGMENT_SELECTOR_RING0; state->es = G_GDT_DESCRIPTOR_KERNEL_DATA | G_SEGMENT_SELECTOR_RING0; - state->fs = G_GDT_DESCRIPTOR_KERNEL_DATA | G_SEGMENT_SELECTOR_RING0; } else { @@ -75,14 +52,12 @@ void taskingStateReset(g_task* task, g_address eip, g_security_level entryLevel) state->ss = G_GDT_DESCRIPTOR_USER_DATA | G_SEGMENT_SELECTOR_RING3; state->ds = G_GDT_DESCRIPTOR_USER_DATA | G_SEGMENT_SELECTOR_RING3; state->es = G_GDT_DESCRIPTOR_USER_DATA | G_SEGMENT_SELECTOR_RING3; - state->fs = G_GDT_DESCRIPTOR_USER_DATA | G_SEGMENT_SELECTOR_RING3; - state->gs = G_GDT_DESCRIPTOR_USERTHREADLOCAL; } if(entryLevel <= G_SECURITY_LEVEL_DRIVER) { - state->eflags |= 0x3000; // IOPL 3 + state->rflags |= 0x3000; // IOPL 3 } - state->eip = eip; -} \ No newline at end of file + state->rip = rip; +} diff --git a/kernel/src/kernel/tasking/tasking_state.hpp b/kernel/src/kernel/tasking/tasking_state.hpp index d0ab53e1..1785256a 100644 --- a/kernel/src/kernel/tasking/tasking_state.hpp +++ b/kernel/src/kernel/tasking/tasking_state.hpp @@ -23,8 +23,6 @@ #include "kernel/tasking/tasking.hpp" -void taskingStateReset(g_task* task, g_address eip, g_security_level entryLevel); - -void taskingStateResetVm86(g_task* task, g_vm86_registers in, uint32_t intr); +void taskingStateReset(g_task* task, g_address rip, g_security_level entryLevel); #endif diff --git a/kernel/src/kernel/utils/debug.cpp b/kernel/src/kernel/utils/debug.cpp new file mode 100644 index 00000000..9e9dde09 --- /dev/null +++ b/kernel/src/kernel/utils/debug.cpp @@ -0,0 +1,154 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * * + * Ghost, a micro-kernel based operating system for the x86 architecture * + * Copyright (C) 2025, Max Schlüssel * + * * + * This program 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. * + * * + * This program 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 this program. If not, see . * + * * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#include "kernel/utils/debug.hpp" +#include "kernel/system/timing/pit.hpp" +#include "shared/logger/logger.hpp" +#include "kernel/memory/paging.hpp" +#include "shared/memory/constants.hpp" + +void debugHardSleep(uint64_t millis) +{ + for(int i = 0; i < millis; i++) + { + pitPrepareSleep(1000); // 1ms + pitPerformSleep(); + } +} + +void hexDumpRow(void* location, int bytes, bool center = false) +{ + auto centerStr = center ? "<-" : ""; + + if(bytes == 1) + { + auto loc8 = (uint8_t*) location; + logInfo("%# %x: %h %h %h %h %h %h %h %h %c%c%c%c%c%c%c%c %s", location, + loc8[0], loc8[1], loc8[2], loc8[3], loc8[4], loc8[5], loc8[6], loc8[7], + loc8[0], loc8[1], loc8[2], loc8[3], loc8[4], loc8[5], loc8[6], loc8[7], + centerStr); + } + else if(bytes == 8) + { + auto loc64 = (uint64_t*) location; + logInfo("%# %x: %x %s", location, *loc64, centerStr); + } +} + +void hexDump(void* location, int minus, int plus, int bytes) +{ + for(int i = minus; i > 0; i--) + hexDumpRow((uint8_t*) location - i * bytes, bytes); + + hexDumpRow(location, bytes, true); + + for(int i = 1; i < plus + 1; ++i) + hexDumpRow((uint8_t*) location + i * bytes, bytes); +} + +void hexDump8(void* location, int minus, int plus) +{ + hexDump(location, minus, plus, 1); +} + +void hexDump64(void* location, int minus, int plus) +{ + hexDump(location, minus, plus, 8); +} + +void debugDumpPageSpace() +{ + logInfo("%! debug logging initial space:", "paging"); + auto pml4 = (g_address*) G_MEM_PHYS_TO_VIRT(pagingGetCurrentSpace()); + for(int first = 0; first < 512; first++) + { + if(!pml4[first]) + continue; + + logInfo("%# %i: %h -> %h %s", first, G_PML4_VIRT_ADDRESS(first, 0, 0, 0), pml4[first], + pml4[first] & G_PAGE_USER_FLAG ? "user" :"kernel"); + auto pdpt = (g_address*) G_MEM_PHYS_TO_VIRT(G_PAGE_ALIGN_DOWN(pml4[first])); + for(int second = 0; second < 512; second++) + { + if(!pdpt[second]) + continue; + + logInfo("%# %i > %i: %h -> %h %s", first, second, G_PML4_VIRT_ADDRESS(first, second, 0, 0), pdpt[second], + pdpt[second]& G_PAGE_USER_FLAG ? "user":"kernel"); + auto pd = (g_address*) G_MEM_PHYS_TO_VIRT(G_PAGE_ALIGN_DOWN(pdpt[second])); + for(int third = 0; third < 512; third++) + { + if(!pd[third]) + continue; + + logInfo("%# %i > %i > %i: %h -> %h %s", first, second, third, + G_PML4_VIRT_ADDRESS(first, second, third, 0), + pd[third], pd[third]& G_PAGE_USER_FLAG ? "user":"kernel"); + if(pd[third] & G_PAGE_LARGE_PAGE_FLAG) + { + logInfo("%# up to %h", G_PML4_VIRT_ADDRESS(first, second, third, 0) + 0x200000); + } + else + { + auto pt = (g_address*) G_MEM_PHYS_TO_VIRT(G_PAGE_ALIGN_DOWN(pd[third])); + for(int fourth = 0; fourth < 512; fourth++) + { + if(!pt[fourth]) + continue; + + logInfo("%# %i > %i > %i > %i: %h -> %h %s", first, second, third, fourth, + G_PML4_VIRT_ADDRESS(first, second, third, fourth), + pt[fourth], pt[fourth]& G_PAGE_USER_FLAG ? "user":"kernel"); + } + } + } + } + } +} + +void debugPagingPrintValues(g_virtual_address addr) +{ + logInfo("%! debug output for %x", "paging", addr); + + auto pml4 = (g_address*) G_MEM_PHYS_TO_VIRT(pagingGetCurrentSpace()); + uint64_t pml4Index = G_PML4_INDEX(addr); + logInfo("%# in PML4: %x (NX? %i)", pml4[pml4Index], ((1ULL << 63) & pml4[pml4Index])); + uint64_t pdptAddr = pml4[pml4Index] & ~G_PAGE_ALIGN_MASK; + if(!pdptAddr) + return; + + auto pdpt = (g_address*) G_MEM_PHYS_TO_VIRT(pdptAddr); + uint64_t pdptIndex = G_PDPT_INDEX(addr); + logInfo("%# in PDPT: %x (NX? %i)", pdpt[pdptIndex], ((1ULL << 63) & pdpt[pdptIndex])); + uint64_t pdAddr = pdpt[pdptIndex] & ~G_PAGE_ALIGN_MASK; + if(!pdAddr) + return; + + auto pd = (g_address*) G_MEM_PHYS_TO_VIRT(pdAddr); + uint64_t pdIndex = G_PD_INDEX(addr); + logInfo("%# in PD: %x (NX? %i)", pd[pdIndex], ((1ULL << 63) & pd[pdIndex])); + uint64_t ptAddr = pd[pdIndex] & ~G_PAGE_ALIGN_MASK; + if(!ptAddr) + return; + + auto pt = (g_address*) G_MEM_PHYS_TO_VIRT(ptAddr); + uint64_t ptIndex = G_PT_INDEX(addr); + logInfo("%# in PT: %x (NX? %i)", pt[ptIndex], ((1ULL << 63) & pt[ptIndex])); +} diff --git a/kernel/src/loader/memory/gdt.hpp b/kernel/src/kernel/utils/debug.hpp similarity index 78% rename from kernel/src/loader/memory/gdt.hpp rename to kernel/src/kernel/utils/debug.hpp index c689e33d..841e5cae 100644 --- a/kernel/src/loader/memory/gdt.hpp +++ b/kernel/src/kernel/utils/debug.hpp @@ -1,7 +1,7 @@ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Ghost, a micro-kernel based operating system for the x86 architecture * - * Copyright (C) 2015, Max Schlüssel * + * Copyright (C) 2025, Max Schlüssel * * * * This program is free software: you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * @@ -18,17 +18,20 @@ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ -#ifndef __GDT_INITIALIZER__ -#define __GDT_INITIALIZER__ +#ifndef __UTILS_DEBUG__ +#define __UTILS_DEBUG__ +#include #include -/** - * Creates the GDT in the page addressed by the usableAddress. - * - * @param usableAddress the address of the page that can be used to - * store the GDT pointer and the GDT - */ -void gdtInitialize(g_address usableAddress); +void debugHardSleep(uint64_t millis); + +void hexDump8(void* location, int minus = 0, int plus = 0); + +void hexDump64(void* location, int minus = 0, int plus = 0); + +void debugDumpPageSpace(); + +void debugPagingPrintValues(g_virtual_address addr); #endif diff --git a/kernel/src/loader/kernel_loader.cpp b/kernel/src/loader/kernel_loader.cpp deleted file mode 100644 index 3ae7f292..00000000 --- a/kernel/src/loader/kernel_loader.cpp +++ /dev/null @@ -1,176 +0,0 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * * - * Ghost, a micro-kernel based operating system for the x86 architecture * - * Copyright (C) 2015, Max Schlüssel * - * * - * This program 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. * - * * - * This program 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 this program. If not, see . * - * * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -#include "loader/kernel_loader.hpp" -#include "loader/memory/paging.hpp" -#include "loader/setup_information.hpp" -#include "shared/logger/logger.hpp" -#include "shared/memory/bitmap_page_allocator.hpp" -#include "shared/memory/constants.hpp" -#include "shared/memory/memory.hpp" -#include "shared/memory/paging.hpp" -#include "shared/panic.hpp" -#include "shared/video/pretty_boot.hpp" -#include -#include - -/** - * This must stay as a global variable. We can't put this on - * the stack because we change ESP before calling it. - */ -static void (*kernelMain)(g_setup_information*); - -void kernelLoaderLoad(g_multiboot_module* kernelModule) -{ - Elf32_Ehdr* elfHeader = (Elf32_Ehdr*) kernelModule->moduleStart; - kernelLoaderCheckHeader(elfHeader); - kernelLoaderLoadBinary(elfHeader); - - // Initialize rest of kernel space - uint32_t* directory = (uint32_t*) G_RECURSIVE_PAGE_DIRECTORY_ADDRESS; - for(uint32_t ti = G_TABLE_IN_DIRECTORY_INDEX(setupInformation.kernelImageStart); ti < 1024; ti++) - { - if(directory[ti] == 0) - { - uint32_t tableChunkAddress = (uint32_t) bitmapPageAllocatorAllocate(&memoryPhysicalAllocator); - directory[ti] = tableChunkAddress | G_PAGE_TABLE_KERNEL_DEFAULT; - - uint32_t* table = ((uint32_t*) G_RECURSIVE_PAGE_DIRECTORY_AREA) + (0x400 * ti); - for(uint32_t i = 0; i < 1024; i++) - table[i] = 0; - } - } - - // Start kernel stack after kernel image - setupInformation.stackStart = setupInformation.kernelImageEnd; - setupInformation.stackEnd = setupInformation.stackStart + G_PAGE_SIZE; - - g_virtual_address stackVirt = setupInformation.stackEnd - sizeof(uint32_t); - g_physical_address stackPhys = bitmapPageAllocatorAllocate(&memoryPhysicalAllocator); - if(stackPhys == 0) - { - G_PRETTY_BOOT_FAIL("Failed to allocate kernel stack"); - panic("%! out of pages when trying to create kernel stack", "kernload"); - } - - pagingMapPage(setupInformation.stackStart, stackPhys, G_PAGE_TABLE_KERNEL_DEFAULT, G_PAGE_KERNEL_DEFAULT); - - G_PRETTY_BOOT_STATUS_P(20); - kernelLoaderCreateHeap(); - kernelLoaderEnterMain(elfHeader->e_entry, stackVirt); -} - -void kernelLoaderCreateHeap() -{ - uint32_t heapStart = setupInformation.stackEnd; - uint32_t heapEnd = heapStart + G_KERNEL_HEAP_INIT_SIZE; - for(uint32_t virt = heapStart; virt < heapEnd; virt += G_PAGE_SIZE) - { - uint32_t phys = bitmapPageAllocatorAllocate(&memoryPhysicalAllocator); - if(phys == 0) - { - G_PRETTY_BOOT_FAIL("Failed to allocate kernel heap"); - panic("%! out of pages when trying to allocate kernel heap, allocated to %h", "kernload", virt); - } - - pagingMapPage(virt, phys, G_PAGE_TABLE_KERNEL_DEFAULT, G_PAGE_KERNEL_DEFAULT); - } - setupInformation.heapStart = heapStart; - setupInformation.heapEnd = heapEnd; -} - -void kernelLoaderEnterMain(g_address entryAddress, g_address kernelEsp) -{ - kernelMain = (void (*)(g_setup_information*)) entryAddress; - - // Switch to kernel stack & enter kernel - asm volatile("mov %0, %%esp\n" - "mov %%esp, %%ebp\n" ::"r"(kernelEsp)); - kernelMain(&setupInformation); - __builtin_unreachable(); -} - -void kernelLoaderLoadBinary(Elf32_Ehdr* header) -{ - logDebug("%! loading binary to higher memory", "kernload"); - uint32_t imageStart = UINT32_MAX; - uint32_t imageEnd = 0; - - for(uint32_t i = 0; i < header->e_phnum; i++) - { - Elf32_Phdr* programHeader = (Elf32_Phdr*) (((uint32_t) header) + header->e_phoff + (header->e_phentsize * i)); - - if(programHeader->p_type != PT_LOAD) - continue; - - if(programHeader->p_vaddr < imageStart) - imageStart = programHeader->p_vaddr; - - if(programHeader->p_vaddr + programHeader->p_memsz > imageEnd) - imageEnd = programHeader->p_vaddr + programHeader->p_memsz; - } - - imageStart = G_PAGE_ALIGN_DOWN(imageStart); - imageEnd = G_PAGE_ALIGN_UP(imageEnd); - logDebug("%! image spans from %h to %h", "kernload", imageStart, imageEnd); - - for(uint32_t virt = imageStart; virt < imageEnd; virt += G_PAGE_SIZE) - { - uint32_t phys = bitmapPageAllocatorAllocate(&memoryPhysicalAllocator); - pagingMapPage(virt, phys, G_PAGE_TABLE_KERNEL_DEFAULT, G_PAGE_KERNEL_DEFAULT); - } - - for(uint32_t i = 0; i < header->e_phnum; i++) - { - Elf32_Phdr* programHeader = (Elf32_Phdr*) (((uint32_t) header) + header->e_phoff + (header->e_phentsize * i)); - if(programHeader->p_type != PT_LOAD) - continue; - - memorySetBytes((void*) programHeader->p_vaddr, 0, programHeader->p_memsz); - memoryCopy((void*) programHeader->p_vaddr, (uint8_t*) (((uint32_t) header) + programHeader->p_offset), programHeader->p_filesz); - } - - logDebug("%! kernel image loaded to space %h - %h", "kernload", imageStart, imageEnd); - setupInformation.kernelImageStart = imageStart; - setupInformation.kernelImageEnd = imageEnd; -} - -void kernelLoaderCheckHeader(Elf32_Ehdr* header) -{ - if(!(header->e_ident[EI_MAG0] == ELFMAG0 && header->e_ident[EI_MAG1] == ELFMAG1 && header->e_ident[EI_MAG2] == ELFMAG2 && header->e_ident[EI_MAG3] == ELFMAG3)) - panic("%! binary is not ELF", "kernload"); - - if(header->e_type != ET_EXEC) - panic("%! binary is not executable", "kernload"); - - if(header->e_machine != EM_386) - panic("%! binary target architecture not i386", "kernload"); - - if(header->e_ident[EI_CLASS] != ELFCLASS32) - panic("%! binary is not 32bit", "kernload"); - - if(header->e_ident[EI_DATA] != ELFDATA2LSB) - panic("%! binary does not have little endian data encoding", "kernload"); - - if(header->e_version != EV_CURRENT) - panic("%! binary is not standard ELF", "kernload"); - - logDebug("%! binary ELF validation successful", "kernload"); -} diff --git a/kernel/src/loader/kernel_loader.hpp b/kernel/src/loader/kernel_loader.hpp deleted file mode 100644 index 86fee241..00000000 --- a/kernel/src/loader/kernel_loader.hpp +++ /dev/null @@ -1,59 +0,0 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * * - * Ghost, a micro-kernel based operating system for the x86 architecture * - * Copyright (C) 2015, Max Schlüssel * - * * - * This program 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. * - * * - * This program 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 this program. If not, see . * - * * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -#ifndef GHOST_LOADER_KERNELLOADER_KERNELLOADER -#define GHOST_LOADER_KERNELLOADER_KERNELLOADER - -#include "elf.h" -#include "shared/multiboot/multiboot.hpp" -#include "shared/setup_information.hpp" - -/** - * Loads the given kernel binary module. - * - * @param kernelModule the multiboot module containing the kernel - */ -void kernelLoaderLoad(g_multiboot_module* kernelModule); - -/** - * Checks the ELF32 header for validity. - * - * @param header the header to check - */ -void kernelLoaderCheckHeader(Elf32_Ehdr* header); - -/** - * Loads the kernel binary starting at the given ELF header. - * - * @param header the ELF header - */ -void kernelLoaderLoadBinary(Elf32_Ehdr* header); - -/** - * Creates the kernels heap. - */ -void kernelLoaderCreateHeap(); - -/** - * Changes stack and calls the kernel main function. - */ -void kernelLoaderEnterMain(g_address entryAddress, g_address newEsp); - -#endif diff --git a/kernel/src/loader/loader.asm b/kernel/src/loader/loader.asm deleted file mode 100644 index 0e07059f..00000000 --- a/kernel/src/loader/loader.asm +++ /dev/null @@ -1,81 +0,0 @@ -;* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * -;* * -;* Ghost, a micro-kernel based operating system for the x86 architecture * -;* Copyright (C) 2015, Max Schlüssel * -;* * -;* This program 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. * -;* * -;* This program 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 this program. If not, see . * -;* * -;* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - - -BITS 32 - -; # MULTIBOOT -section .multiboot - MODULEALIGN equ 1 << 0 - MEMINFO equ 1 << 1 - FLAGS equ MODULEALIGN | MEMINFO - MAGIC equ 0x1BADB002 - CHECKSUM equ -(MAGIC + FLAGS) - - ; Fill constants into memory (dwords) - align 4 - dd MAGIC - dd FLAGS - dd CHECKSUM - - - -; # CODE -section .text - - ; Entry point for GRUB - global loaderEntry - - ; Initialization method - extern loaderMain - - ; Create the initial loader stack - STACKSIZE equ 0x1000 - - ; Calls the initialization routines - loaderEntry: - ; Set the stack - mov esp, stack + STACKSIZE - mov ebp, esp - - ; We don't want interrupts until the kernel is ready - cli - - ; Call the loader - push eax ; Magic number - push ebx ; Multiboot information pointer - call loaderMain - - ; Hang the system after execution - cli - hlt - - -; # DATA -section .bss - - ; Align the location of the following res-commands - align 4 - - ; Reserves space for the initial kernel stack - stack: - resb STACKSIZE - - diff --git a/kernel/src/loader/loader.cpp b/kernel/src/loader/loader.cpp deleted file mode 100644 index 3a7cbf1e..00000000 --- a/kernel/src/loader/loader.cpp +++ /dev/null @@ -1,132 +0,0 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * * - * Ghost, a micro-kernel based operating system for the x86 architecture * - * Copyright (C) 2015, Max Schlüssel * - * * - * This program 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. * - * * - * This program 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 this program. If not, see . * - * * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -#include "loader/loader.hpp" -#include "loader/kernel_loader.hpp" -#include "loader/memory/physical.hpp" -#include "loader/setup_information.hpp" -#include "shared/debug/debug_interface.hpp" -#include "shared/logger/logger.hpp" -#include "shared/panic.hpp" -#include "shared/system/bios_data_area.hpp" -#include "shared/system/serial_port.hpp" -#include "shared/video/console_video.hpp" -#include "shared/video/pretty_boot.hpp" - -// Symbol provided by linker at end of loader binary -extern "C" void* endAddress; - -extern "C" void loaderMain(g_multiboot_information* multiboot, uint32_t magicNumber) -{ - if(magicNumber != G_MULTIBOOT_BOOTLOADER_MAGIC) - panic("%! invalid magic number in multiboot struct", "mboot"); - - if(multiboot->flags & G_MULTIBOOT_FLAGS_BOOTLDNAM) - logInfo("%! loaded by: %s", "mboot", multiboot->bootloaderName); - - loaderEnableLoggingFeatures(); - setupInformation.multibootInformation = multiboot; - loaderInitializeMemory(); - loaderStartKernel(); -} - -g_physical_address loaderSetupGdt() -{ - g_address loaderEnd = G_PAGE_ALIGN_UP((g_address) &endAddress); - g_address gdtPage = memoryPhysicalAllocateInitial(loaderEnd, 1); - gdtInitialize(gdtPage); - return gdtPage + G_PAGE_SIZE; -} - -/** - * The bootloader has loaded the kernel and the ramdisk as multiboot modules - * into memory somewhere after 0x00100000. The GDT is allocated in the first - * found free physical page. The physical memory map is interpreted to - * determine how much space is required for the bitmap array used by the - * physical allocator. The bitmap array starts right after the GDT page. - * - * The end of the bitmap array is also the end of the "reserved area", which - * is identity-mapped so that the kernel can access this data. - * - * Since there is often some free space before the multiboot modules, - * the memory layout usually looks like this after initializing: - * - * [0x0-0x100000]...[gdt][mb-kernel][mb-ramdisk][bitmap-array]... - */ -void loaderInitializeMemory() -{ - g_physical_address gdtEnd = loaderSetupGdt(); - - uint32_t bitmapRequiredMemory = memoryPhysicalReadMemoryMap(gdtEnd, 0); - setupInformation.bitmapArrayStart = memoryPhysicalAllocateInitial(gdtEnd, G_PAGE_ALIGN_UP(bitmapRequiredMemory) / G_PAGE_SIZE); - setupInformation.bitmapArrayEnd = G_PAGE_ALIGN_UP(setupInformation.bitmapArrayStart + bitmapRequiredMemory); - memoryPhysicalReadMemoryMap(setupInformation.bitmapArrayEnd, setupInformation.bitmapArrayStart); - bitmapPageAllocatorInitialize(&memoryPhysicalAllocator, (g_bitmap_header*) setupInformation.bitmapArrayStart); - - setupInformation.initialPageDirectoryPhysical = pagingInitialize(setupInformation.bitmapArrayEnd); -} - -void loaderStartKernel() -{ - g_multiboot_module* kernelModule = multibootFindModule(setupInformation.multibootInformation, "/boot/kernel"); - if(!kernelModule) - { - G_PRETTY_BOOT_FAIL("Kernel module not found"); - panic("%! kernel module not found", "loader"); - } - - G_PRETTY_BOOT_STATUS_P(5); - logInfo("%! found kernel binary at %h, loading...", "loader", kernelModule->moduleStart); - logInfo(""); - - kernelLoaderLoad(kernelModule); -} - -void loaderEnableLoggingFeatures() -{ - g_com_port_information comPortInfo = biosDataArea->comPortInfo; - if(comPortInfo.com1 > 0) - { - serialPortInitialize(comPortInfo.com1, false); // Initialize in poll mode - loggerEnableSerial(true); - debugInterfaceInitialize(comPortInfo.com1); - } - else - { - logWarn("%! COM1 port not available for serial debug output", "logger"); - } - - if(G_PRETTY_BOOT) - { - prettyBootEnable(); - } - else - { - consoleVideoClear(); - } - - logInfo(""); - consoleVideoSetColor(0x90); - logInfon("Ghost Loader"); - consoleVideoSetColor(0x0F); - logInfo(" Version %i.%i.%i", G_LOADER_VERSION_MAJOR, G_LOADER_VERSION_MINOR, G_LOADER_VERSION_PATCH); - logInfo(""); - G_PRETTY_BOOT_STATUS_P(1); -} diff --git a/kernel/src/loader/loader.hpp b/kernel/src/loader/loader.hpp deleted file mode 100644 index e6d9368e..00000000 --- a/kernel/src/loader/loader.hpp +++ /dev/null @@ -1,66 +0,0 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * * - * Ghost, a micro-kernel based operating system for the x86 architecture * - * Copyright (C) 2015, Max Schlüssel * - * * - * This program 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. * - * * - * This program 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 this program. If not, see . * - * * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -#ifndef __LOADER__ -#define __LOADER__ - -#include "loader/memory/gdt.hpp" -#include "loader/memory/paging.hpp" -#include "shared/memory/bitmap_page_allocator.hpp" -#include "shared/memory/memory.hpp" -#include "shared/multiboot/multiboot.hpp" -#include "shared/setup_information.hpp" -#include - -/** - * Initialization function, called from the loader assembly. Checks the - * multiboot magic number and then passes the multiboot structure to the - * loader for further initialization. - * - * @param multibootStruct the multiboot structure passed by bootloader - * @param magicNumber the magic number passed by bootloader - */ -extern "C" void loaderMain(g_multiboot_information* multibootStruct, uint32_t magicNumber); - -/** - * Initializes memory management. - */ -void loaderInitializeMemory(); - -/** - * Searches for the kernel multiboot module and executes it. - */ -void loaderStartKernel(); - -/** - * Sets the global descriptor table up and returns the end address. - */ -g_address loaderSetupGdt(); - -/** - * This function is used to find a chunk of free memory before any memory management was initialized. - * It is used to find a place to put the GDT and the bitmap, to avoid accidentally overwriting - * multiboot modules. - */ -g_address loaderFindNextFreePages(g_address start, int pages); - -void loaderEnableLoggingFeatures(); - -#endif diff --git a/kernel/src/loader/logger/logger.cpp b/kernel/src/loader/logger/logger.cpp deleted file mode 100644 index aa167f49..00000000 --- a/kernel/src/loader/logger/logger.cpp +++ /dev/null @@ -1,39 +0,0 @@ -#/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * * - * Ghost, a micro-kernel based operating system for the x86 architecture * - * Copyright (C) 2015, Max Schlüssel * - * * - * This program 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. * - * * - * This program 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 this program. If not, see . * - * * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -#include "shared/logger/logger.hpp" - -void loggerPrintLocked(const char* message, ...) -{ - va_list valist; - va_start(valist, message); - loggerPrintFormatted(message, valist); - va_end(valist); -} - -void loggerPrintlnLocked(const char* message, ...) -{ - va_list valist; - va_start(valist, message); - loggerPrintFormatted(message, valist); - va_end(valist); - loggerPrintCharacter('\n'); -} - diff --git a/kernel/src/loader/memory/gdt.cpp b/kernel/src/loader/memory/gdt.cpp deleted file mode 100644 index a1cfdef4..00000000 --- a/kernel/src/loader/memory/gdt.cpp +++ /dev/null @@ -1,47 +0,0 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * * - * Ghost, a micro-kernel based operating system for the x86 architecture * - * Copyright (C) 2015, Max Schlüssel * - * * - * This program 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. * - * * - * This program 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 this program. If not, see . * - * * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -#include "loader/memory/gdt.hpp" -#include "shared/logger/logger.hpp" -#include "shared/memory/gdt.hpp" - -void gdtInitialize(g_address gdtPage) -{ - g_address gdtAddress = gdtPage + sizeof(g_gdt_pointer); - - g_gdt_pointer* gdtPointer = (g_gdt_pointer*) gdtPage; - gdtPointer->limit = (sizeof(g_gdt_entry) * 3) - 1; - gdtPointer->base = gdtAddress; - g_gdt_entry* gdt = (g_gdt_entry*) gdtAddress; - - // Null descriptor, position 0x00 - gdtCreateGate(&gdt[0], 0, 0, 0, 0); - - // Kernel code segment descriptor, position 0x08 - gdtCreateGate(&gdt[1], 0, 0xFFFFFFFF, G_ACCESS_BYTE__KERNEL_CODE_SEGMENT, 0xCF); - - // Kernel data segment descriptor, position 0x10 - gdtCreateGate(&gdt[2], 0, 0xFFFFFFFF, G_ACCESS_BYTE__KERNEL_DATA_SEGMENT, 0xCF); - - logDebug("%! descriptor table created at %h", "initgdt", gdtAddress); - logDebug("%! pointer at %h with base %h and limit %h", "initgdt", gdtPointer, gdtPointer->base, gdtPointer->limit); - _loadGdt(gdtPage); - logDebug("%! initialized", "initgdt"); -} diff --git a/kernel/src/loader/memory/paging.cpp b/kernel/src/loader/memory/paging.cpp deleted file mode 100644 index 49be2ff4..00000000 --- a/kernel/src/loader/memory/paging.cpp +++ /dev/null @@ -1,136 +0,0 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * * - * Ghost, a micro-kernel based operating system for the x86 architecture * - * Copyright (C) 2015, Max Schlüssel * - * * - * This program 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. * - * * - * This program 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 this program. If not, see . * - * * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -#include "loader/memory/paging.hpp" -#include "loader/memory/physical.hpp" -#include "loader/setup_information.hpp" -#include "shared/logger/logger.hpp" -#include "shared/memory/bitmap_page_allocator.hpp" -#include "shared/memory/constants.hpp" -#include "shared/memory/memory.hpp" -#include "shared/memory/paging.hpp" -#include "shared/panic.hpp" - -g_physical_address pagingInitialize(g_virtual_address reservedAreaEnd) -{ - g_physical_address pageDirPhys = bitmapPageAllocatorAllocate(&memoryPhysicalAllocator); - if(!pageDirPhys) - panic("pagingInitialize: failed to allocate memory for page directory"); - - g_page_directory pageDirectory = (g_page_directory) pageDirPhys; - - for(uint32_t i = 0; i < 1024; i++) - pageDirectory[i] = 0; - pageDirectory[1023] = pageDirPhys | G_PAGE_TABLE_KERNEL_DEFAULT; - - pagingIdentityMap(pageDirectory, 0, reservedAreaEnd, G_PAGE_TABLE_USER_DEFAULT, G_PAGE_USER_DEFAULT); - pagingRelocateMultibootModules(pageDirectory, reservedAreaEnd); - pagingEnableGlobalPageFlag(); - pagingSwitchToSpace(pageDirPhys); - pagingEnable(); - return pageDirPhys; -} - -void pagingEnableGlobalPageFlag() -{ - uint32_t cr4; - asm volatile("mov %%cr4, %0" - : "=r"(cr4)); - cr4 |= (1 << 7); - asm volatile("mov %0, %%cr4" ::"b"(cr4)); -} - -void pagingRelocateMultibootModules(g_page_directory pageDirectory, g_address startAt) -{ - g_multiboot_information* mbInfo = setupInformation.multibootInformation; - g_address nextModuleLocation = startAt; - - for(int i = 0; i < (int) mbInfo->modulesCount; i++) - { - g_multiboot_module* module = &mbInfo->modules[i]; - g_address modPhysStartAligned = G_PAGE_ALIGN_DOWN(module->moduleStart); - g_address modPhysOff = module->moduleStart - modPhysStartAligned; - g_address modPhysEndAligned = G_PAGE_ALIGN_UP(module->moduleEnd); - g_address modPhysLen = module->moduleEnd - module->moduleStart; - - g_address modVirtStartAligned = nextModuleLocation; - g_address modVirtStart = modVirtStartAligned + modPhysOff; - - for(uint32_t off = 0; off < modPhysEndAligned - modPhysStartAligned; off += G_PAGE_SIZE) - pagingMapPageToDirectory(pageDirectory, modVirtStartAligned + off, modPhysStartAligned + off, - G_PAGE_TABLE_USER_DEFAULT, G_PAGE_USER_DEFAULT); - - // Finish relocation by updating multiboot structure - logDebugn("%! relocated, mapped phys %h-%h", "mmodule", module->moduleStart, module->moduleEnd); - module->moduleStart = modVirtStart; - module->moduleEnd = modVirtStart + modPhysLen; - logDebug(" to virt %h-%h", module->moduleStart, module->moduleEnd); - - nextModuleLocation = G_PAGE_ALIGN_UP(module->moduleEnd); - } -} - -void pagingIdentityMap(g_page_directory directory, uint32_t start, uint32_t end, uint32_t tableFlags, uint32_t pageFlags) -{ - logDebug("%! identity-mapping: %h - %h", "paging", start, end); - - while(start < end) - { - pagingMapPageToDirectory(directory, start, start, tableFlags, pageFlags); - start += G_PAGE_SIZE; - } -} - -void pagingMapPageToDirectory(g_page_directory directory, g_address virtualAddress, g_address physicalAddress, uint32_t tableFlags, uint32_t pageFlags) -{ - uint32_t ti = G_TABLE_IN_DIRECTORY_INDEX(virtualAddress); - uint32_t pi = G_PAGE_IN_TABLE_INDEX(virtualAddress); - - if(directory[ti] == 0) - { - g_physical_address tablePage = (uint32_t) bitmapPageAllocatorAllocate(&memoryPhysicalAllocator); - if(!tablePage) - panic("pagingMapPage: failed to map %h -> %h, could not allocate page for table", virtualAddress, physicalAddress); - - g_page_table table = (g_page_table) tablePage; - for(uint32_t i = 0; i < 1024; i++) - table[i] = 0; - - directory[ti] = tablePage | tableFlags; - } - - g_page_table table = (g_page_table) (directory[ti] & 0xFFFFF000); - if(table[pi]) - panic("pagingMapPage: duplicate mapping to address %h -> %h, table value: %h", virtualAddress, physicalAddress, table[pi]); - - table[pi] = physicalAddress | pageFlags; - pagingInvalidatePage(virtualAddress); -} - -void pagingEnable() -{ - logDebug("%! enabling", "paging"); - - uint32_t cr0; - asm volatile("mov %%cr0, %0" - : "=b"(cr0)); - cr0 |= 0x80000000; - asm volatile("mov %0, %%cr0" ::"b"(cr0)); -} diff --git a/kernel/src/loader/memory/paging.hpp b/kernel/src/loader/memory/paging.hpp deleted file mode 100644 index 4f246063..00000000 --- a/kernel/src/loader/memory/paging.hpp +++ /dev/null @@ -1,68 +0,0 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * * - * Ghost, a micro-kernel based operating system for the x86 architecture * - * Copyright (C) 2015, Max Schlüssel * - * * - * This program 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. * - * * - * This program 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 this program. If not, see . * - * * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -#ifndef __PAGING_INITIALIZER__ -#define __PAGING_INITIALIZER__ - -#include "shared/memory/paging.hpp" -#include "shared/setup_information.hpp" -#include - -/** - * Initially creates the paging directory and identity maps the lower 1MB plus the area of the kernel - * (end of this is delimited by the parameter given to initialize). Identity-maps the memory from - * 0x00000000 to reservedAreaEnd. - * - * @param reservedAreaEnd end of the reserved kernel area - * @returns the allocated physical directory - */ -g_physical_address pagingInitialize(g_virtual_address reservedAreaEnd); - -/** - * Sets the "page global enabled" in the CR4 to enable the use of global pages for the kernel space. - */ -void pagingEnableGlobalPageFlag(); - -/** - * Enables paging. - */ -void pagingEnable(); - -/** - * Relocates the multiboot modules. The bootloader loads them right behind 1MiB, so we remap them - * here and write their new addresses into the multiboot structures. - */ -void pagingRelocateMultibootModules(g_page_directory pageDirectory, g_virtual_address startAt); - -/** - * Identity-maps the area from start to end to the page directory directory, using the given tableFlags and pageFlags. - * This only works while paging is disable, thus it is private for the paging initializer. - */ -void pagingIdentityMap(g_page_directory directory, uint32_t start, uint32_t end, uint32_t tableFlags, - uint32_t pageFlags); - -/** - * Maps the page at physicalAddress to the virtualAddress, using the given tableFlags and pageFlags. - * This only works while paging is disable, thus it is private for the paging initializer. - */ -void pagingMapPageToDirectory(g_page_directory directory, uint32_t virtualAddress, uint32_t physicalAddress, - uint32_t tableFlags, uint32_t pageFlags); - -#endif diff --git a/kernel/src/loader/memory/physical.cpp b/kernel/src/loader/memory/physical.cpp deleted file mode 100644 index feea00b4..00000000 --- a/kernel/src/loader/memory/physical.cpp +++ /dev/null @@ -1,163 +0,0 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * * - * Ghost, a micro-kernel based operating system for the x86 architecture * - * Copyright (C) 2015, Max Schlüssel * - * * - * This program 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. * - * * - * This program 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 this program. If not, see . * - * * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -#include "loader/memory/physical.hpp" -#include "loader/setup_information.hpp" -#include "shared/logger/logger.hpp" -#include "shared/multiboot/multiboot.hpp" -#include "shared/panic.hpp" - -uint32_t memoryPhysicalReadMemoryMap(g_address startAfter, g_address bitmapArrayStart) -{ - g_multiboot_information* multiboot = setupInformation.multibootInformation; - - if(!(multiboot->flags & G_MULTIBOOT_FLAGS_MMAP)) - panic("%! no memory map available", "mboot"); - - // Those are only used when target address is given - g_bitmap_header* currentBitmap = (g_bitmap_header*) bitmapArrayStart; - g_bitmap_header* previousBitmap = nullptr; - - uint32_t totalBitmapsSize = 0; - - g_address mapListEnd = ((g_address) multiboot->memoryMap) + multiboot->memoryMapLength; - for(g_multiboot_mmap* map = multiboot->memoryMap; - (g_address) map < mapListEnd; - map = (g_multiboot_mmap*) ((g_address) map + map->size + sizeof(uint32_t))) - { - if(map->type != G_MULTIBOOT_MMAP_TYPE_FREE) - continue; - - // Make sure start and end are in allowed range - uint64_t start = map->baseAddress; - uint64_t end = start + map->length; - - if(start > G_ADDRESS_MAX) - continue; - - if(start < startAfter) - start = startAfter; - - if(end > G_ADDRESS_MAX) - end = G_ADDRESS_MAX; - - start = G_PAGE_ALIGN_UP(start); - end = G_PAGE_ALIGN_DOWN(end); - - if(start >= end) - continue; - - // Artificially split the current range into multiple bitmaps to improve multi-core performance - g_address splitStart = start; - while(splitStart < end) - { - g_address splitEnd = splitStart + G_BITMAP_MAX_RANGE; - if(splitEnd > end) - splitEnd = end; - - // Calculate required size of current bitmap - uint32_t entryCount = ((splitEnd - splitStart) / G_PAGE_SIZE) / G_BITMAP_PAGES_PER_ENTRY; - uint32_t currentBitmapSize = sizeof(g_bitmap_header) + (entryCount * sizeof(g_bitmap_entry)); - totalBitmapsSize += currentBitmapSize; - - // Write bitmap if it's not a dry-run - if(bitmapArrayStart) - { - currentBitmap->baseAddress = splitStart; - currentBitmap->entryCount = entryCount; - currentBitmap->hasNext = false; - currentBitmap->firstFree = 0; - g_bitmap_entry* currentBitmapEntries = G_BITMAP_ENTRIES(currentBitmap); - for(uint32_t i = 0; i < currentBitmap->entryCount; i++) - { - currentBitmapEntries[i] = 0; - } - - if(previousBitmap) - previousBitmap->hasNext = true; - - logDebug("%! bitmap: %x, base: %x, entries: %i", "physical", currentBitmap, currentBitmap->baseAddress, currentBitmap->entryCount); - - previousBitmap = currentBitmap; - currentBitmap = G_BITMAP_NEXT_UNCHECKED(currentBitmap); - } - - splitStart += G_BITMAP_MAX_RANGE; - } - } - - return totalBitmapsSize; -} - -g_address memoryPhysicalAllocateInitial(g_address startAfter, int pages) -{ - auto multiboot = setupInformation.multibootInformation; - - for(g_address start = startAfter; - start < G_ADDRESS_MAX; - start += G_PAGE_SIZE) - { - g_address end = start + pages * G_PAGE_SIZE; - - // Make sure none of the pages is within a multiboot module - bool inModule = false; - for(g_address page = start; page < end; page += G_PAGE_SIZE) - { - for(int i = 0; i < (int) multiboot->modulesCount; i++) - { - g_multiboot_module* module = &multiboot->modules[i]; - if(page >= G_PAGE_ALIGN_DOWN(module->moduleStart) && - page < G_PAGE_ALIGN_UP(module->moduleEnd)) - { - inModule = true; - start = G_PAGE_ALIGN_UP(module->moduleEnd); - break; - } - } - } - if(inModule) - { - continue; - } - - // Make sure the allocated range is free within the memory map - bool valid = false; - g_address mapEnd = ((g_address) multiboot->memoryMap) + multiboot->memoryMapLength; - for(g_multiboot_mmap* map = multiboot->memoryMap; - (g_address) map < mapEnd; - map = (g_multiboot_mmap*) ((g_address) map + map->size + sizeof(uint32_t))) - { - if(map->type == G_MULTIBOOT_MMAP_TYPE_FREE && start >= map->baseAddress && end < map->baseAddress + map->length) - { - valid = true; - break; - } - } - if(!valid) - { - logWarn("%! tried to allocate a physical range at %x which was not within allowed ranges", "physical", start); - continue; - } - - return start; - } - - panic("%! failed to allocate physical memory in early stage", "loader"); -} diff --git a/kernel/src/loader/memory/physical.hpp b/kernel/src/loader/memory/physical.hpp deleted file mode 100644 index 566942cc..00000000 --- a/kernel/src/loader/memory/physical.hpp +++ /dev/null @@ -1,44 +0,0 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * * - * Ghost, a micro-kernel based operating system for the x86 architecture * - * Copyright (C) 2015, Max Schlüssel * - * * - * This program 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. * - * * - * This program 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 this program. If not, see . * - * * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -#ifndef __LOADER_PHYSICALALLOCATOR__ -#define __LOADER_PHYSICALALLOCATOR__ - -#include "shared/memory/bitmap.hpp" -#include - -/** - * Reads the GRUB memory map to find out which memory areas are usable and free. - * Everything after "startAfter" is excluded. - * - * This function is run twice; the first time, the memory map is interpreted to - * determine how large all bitmaps in the bitmap array will be. In the second - * run, a sufficient physical space was allocated and the bitmaps are written - * to the given address. - */ -uint32_t memoryPhysicalReadMemoryMap(g_address startAfter, g_address bitmapArrayStart); - -/** - * Before the bitmap allocator is initialized, this simple allocation function - * searches and allocates free pages, starting after the given address. - */ -g_address memoryPhysicalAllocateInitial(g_address startAfter, int pages); - -#endif diff --git a/kernel/src/loader/setup_information.cpp b/kernel/src/loader/setup_information.cpp deleted file mode 100644 index a04f36ef..00000000 --- a/kernel/src/loader/setup_information.cpp +++ /dev/null @@ -1,23 +0,0 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * * - * Ghost, a micro-kernel based operating system for the x86 architecture * - * Copyright (C) 2015, Max Schlüssel * - * * - * This program 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. * - * * - * This program 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 this program. If not, see . * - * * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -#include "loader/setup_information.hpp" - -g_setup_information setupInformation; diff --git a/kernel/src/loader/system/mutex.cpp b/kernel/src/loader/system/mutex.cpp deleted file mode 100644 index ea42dcd3..00000000 --- a/kernel/src/loader/system/mutex.cpp +++ /dev/null @@ -1,48 +0,0 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * * - * Ghost, a micro-kernel based operating system for the x86 architecture * - * Copyright (C) 2015, Max Schlüssel * - * * - * This program 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. * - * * - * This program 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 this program. If not, see . * - * * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -#include "shared/system/mutex.hpp" - -/** - * This implementation exists only because the loader uses code that relies on - * these functions being available, but in the context of the loader mutexes - * are not required. - */ - -void mutexInitializeTask(g_mutex* mutex, const char* location) -{ -} - -void mutexInitializeGlobal(g_mutex* mutex, const char* location) -{ -} - -void mutexAcquire(g_mutex* mutex) -{ -} - -void mutexRelease(g_mutex* mutex) -{ -} - -bool mutexIsAcquired(g_mutex* mutex) -{ - return false; -} diff --git a/kernel/src/shared/multiboot/multiboot.cpp b/kernel/src/shared/boot/limine.cpp similarity index 78% rename from kernel/src/shared/multiboot/multiboot.cpp rename to kernel/src/shared/boot/limine.cpp index 97b8f6b2..5a197ec6 100644 --- a/kernel/src/shared/multiboot/multiboot.cpp +++ b/kernel/src/shared/boot/limine.cpp @@ -18,25 +18,28 @@ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ -#include "shared/multiboot/multiboot.hpp" -#include "shared/logger/logger.hpp" +#include "shared/boot/limine.hpp" #include "shared/utils/string.hpp" -g_multiboot_module* multibootFindModule(g_multiboot_information* info, const char* path) -{ - logDebug("%! searching for module: %s", "mbutil", path); - - uint32_t moduleCount = info->modulesCount; +static limine_framebuffer* fb = nullptr; - for(uint32_t i = 0; i < moduleCount; i++) +limine_file* limineFindModule(limine_module_response* info, const char* path) +{ + for(uint64_t i = 0; i < info->module_count; i++) { - g_multiboot_module* module = &info->modules[i]; - logDebug("%# module: %s", module->path); - - // Check modules path + auto module = info->modules[i]; if(stringEquals(module->path, path)) return module; } + return nullptr; +} - return 0; +void limineStoreFramebuffer(limine_framebuffer* framebuffer) +{ + fb = framebuffer; +} + +limine_framebuffer* limineGetFramebuffer() +{ + return fb; } diff --git a/kernel/src/shared/logger/logger.cpp b/kernel/src/shared/logger/logger.cpp index 4f82c370..975937c5 100644 --- a/kernel/src/shared/logger/logger.cpp +++ b/kernel/src/shared/logger/logger.cpp @@ -45,7 +45,7 @@ void loggerPrintFormatted(const char* message_const, va_list valist) { char* message = (char*) message_const; - uint16_t headerColor = 0x07; + uint16_t headerColor = 0xFF888888; int max = 500; while(*message && --max) @@ -59,41 +59,48 @@ void loggerPrintFormatted(const char* message_const, va_list valist) ++message; if(*message == 'i') - { // integer - int32_t val = va_arg(valist, int32_t); - loggerPrintNumber(val, 10); + { + // integer + int64_t val = va_arg(valist, int64_t); + loggerPrintNumber(val, 10, false); } else if(*message == 'h' || *message == 'x') - { // positive hex number - uint32_t val = va_arg(valist, uint32_t); + { + // positive hex number + uint64_t val = va_arg(valist, uint64_t); loggerPrintPlain("0x"); - loggerPrintNumber(val, 16); + loggerPrintNumber(val, 16, *message == 'h'); } else if(*message == 'b') - { // boolean - uint32_t val = va_arg(valist, uint32_t); + { + // boolean + int64_t val = va_arg(valist, int64_t); loggerPrintPlain("0b"); - loggerPrintNumber(val, 2); + loggerPrintNumber(val, 2, false); } else if(*message == 'c') - { // char + { + // char int val = va_arg(valist, int); loggerPrintCharacter((char) val); } else if(*message == 's') - { // string + { + // string char* val = va_arg(valist, char*); loggerPrintPlain(val); } else if(*message == '#') - { // indented printing + { + // indented printing for(uint32_t i = 0; i < LOGGER_HEADER_WIDTH + 3; i++) { loggerPrintCharacter(' '); } } else if(*message == '!') - { // indented header printing + { + // indented header printing char* val = va_arg(valist, char*); uint32_t headerlen = stringLength(val); @@ -105,24 +112,27 @@ void loggerPrintFormatted(const char* message_const, va_list valist) } } + auto lastColor = consoleVideoGetColor(); consoleVideoSetColor(headerColor); loggerPrintPlain(val); - consoleVideoSetColor(0x0F); + consoleVideoSetColor(lastColor); loggerPrintCharacter(' '); } else if(*message == '%') - { // escaped % + { + // escaped % loggerPrintCharacter(*message); } else if(*message == '*') - { // header color change + { + // header color change headerColor = (uint16_t) (va_arg(valist, int)); } ++message; } } -void loggerPrintNumber(uint32_t number, uint16_t base) +void loggerPrintNumber(uint64_t number, uint16_t base, bool shortened) { // Remember if negative @@ -150,9 +160,9 @@ void loggerPrintNumber(uint32_t number, uint16_t base) } while(number); // If base is 16, write 0's until 8 - if(base == 16) + if(!shortened && base == 16) { - while(len < 8) + while(len < 16) { *cbufp++ = '0'; ++len; diff --git a/kernel/src/shared/memory/bitmap_page_allocator.cpp b/kernel/src/shared/memory/bitmap_page_allocator.cpp index 9af3de4c..204441a1 100644 --- a/kernel/src/shared/memory/bitmap_page_allocator.cpp +++ b/kernel/src/shared/memory/bitmap_page_allocator.cpp @@ -1,7 +1,7 @@ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Ghost, a micro-kernel based operating system for the x86 architecture * - * Copyright (C) 2015, Max Schlüssel * + * Copyright (C) 2025, Max Schlüssel * * * * This program is free software: you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * @@ -20,117 +20,204 @@ #include "shared/memory/bitmap_page_allocator.hpp" #include "shared/logger/logger.hpp" +#include "shared/memory/constants.hpp" +#include "shared/system/mutex.hpp" +#include "shared/panic.hpp" -void bitmapPageAllocatorFastBufferInitialize(g_bitmap_page_allocator* allocator); -bool bitmapPageAllocatorFastBufferFree(g_bitmap_page_allocator* allocator, g_physical_address address); -g_physical_address bitmapPageAllocatorFastBufferAllocate(g_bitmap_page_allocator* allocator); +void _bitmapPageAllocatorFastBufferInitialize(g_bitmap_page_allocator* allocator); +bool _bitmapPageAllocatorFastBufferFree(g_bitmap_page_allocator* allocator, g_physical_address address); +g_physical_address _bitmapPageAllocatorFastBufferAllocate(g_bitmap_page_allocator* allocator); +g_physical_address _bitmapPageAllocatorEarlyAllocate(limine_memmap_response* memoryMap, int pages); +g_bitmap_header* _bitmapPageAllocatorInitializeBitmap(g_physical_address addr); -void bitmapPageAllocatorInitialize(g_bitmap_page_allocator* allocator, g_bitmap_header* bitmapArray) +void bitmapPageAllocatorInitialize(g_bitmap_page_allocator* allocator, limine_memmap_response* memoryMap) { - allocator->bitmapArray = bitmapArray; + mutexInitializeGlobal(&allocator->lock); allocator->freePageCount = 0; - g_bitmap_header* bitmap = bitmapArray; - while(bitmap) + // Allocate top-level index page that keeps pointers to bitmaps + g_physical_address indexPagePhys = _bitmapPageAllocatorEarlyAllocate(memoryMap, 1); + allocator->indexPage = (g_bitmap_index_page_header*) G_MEM_PHYS_TO_VIRT(indexPagePhys); + for(size_t i = 0; i < G_BITMAP_INDEX_MAX_ENTRIES; i++) + allocator->indexPage->entries[i] = nullptr; + + int indexEntry = 0; + for(int i = 0; i < memoryMap->entry_count; i++) { - mutexInitializeGlobal(&bitmap->lock); - allocator->freePageCount += bitmap->entryCount * G_BITMAP_PAGES_PER_ENTRY; - bitmap = G_BITMAP_NEXT(bitmap); + auto entry = memoryMap->entries[i]; + if(entry->type != LIMINE_MEMMAP_USABLE) + continue; + + g_physical_address currentPage = entry->base; + + // At the start of every free area, create a bitmap + auto bitmap = _bitmapPageAllocatorInitializeBitmap(currentPage); + allocator->indexPage->entries[indexEntry++] = bitmap; + currentPage += G_PAGE_SIZE; + + while(currentPage < entry->base + entry->length) + { + size_t entryIndex = (currentPage - bitmap->base) / G_PAGE_SIZE; + size_t bitmapIndex = entryIndex / G_BITMAP_BITS_PER_ENTRY; + size_t bitmapBit = entryIndex % G_BITMAP_BITS_PER_ENTRY; + bitmap->entries[bitmapIndex] |= (1 << bitmapBit); + allocator->freePageCount++; + + // Go to next page + currentPage += G_PAGE_SIZE; + bitmap->end = currentPage; + + // Check if we have reached the end of this bitmap + bool bitmapFull = entryIndex == G_BITMAP_TOTAL_BITS - 1; + if(bitmapFull) + { + bool remainingSpaceSufficient = currentPage + G_PAGE_SIZE < entry->base + entry->length; + if(!remainingSpaceSufficient) + break; + + // Create the next bitmap at the next free page + bitmap = _bitmapPageAllocatorInitializeBitmap(currentPage); + allocator->indexPage->entries[indexEntry++] = bitmap; + currentPage += G_PAGE_SIZE; + + // Currently only one index page is supported + if(indexEntry >= G_BITMAP_INDEX_MAX_ENTRIES) + goto stopFilling; + } + } } - bitmapPageAllocatorFastBufferInitialize(allocator); +stopFilling: + _bitmapPageAllocatorFastBufferInitialize(allocator); } +g_bitmap_header* _bitmapPageAllocatorInitializeBitmap(g_physical_address addrPhys) +{ + auto bitmap = (g_bitmap_header*) G_MEM_PHYS_TO_VIRT(addrPhys); + + bitmap->base = addrPhys + G_PAGE_SIZE; + bitmap->end = addrPhys + G_PAGE_SIZE; + mutexInitializeGlobal(&bitmap->lock); + + for(size_t entry = 0; entry < G_BITMAP_MAX_ENTRIES; entry++) + bitmap->entries[entry] = 0; -void bitmapPageAllocatorRelocate(g_bitmap_page_allocator* allocator, g_virtual_address newBitmapArray) + return bitmap; +} + + +/** + * Early allocation function that modifies the memory map to simply cut off the + * requested amount of pages from one of the usable areas. Does not use the + * lower memory area. + */ +g_physical_address _bitmapPageAllocatorEarlyAllocate(limine_memmap_response* memoryMap, int pages) { - allocator->bitmapArray = (g_bitmap_header*) newBitmapArray; + size_t allocatedSize = pages * G_PAGE_SIZE; + + for(int i = 0; i < memoryMap->entry_count; i++) + { + auto entry = memoryMap->entries[i]; + if(entry->type != LIMINE_MEMMAP_USABLE) + continue; + + if(entry->base >= G_MEM_LOWER_END && entry->length > allocatedSize) + { + g_physical_address address = entry->base + entry->length - allocatedSize; + entry->length -= allocatedSize; + return address; + } + } + + panic("%! failed to allocate %i physical pages", "bitmap", pages); } + void bitmapPageAllocatorMarkFree(g_bitmap_page_allocator* allocator, g_physical_address address) { - if(bitmapPageAllocatorFastBufferFree(allocator, address)) + if(G_PAGE_ALIGN_DOWN(address) != address) + panic("%! attempted to free unaligned physical address %x", "bitmap", address); + + if(_bitmapPageAllocatorFastBufferFree(allocator, address)) return; - bool freed = false; + bool success = false; - g_bitmap_header* bitmap = allocator->bitmapArray; - while(bitmap) + for(size_t i = 0; i < G_BITMAP_INDEX_MAX_ENTRIES; i++) { - mutexAcquire(&bitmap->lock); + g_bitmap_header* bitmap = allocator->indexPage->entries[i]; + if(!bitmap) + break; - g_address endAddress = bitmap->baseAddress + (bitmap->entryCount * G_BITMAP_PAGES_PER_ENTRY) * G_PAGE_SIZE; - if(address >= bitmap->baseAddress && address < endAddress) + // TODO: Try acquire would be cool here + mutexAcquire(&bitmap->lock); + if(address >= bitmap->base && address < bitmap->end) { - g_offset offset = address - bitmap->baseAddress; + size_t totalBitIndex = (address - bitmap->base) / G_PAGE_SIZE; + size_t bitmapIndex = totalBitIndex / G_BITMAP_BITS_PER_ENTRY; + size_t bitmapBit = totalBitIndex % G_BITMAP_BITS_PER_ENTRY; + bitmap->entries[bitmapIndex] &= ~(1ULL << bitmapBit); - uint32_t index = G_OFFSET_TO_BITMAP_INDEX(offset); - uint32_t bit = G_OFFSET_TO_BITMAP_BIT(offset); - G_BITMAP_UNSET(bitmap, index, bit); + mutexAcquire(&allocator->lock); + allocator->freePageCount++; + mutexRelease(&allocator->lock); - if(index < bitmap->firstFree) - bitmap->firstFree = index; - - ++allocator->freePageCount; - - freed = true; + success = true; } - mutexRelease(&bitmap->lock); - if(freed) + if(success) break; - - bitmap = G_BITMAP_NEXT(bitmap); } - if(!freed) + if(!success) logWarn("%! failed to free physical address %x", "bitmap", address); } g_physical_address bitmapPageAllocatorAllocate(g_bitmap_page_allocator* allocator) { - g_physical_address addressFromFB = bitmapPageAllocatorFastBufferAllocate(allocator); + g_physical_address addressFromFB = _bitmapPageAllocatorFastBufferAllocate(allocator); if(addressFromFB) return addressFromFB; - g_bitmap_header* bitmap = allocator->bitmapArray; - while(bitmap) + for(size_t bitmapIndex = 0; bitmapIndex < G_BITMAP_INDEX_MAX_ENTRIES; bitmapIndex++) { - g_physical_address result = 0; - mutexAcquire(&bitmap->lock); + auto bitmap = allocator->indexPage->entries[bitmapIndex]; + if(!bitmap) + break; - for(uint32_t i = bitmap->firstFree; i < bitmap->entryCount; i++) + mutexAcquire(&bitmap->lock); + g_physical_address result = 0; + for(size_t entryIndex = 0; entryIndex < G_BITMAP_MAX_ENTRIES; entryIndex++) { - if(G_BITMAP_ENTRIES(bitmap)[i] == G_BITMAP_ENTRY_FULL) + auto entry = bitmap->entries[entryIndex]; + if(entry == 0) continue; - for(uint32_t b = 0; b < G_BITMAP_PAGES_PER_ENTRY; b++) + for(int bit = 0; bit < sizeof(entry) * 8; bit++) { - if(G_BITMAP_IS_SET(bitmap, i, b)) - continue; - - G_BITMAP_SET(bitmap, i, b); - --allocator->freePageCount; - - result = bitmap->baseAddress + G_BITMAP_TO_OFFSET(i, b); - break; + if(entry & (1ULL << bit)) + { + bitmap->entries[entryIndex] &= ~(1ULL << bit); + size_t totalBitIndex = entryIndex * G_BITMAP_BITS_PER_ENTRY + bit; + + mutexAcquire(&allocator->lock); + allocator->freePageCount--; + mutexRelease(&allocator->lock); + + result = bitmap->base + totalBitIndex * G_PAGE_SIZE; + goto allocated; + } } - - if(result) - break; } - + allocated: mutexRelease(&bitmap->lock); - if(result) + if(result > 0) return result; - - bitmap = G_BITMAP_NEXT(bitmap); } - logWarn("%! failed to allocate physical page", "bitmap"); - return 0; + panic("%! failed to allocate physical memory", "bitmap"); } /** @@ -138,7 +225,7 @@ g_physical_address bitmapPageAllocatorAllocate(g_bitmap_page_allocator* allocato * * @param allocator */ -void bitmapPageAllocatorFastBufferInitialize(g_bitmap_page_allocator* allocator) +void _bitmapPageAllocatorFastBufferInitialize(g_bitmap_page_allocator* allocator) { mutexInitializeGlobal(&allocator->fastBuffer.lock); for(g_physical_address& cell: allocator->fastBuffer.buffer) @@ -148,7 +235,7 @@ void bitmapPageAllocatorFastBufferInitialize(g_bitmap_page_allocator* allocator) allocator->fastBuffer.size = 0; } -bool bitmapPageAllocatorFastBufferFree(g_bitmap_page_allocator* allocator, g_physical_address address) +bool _bitmapPageAllocatorFastBufferFree(g_bitmap_page_allocator* allocator, g_physical_address address) { bool freed = false; @@ -160,10 +247,14 @@ bool bitmapPageAllocatorFastBufferFree(g_bitmap_page_allocator* allocator, g_phy } mutexRelease(&allocator->fastBuffer.lock); + mutexAcquire(&allocator->lock); + allocator->freePageCount++; + mutexRelease(&allocator->lock); + return freed; } -g_physical_address bitmapPageAllocatorFastBufferAllocate(g_bitmap_page_allocator* allocator) +g_physical_address _bitmapPageAllocatorFastBufferAllocate(g_bitmap_page_allocator* allocator) { g_physical_address address = 0; @@ -174,5 +265,9 @@ g_physical_address bitmapPageAllocatorFastBufferAllocate(g_bitmap_page_allocator } mutexRelease(&allocator->fastBuffer.lock); + mutexAcquire(&allocator->lock); + allocator->freePageCount--; + mutexRelease(&allocator->lock); + return address; } diff --git a/kernel/src/shared/memory/gdt_mounter.asm b/kernel/src/shared/memory/gdt_mounter.asm deleted file mode 100644 index ba327da0..00000000 --- a/kernel/src/shared/memory/gdt_mounter.asm +++ /dev/null @@ -1,78 +0,0 @@ -;* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * -;* * -;* Ghost, a micro-kernel based operating system for the x86 architecture * -;* Copyright (C) 2015, Max Schlüssel * -;* * -;* This program 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. * -;* * -;* This program 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 this program. If not, see . * -;* * -;* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - - -BITS 32 - -global _loadGdt -global _loadTss - -; -; void _loadGdt(uint32_t gdtPointerAddress) -; -; Mounts the global descriptor table -; and does a far jump back to the code -; -; Parameters: -; gdtPointerAddress ebp + 8 -; -_loadGdt: - ; Prologue - push ebp - mov ebp, esp - - ; Load GDT - mov eax, [ebp + 8] - lgdt [eax] - ; Switch to kernel data segment - mov ax, 0x10 - mov ds, ax - mov es, ax - mov fs, ax - mov gs, ax - mov ss, ax - - ; Far jump into kernel code segment - jmp 0x08:flush - -flush: - ; Epilogue - pop ebp - ret - -; -; void _loadTss(uint16_t tssDescriptorIndex) -; -; Loads the TSS -; -; Parameters: -; tssDescriptorIndex ebp + 8 -; -_loadTss: - ; Prologue - push ebp - mov ebp, esp - - mov ax, [ebp + 8] - ltr ax - - ; Epilogue - pop ebp - ret diff --git a/kernel/src/shared/memory/memory.cpp b/kernel/src/shared/memory/memory.cpp index 42a6087c..f81ed387 100644 --- a/kernel/src/shared/memory/memory.cpp +++ b/kernel/src/shared/memory/memory.cpp @@ -47,6 +47,8 @@ void* memoryCopy(void* target, const void* source, int32_t size) auto targetPtr = (uint8_t*) target; auto sourcePtr = (const uint8_t*) source; + // TODO qword copying + while(size >= 4) { *(uint32_t*) targetPtr = *(const uint32_t*) sourcePtr; diff --git a/kernel/src/shared/memory/paging.cpp b/kernel/src/shared/memory/paging.cpp index b1357950..e35cda3e 100644 --- a/kernel/src/shared/memory/paging.cpp +++ b/kernel/src/shared/memory/paging.cpp @@ -19,75 +19,128 @@ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #include "shared/memory/paging.hpp" +#include "shared/logger/logger.hpp" #include "shared/memory/constants.hpp" #include "shared/memory/memory.hpp" #include "shared/panic.hpp" -#include "shared/logger/logger.hpp" +// Switches to a new paging structure (by loading CR3) void pagingSwitchToSpace(g_physical_address dir) { - asm volatile("mov %0, %%cr3" ::"b"(dir)); + asm volatile("mov %0, %%cr3" : : "b"(dir)); +} + +bool pagingMapPage(g_virtual_address virt, g_physical_address phys, + uint64_t tableFlags, uint64_t ptFlags, + bool allowOverride) +{ + return pagingMapPage(virt, phys, tableFlags, tableFlags, tableFlags, ptFlags, allowOverride); } -bool pagingMapPage(g_virtual_address virt, g_physical_address phys, uint32_t tableFlags, uint32_t pageFlags, bool allowOverride) +bool pagingMapPage(g_virtual_address virt, g_physical_address phys, + uint64_t pdptFlags, uint64_t pdFlags, + uint64_t ptFlags, uint64_t pageFlags, + bool allowOverride) { if((virt & G_PAGE_ALIGN_MASK) || (phys & G_PAGE_ALIGN_MASK)) panic("%! tried to map unaligned addresses: %h -> %h", "paging", virt, phys); - uint32_t ti = G_TABLE_IN_DIRECTORY_INDEX(virt); - uint32_t pi = G_PAGE_IN_TABLE_INDEX(virt); + auto pml4 = (volatile uint64_t*) G_MEM_PHYS_TO_VIRT(pagingGetCurrentSpace()); - g_page_directory directory = (g_page_directory) G_RECURSIVE_PAGE_DIRECTORY_ADDRESS; - g_page_table table = ((g_page_table) G_RECURSIVE_PAGE_DIRECTORY_AREA) + (0x400 * ti); - if(directory[ti] == 0) + // Get PDPT from PML4 + uint64_t pml4Index = G_PML4_INDEX(virt); + volatile uint64_t* pdpt; + if(!pml4[pml4Index]) { - g_physical_address newTablePage = bitmapPageAllocatorAllocate(&memoryPhysicalAllocator); - if(!newTablePage) - panic("%! no pages left for mapping", "paging"); + g_physical_address newPdpt = bitmapPageAllocatorAllocate(&memoryPhysicalAllocator); + pml4[pml4Index] = newPdpt | pdptFlags; - directory[ti] = newTablePage | tableFlags; - for(uint32_t i = 0; i < 1024; i++) - table[i] = 0; + pdpt = (volatile uint64_t*) G_MEM_PHYS_TO_VIRT(newPdpt); + for(int i = 0; i < 512; i++) + pdpt[i] = 0; } - else if((tableFlags & G_PAGE_TABLE_USERSPACE) && ((directory[ti] & G_PAGE_ALIGN_MASK) & G_PAGE_TABLE_USERSPACE) == 0) + else { - panic("%! tried to map user page in kernel space table, virt %h", "paging", virt); + pdpt = (volatile uint64_t*) G_MEM_PHYS_TO_VIRT(pml4[pml4Index] & ~G_PAGE_ALIGN_MASK); } - if(table[pi] == 0 || allowOverride) + // Get PD from PDPT + uint64_t pdptIndex = G_PDPT_INDEX(virt); + volatile uint64_t* pd; + if(!pdpt[pdptIndex]) { - table[pi] = phys | pageFlags; + g_physical_address newPd = bitmapPageAllocatorAllocate(&memoryPhysicalAllocator); + pdpt[pdptIndex] = newPd | pdFlags; + + pd = (volatile uint64_t*) G_MEM_PHYS_TO_VIRT(newPd); + for(int i = 0; i < 512; i++) + pd[i] = 0; + } + else + { + pd = (volatile uint64_t*) G_MEM_PHYS_TO_VIRT(pdpt[pdptIndex] & ~G_PAGE_ALIGN_MASK); + } + + // Get PT from PD + uint64_t pdIndex = G_PD_INDEX(virt); + volatile uint64_t* pt; + if(!pd[pdIndex]) + { + g_physical_address newPt = bitmapPageAllocatorAllocate(&memoryPhysicalAllocator); + pd[pdIndex] = newPt | ptFlags; + + pt = (volatile uint64_t*) G_MEM_PHYS_TO_VIRT(newPt); + for(int i = 0; i < 512; i++) + pt[i] = 0; + } + else + { + pt = (volatile uint64_t*) G_MEM_PHYS_TO_VIRT(pd[pdIndex] & ~G_PAGE_ALIGN_MASK); + } + + // Write page into page table + uint64_t ptIndex = G_PT_INDEX(virt); + if(!pt[ptIndex] || allowOverride) + { + pt[ptIndex] = phys | pageFlags; pagingInvalidatePage(virt); return true; } - logInfo("%! warning: tried duplicate mapping of page %h", "paging", virt); + logInfo("%! failed to write paging entry for %x since it is already set to: %x", "paging", virt, pt[ptIndex]); return false; } void pagingUnmapPage(g_virtual_address virt) { - uint32_t ti = G_TABLE_IN_DIRECTORY_INDEX(virt); - uint32_t pi = G_PAGE_IN_TABLE_INDEX(virt); + auto pml4 = (volatile uint64_t*) G_MEM_PHYS_TO_VIRT(pagingGetCurrentSpace()); + uint64_t pml4Index = G_PML4_INDEX(virt); + if(!pml4[pml4Index]) + return; - g_page_directory directory = (g_page_directory) G_RECURSIVE_PAGE_DIRECTORY_ADDRESS; - g_page_table table = G_RECURSIVE_PAGE_TABLE(ti); + auto pdpt = (volatile uint64_t*) G_MEM_PHYS_TO_VIRT(pml4[pml4Index] & ~G_PAGE_ALIGN_MASK); + uint64_t pdptIndex = G_PDPT_INDEX(virt); + if(!pdpt[pdptIndex]) + return; - if(!directory[ti]) + auto pd = (volatile uint64_t*) G_MEM_PHYS_TO_VIRT(pdpt[pdptIndex] & ~G_PAGE_ALIGN_MASK); + uint64_t pdIndex = G_PD_INDEX(virt); + if(!pd[pdIndex]) return; - if(!table[pi]) + auto pt = (volatile uint64_t*) G_MEM_PHYS_TO_VIRT(pd[pdIndex] & ~G_PAGE_ALIGN_MASK); + uint64_t ptIndex = G_PT_INDEX(virt); + if(!pt[ptIndex]) return; - table[pi] = 0; + pt[ptIndex] = 0; pagingInvalidatePage(virt); } g_physical_address pagingGetCurrentSpace() { - uint32_t directory; - asm volatile("mov %%cr3, %0" - : "=r"(directory)); + g_physical_address directory; + asm volatile("mov %%cr3, %0" : "=r"(directory)); return directory; } diff --git a/kernel/src/shared/system/serial_port.cpp b/kernel/src/shared/system/serial_port.cpp index c42b508d..d004b520 100644 --- a/kernel/src/shared/system/serial_port.cpp +++ b/kernel/src/shared/system/serial_port.cpp @@ -21,6 +21,19 @@ #include "shared/system/serial_port.hpp" #include "shared/system/io_port.hpp" +// Check if the COM1 port is available +bool serialPortIsAvailable(uint16_t port) +{ + // Try writing to the Line Control Register (LCR) + ioPortWriteByte(port + 3, 0x80); // Set DLAB (Divisor Latch Access Bit) + + // Read back the value + uint8_t lcr = ioPortReadByte(port + 3); + + // If we read back the same value, the port is likely present + return lcr == 0x80; +} + void serialPortInitialize(uint16_t port, bool interruptsEnabled) { // Disable the interrupts @@ -42,7 +55,7 @@ void serialPortInitialize(uint16_t port, bool interruptsEnabled) // 5: 0 ^ ioPortWriteByte(port + G_SERIAL_PORT_OFFSET_LINE_CONTROL, 0x03); - if (interruptsEnabled) + if(interruptsEnabled) { // Enable FIFO ioPortWriteByte(port + G_SERIAL_PORT_OFFSET_INT_FIFO, 0xC7); @@ -70,7 +83,7 @@ void serialPortInitialize(uint16_t port, bool interruptsEnabled) uint8_t serialPortRead(uint16_t port) { // Wait byte available - while ((ioPortReadByte(port + G_SERIAL_PORT_OFFSET_LINE_STATUS) & 0x01) == 0) + while((ioPortReadByte(port + G_SERIAL_PORT_OFFSET_LINE_STATUS) & 0x01) == 0) { } @@ -81,11 +94,10 @@ uint8_t serialPortRead(uint16_t port) void serialPortWrite(uint16_t port, uint8_t value) { // Wait until ready - while ((ioPortReadByte(port + G_SERIAL_PORT_OFFSET_LINE_STATUS) & 0x20) == 0) + while((ioPortReadByte(port + G_SERIAL_PORT_OFFSET_LINE_STATUS) & 0x20) == 0) { } // Write byte ioPortWriteByte(port + G_SERIAL_PORT_OFFSET_DATA_REGISTER, value); } - diff --git a/kernel/src/loader/setup_information.hpp b/kernel/src/shared/video/bitmap_font.cpp similarity index 79% rename from kernel/src/loader/setup_information.hpp rename to kernel/src/shared/video/bitmap_font.cpp index 7db0be6d..6ab0727e 100644 --- a/kernel/src/loader/setup_information.hpp +++ b/kernel/src/shared/video/bitmap_font.cpp @@ -1,5 +1,5 @@ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * * +* * * Ghost, a micro-kernel based operating system for the x86 architecture * * Copyright (C) 2015, Max Schlüssel * * * @@ -18,11 +18,13 @@ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ -#ifndef __LOADER_SETUPINFORMATION__ -#define __LOADER_SETUPINFORMATION__ - -#include "shared/setup_information.hpp" - -extern g_setup_information setupInformation; +#include "shared/video/bitmap_font.hpp" +#include "shared/logger/logger.hpp" -#endif +uint8_t* bitmapFontGetChar(char c) +{ + uint16_t offset = c - bitmapFontAsciiOffset; + if(offset >= bitmapFontCharCount) + return nullptr; + return bitmapFontCharSet[offset]; +} diff --git a/kernel/src/shared/video/bitmap_font_data.cpp b/kernel/src/shared/video/bitmap_font_data.cpp new file mode 100644 index 00000000..40263c6e --- /dev/null +++ b/kernel/src/shared/video/bitmap_font_data.cpp @@ -0,0 +1,2872 @@ +/* + * NOTE: This file is generated by the bitmap-font tool, use it to update it. + */ +#include + +uint8_t bitmapFontCharWidth = 10; +uint8_t bitmapFontCharHeight = 19; +uint8_t bitmapFontCharCount = 130; +uint8_t bitmapFontAsciiOffset = 0; + +uint8_t bitmapFontCharSet[130][190] = { + + // Char 0 +{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 1, 0, 0, 1, 0, 0, 0, // +0, 0, 0, 1, 1, 0, 1, 0, 0, 0, // +0, 0, 0, 1, 0, 1, 1, 0, 0, 0, // +0, 0, 0, 1, 0, 0, 1, 0, 0, 0, // +0, 0, 0, 1, 0, 0, 1, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 1, 0, 0, 1, 0, 0, 0, // +0, 0, 0, 1, 0, 0, 1, 0, 0, 0, // +0, 0, 0, 1, 0, 0, 1, 0, 0, 0, // +0, 0, 0, 1, 0, 0, 1, 0, 0, 0, // +0, 0, 0, 1, 1, 1, 1, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 1, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 1, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 1, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 1, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 1, 1, 1, 1, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +}, + + // Char 1 +{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +}, + + // Char 2 +{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +}, + + // Char 3 +{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +}, + + // Char 4 +{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +}, + + // Char 5 +{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +}, + + // Char 6 +{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +}, + + // Char 7 +{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +}, + + // Char 8 +{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +}, + + // Char 9 +{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +}, + + // Char 10 +{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +}, + + // Char 11 +{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +}, + + // Char 12 +{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +}, + + // Char 13 +{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +}, + + // Char 14 +{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +}, + + // Char 15 +{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +}, + + // Char 16 +{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +}, + + // Char 17 +{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +}, + + // Char 18 +{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +}, + + // Char 19 +{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +}, + + // Char 20 +{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +}, + + // Char 21 +{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +}, + + // Char 22 +{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +}, + + // Char 23 +{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +}, + + // Char 24 +{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +}, + + // Char 25 +{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +}, + + // Char 26 +{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +}, + + // Char 27 +{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +}, + + // Char 28 +{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +}, + + // Char 29 +{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +}, + + // Char 30 +{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +}, + + // Char 31 +{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +}, + + // Char 32 +{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +}, + + // Char 33 +{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 1, 1, 0, 0, 0, 0, // +0, 0, 0, 0, 1, 1, 0, 0, 0, 0, // +0, 0, 0, 0, 1, 1, 0, 0, 0, 0, // +0, 0, 0, 0, 1, 1, 0, 0, 0, 0, // +0, 0, 0, 0, 1, 1, 0, 0, 0, 0, // +0, 0, 0, 0, 1, 1, 0, 0, 0, 0, // +0, 0, 0, 0, 1, 1, 0, 0, 0, 0, // +0, 0, 0, 0, 1, 1, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 1, 1, 0, 0, 0, 0, // +0, 0, 0, 0, 1, 1, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +}, + + // Char 34 +{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 1, 1, 0, 1, 1, 0, 0, // +0, 0, 0, 1, 1, 0, 1, 1, 0, 0, // +0, 0, 0, 1, 1, 0, 1, 1, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +}, + + // Char 35 +{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 1, 0, 0, 1, 0, 0, 0, // +0, 0, 0, 1, 0, 0, 1, 0, 0, 0, // +0, 0, 0, 1, 0, 0, 1, 0, 0, 0, // +0, 1, 1, 1, 1, 1, 1, 1, 1, 0, // +0, 0, 0, 1, 0, 0, 1, 0, 0, 0, // +0, 0, 0, 1, 0, 0, 1, 0, 0, 0, // +0, 1, 1, 1, 1, 1, 1, 1, 1, 0, // +0, 0, 0, 1, 0, 0, 1, 0, 0, 0, // +0, 0, 0, 1, 0, 0, 1, 0, 0, 0, // +0, 0, 0, 1, 0, 0, 1, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +}, + + // Char 36 +{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 1, 1, 0, 0, 0, 0, // +0, 0, 0, 0, 1, 1, 0, 0, 0, 0, // +0, 0, 1, 1, 1, 1, 1, 0, 0, 0, // +0, 1, 1, 0, 1, 1, 0, 0, 0, 0, // +0, 1, 1, 0, 1, 1, 0, 0, 0, 0, // +0, 1, 1, 1, 1, 1, 0, 0, 0, 0, // +0, 0, 1, 1, 1, 1, 1, 0, 0, 0, // +0, 0, 0, 1, 1, 1, 1, 1, 0, 0, // +0, 0, 0, 0, 1, 1, 1, 1, 0, 0, // +0, 0, 0, 0, 1, 1, 0, 1, 0, 0, // +0, 1, 0, 1, 1, 1, 1, 1, 0, 0, // +0, 1, 1, 1, 1, 1, 1, 1, 0, 0, // +0, 0, 1, 1, 1, 1, 1, 0, 0, 0, // +0, 0, 0, 0, 1, 1, 0, 0, 0, 0, // +0, 0, 0, 0, 1, 1, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +}, + + // Char 37 +{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 1, 1, 1, 0, 0, 0, 1, 0, // +0, 0, 1, 0, 1, 0, 0, 1, 1, 0, // +0, 0, 1, 0, 1, 0, 1, 1, 0, 0, // +0, 0, 1, 1, 1, 0, 1, 1, 0, 0, // +0, 0, 0, 0, 0, 1, 1, 0, 0, 0, // +0, 0, 0, 0, 0, 1, 0, 0, 0, 0, // +0, 0, 0, 0, 1, 1, 0, 0, 0, 0, // +0, 0, 0, 1, 1, 0, 1, 1, 1, 0, // +0, 0, 0, 1, 1, 0, 1, 0, 1, 0, // +0, 0, 1, 1, 0, 0, 1, 0, 1, 0, // +0, 1, 1, 0, 0, 0, 1, 1, 1, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +}, + + // Char 38 +{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 1, 1, 1, 1, 0, 0, 0, // +0, 0, 0, 1, 1, 1, 1, 1, 0, 0, // +0, 0, 1, 1, 0, 0, 1, 1, 0, 0, // +0, 0, 1, 1, 0, 1, 1, 1, 0, 0, // +0, 0, 0, 1, 1, 1, 1, 0, 0, 0, // +0, 0, 0, 1, 1, 1, 0, 0, 1, 0, // +0, 0, 1, 1, 1, 1, 0, 1, 1, 0, // +0, 1, 1, 0, 0, 1, 1, 1, 1, 0, // +0, 1, 1, 0, 0, 0, 1, 1, 1, 0, // +0, 0, 1, 1, 0, 0, 1, 1, 1, 0, // +0, 0, 1, 1, 1, 1, 1, 1, 1, 1, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +}, + + // Char 39 +{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 1, 1, 0, 0, 0, 0, 0, // +0, 0, 0, 1, 1, 0, 0, 0, 0, 0, // +0, 0, 0, 1, 1, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 1, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +}, + + // Char 40 +{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 1, 1, 0, 0, 0, // +0, 0, 0, 0, 1, 1, 0, 0, 0, 0, // +0, 0, 0, 1, 1, 0, 0, 0, 0, 0, // +0, 0, 0, 1, 1, 0, 0, 0, 0, 0, // +0, 0, 0, 1, 0, 0, 0, 0, 0, 0, // +0, 0, 1, 1, 0, 0, 0, 0, 0, 0, // +0, 0, 1, 1, 0, 0, 0, 0, 0, 0, // +0, 0, 1, 1, 0, 0, 0, 0, 0, 0, // +0, 0, 1, 1, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 1, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 1, 1, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 1, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 1, 1, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 1, 1, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +}, + + // Char 41 +{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 1, 1, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 1, 1, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 1, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 1, 1, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 1, 1, 0, 0, // +0, 0, 0, 0, 0, 0, 1, 1, 0, 0, // +0, 0, 0, 0, 0, 0, 1, 1, 0, 0, // +0, 0, 0, 0, 0, 0, 1, 1, 0, 0, // +0, 0, 0, 0, 0, 0, 1, 1, 0, 0, // +0, 0, 0, 0, 0, 1, 1, 0, 0, 0, // +0, 0, 0, 0, 0, 1, 1, 0, 0, 0, // +0, 0, 0, 0, 1, 1, 0, 0, 0, 0, // +0, 0, 0, 0, 1, 1, 0, 0, 0, 0, // +0, 0, 0, 1, 1, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +}, + + // Char 42 +{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 1, 0, 0, 0, 0, // +0, 0, 1, 1, 0, 1, 0, 1, 1, 0, // +0, 0, 0, 1, 1, 1, 1, 1, 0, 0, // +0, 0, 0, 0, 1, 1, 1, 0, 0, 0, // +0, 0, 1, 1, 1, 1, 1, 1, 1, 0, // +0, 0, 0, 0, 1, 1, 1, 0, 0, 0, // +0, 0, 0, 1, 1, 1, 1, 1, 0, 0, // +0, 0, 1, 1, 0, 1, 0, 1, 1, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +}, + + // Char 43 +{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 1, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 1, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 1, 0, 0, 0, 0, // +0, 1, 1, 1, 1, 1, 1, 1, 1, 0, // +0, 0, 1, 1, 1, 1, 1, 1, 1, 0, // +0, 0, 0, 0, 0, 1, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 1, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 1, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +}, + + // Char 44 +{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 1, 0, 0, 0, 0, // +0, 0, 0, 0, 1, 1, 1, 0, 0, 0, // +0, 0, 0, 0, 1, 1, 1, 0, 0, 0, // +0, 0, 0, 0, 0, 1, 1, 0, 0, 0, // +0, 0, 0, 1, 1, 1, 0, 0, 0, 0, // +0, 0, 0, 1, 1, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +}, + + // Char 45 +{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 1, 1, 1, 1, 1, 0, 0, // +0, 0, 0, 1, 1, 1, 1, 1, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +}, + + // Char 46 +{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 1, 0, 0, 0, 0, 0, // +0, 0, 0, 1, 1, 1, 0, 0, 0, 0, // +0, 0, 0, 1, 1, 1, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +}, + + // Char 47 +{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 1, 1, 0, // +0, 0, 0, 0, 0, 0, 1, 1, 0, 0, // +0, 0, 0, 0, 0, 0, 1, 1, 0, 0, // +0, 0, 0, 0, 0, 0, 1, 0, 0, 0, // +0, 0, 0, 0, 0, 1, 1, 0, 0, 0, // +0, 0, 0, 0, 0, 1, 0, 0, 0, 0, // +0, 0, 0, 0, 1, 1, 0, 0, 0, 0, // +0, 0, 0, 0, 1, 1, 0, 0, 0, 0, // +0, 0, 0, 1, 1, 0, 0, 0, 0, 0, // +0, 0, 0, 1, 1, 0, 0, 0, 0, 0, // +0, 0, 0, 1, 0, 0, 0, 0, 0, 0, // +0, 0, 1, 1, 0, 0, 0, 0, 0, 0, // +0, 0, 1, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +}, + + // Char 48 +{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 1, 1, 1, 1, 1, 0, 0, // +0, 0, 1, 1, 0, 0, 1, 1, 1, 0, // +0, 0, 1, 1, 0, 0, 0, 1, 1, 0, // +0, 0, 1, 0, 0, 0, 1, 1, 1, 0, // +0, 0, 1, 0, 0, 1, 1, 1, 1, 0, // +0, 0, 1, 1, 1, 1, 0, 0, 1, 0, // +0, 0, 1, 1, 0, 0, 0, 1, 1, 0, // +0, 0, 1, 1, 0, 0, 0, 1, 1, 0, // +0, 0, 1, 1, 0, 0, 1, 1, 0, 0, // +0, 0, 0, 1, 1, 1, 1, 1, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +}, + + // Char 49 +{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 1, 1, 1, 0, 0, 0, // +0, 0, 1, 1, 1, 1, 1, 0, 0, 0, // +0, 0, 1, 1, 0, 1, 1, 0, 0, 0, // +0, 0, 0, 0, 0, 1, 1, 0, 0, 0, // +0, 0, 0, 0, 0, 1, 1, 0, 0, 0, // +0, 0, 0, 0, 0, 1, 1, 0, 0, 0, // +0, 0, 0, 0, 0, 1, 1, 0, 0, 0, // +0, 0, 0, 0, 0, 1, 1, 0, 0, 0, // +0, 0, 0, 0, 0, 1, 1, 0, 0, 0, // +0, 0, 1, 1, 1, 1, 1, 1, 1, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +}, + + // Char 50 +{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 1, 1, 1, 1, 0, 0, 0, // +0, 0, 1, 1, 1, 1, 1, 1, 0, 0, // +0, 0, 1, 1, 0, 0, 1, 1, 0, 0, // +0, 0, 0, 0, 0, 0, 1, 1, 0, 0, // +0, 0, 0, 0, 0, 0, 1, 1, 0, 0, // +0, 0, 0, 0, 0, 1, 1, 1, 0, 0, // +0, 0, 0, 0, 1, 1, 1, 0, 0, 0, // +0, 0, 0, 1, 1, 1, 0, 0, 0, 0, // +0, 0, 1, 1, 1, 0, 0, 0, 0, 0, // +0, 0, 1, 1, 1, 1, 1, 1, 1, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +}, + + // Char 51 +{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 1, 1, 1, 1, 1, 1, 0, 0, // +0, 0, 0, 0, 0, 0, 1, 1, 0, 0, // +0, 0, 0, 0, 0, 0, 1, 1, 0, 0, // +0, 0, 0, 0, 0, 0, 1, 1, 0, 0, // +0, 0, 0, 1, 1, 1, 1, 0, 0, 0, // +0, 0, 0, 0, 0, 1, 1, 1, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 1, 1, 0, // +0, 0, 0, 0, 0, 0, 0, 1, 1, 0, // +0, 0, 0, 0, 0, 0, 1, 1, 0, 0, // +0, 0, 1, 1, 1, 1, 1, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +}, + + // Char 52 +{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 1, 1, 1, 0, 0, // +0, 0, 0, 0, 1, 1, 1, 1, 0, 0, // +0, 0, 0, 0, 1, 1, 1, 1, 0, 0, // +0, 0, 0, 1, 1, 0, 1, 1, 0, 0, // +0, 0, 1, 1, 0, 0, 1, 1, 0, 0, // +0, 0, 1, 1, 0, 0, 1, 1, 0, 0, // +0, 1, 1, 1, 1, 1, 1, 1, 1, 0, // +0, 1, 1, 1, 1, 1, 1, 1, 1, 1, // +0, 0, 0, 0, 0, 0, 1, 1, 0, 0, // +0, 0, 0, 0, 0, 0, 1, 1, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +}, + + // Char 53 +{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 1, 1, 1, 1, 1, 1, 0, 0, 0, // +0, 1, 1, 0, 0, 0, 0, 0, 0, 0, // +0, 1, 1, 0, 0, 0, 0, 0, 0, 0, // +0, 1, 1, 0, 0, 0, 0, 0, 0, 0, // +0, 1, 1, 1, 1, 1, 1, 0, 0, 0, // +0, 0, 0, 0, 0, 1, 1, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 1, 1, 0, 0, // +0, 0, 0, 0, 0, 0, 1, 1, 0, 0, // +0, 0, 0, 0, 0, 1, 1, 0, 0, 0, // +0, 1, 1, 1, 1, 1, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +}, + + // Char 54 +{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 1, 1, 1, 1, 0, 0, // +0, 0, 0, 1, 1, 0, 0, 0, 0, 0, // +0, 0, 1, 1, 0, 0, 0, 0, 0, 0, // +0, 0, 1, 1, 0, 0, 0, 0, 0, 0, // +0, 0, 1, 1, 1, 1, 1, 1, 0, 0, // +0, 0, 1, 1, 0, 0, 0, 1, 1, 0, // +0, 0, 1, 1, 0, 0, 0, 1, 1, 0, // +0, 0, 1, 1, 0, 0, 0, 1, 1, 0, // +0, 0, 1, 1, 0, 0, 0, 1, 1, 0, // +0, 0, 0, 1, 1, 1, 1, 1, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +}, + + // Char 55 +{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 1, 1, 1, 1, 1, 1, 1, 0, // +0, 0, 0, 0, 0, 0, 0, 1, 1, 0, // +0, 0, 0, 0, 0, 0, 1, 1, 0, 0, // +0, 0, 0, 0, 0, 0, 1, 1, 0, 0, // +0, 0, 0, 0, 0, 1, 1, 0, 0, 0, // +0, 0, 0, 0, 0, 1, 1, 0, 0, 0, // +0, 0, 0, 0, 1, 1, 0, 0, 0, 0, // +0, 0, 0, 0, 1, 1, 0, 0, 0, 0, // +0, 0, 0, 1, 1, 0, 0, 0, 0, 0, // +0, 0, 0, 1, 1, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +}, + + // Char 56 +{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 1, 1, 1, 1, 1, 0, 0, // +0, 0, 1, 1, 0, 0, 0, 1, 1, 0, // +0, 0, 1, 1, 0, 0, 0, 1, 1, 0, // +0, 0, 1, 1, 1, 0, 1, 1, 0, 0, // +0, 0, 0, 1, 1, 1, 1, 0, 0, 0, // +0, 0, 0, 1, 1, 1, 1, 1, 0, 0, // +0, 0, 1, 1, 0, 0, 0, 1, 1, 0, // +0, 0, 1, 1, 0, 0, 0, 1, 1, 0, // +0, 0, 1, 1, 0, 0, 0, 1, 1, 0, // +0, 0, 0, 1, 1, 1, 1, 1, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +}, + + // Char 57 +{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 1, 1, 1, 1, 1, 0, 0, // +0, 0, 1, 1, 0, 0, 0, 1, 0, 0, // +0, 0, 1, 0, 0, 0, 0, 1, 1, 0, // +0, 0, 1, 0, 0, 0, 0, 1, 1, 0, // +0, 0, 1, 1, 0, 0, 0, 1, 1, 0, // +0, 0, 0, 1, 1, 1, 1, 1, 1, 0, // +0, 0, 0, 0, 0, 0, 0, 1, 1, 0, // +0, 0, 0, 0, 0, 0, 0, 1, 0, 0, // +0, 0, 0, 0, 0, 1, 1, 1, 0, 0, // +0, 0, 1, 1, 1, 1, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +}, + + // Char 58 +{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 1, 1, 1, 0, 0, 0, 0, // +0, 0, 0, 1, 1, 1, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 1, 1, 1, 0, 0, 0, 0, // +0, 0, 0, 1, 1, 1, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +}, + + // Char 59 +{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 1, 1, 0, 0, 0, 0, // +0, 0, 0, 0, 1, 1, 1, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 1, 0, 0, 0, 0, // +0, 0, 0, 0, 1, 1, 1, 0, 0, 0, // +0, 0, 0, 0, 0, 1, 1, 0, 0, 0, // +0, 0, 0, 0, 0, 1, 1, 0, 0, 0, // +0, 0, 0, 1, 1, 1, 0, 0, 0, 0, // +0, 0, 0, 1, 1, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +}, + + // Char 60 +{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 1, 0, 0, // +0, 0, 0, 0, 0, 0, 1, 1, 0, 0, // +0, 0, 0, 0, 1, 1, 1, 0, 0, 0, // +0, 0, 0, 1, 1, 1, 0, 0, 0, 0, // +0, 0, 1, 1, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 1, 1, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 1, 1, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 1, 1, 1, 0, 0, // +0, 0, 0, 0, 0, 0, 1, 1, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +}, + + // Char 61 +{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 1, 1, 1, 1, 1, 1, 1, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 1, 1, 1, 1, 1, 1, 1, 0, // +0, 0, 1, 1, 1, 1, 1, 1, 1, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +}, + + // Char 62 +{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 1, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 1, 1, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 1, 1, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 1, 1, 1, 0, 0, // +0, 0, 0, 0, 0, 0, 1, 1, 1, 0, // +0, 0, 0, 0, 0, 0, 1, 1, 0, 0, // +0, 0, 0, 0, 1, 1, 1, 0, 0, 0, // +0, 0, 0, 1, 1, 1, 0, 0, 0, 0, // +0, 0, 0, 1, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +}, + + // Char 63 +{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 1, 1, 1, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 1, 1, 1, 0, 0, 0, // +0, 0, 0, 0, 0, 1, 1, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 1, 0, 0, 0, // +0, 0, 0, 0, 0, 1, 1, 0, 0, 0, // +0, 0, 0, 1, 1, 1, 1, 0, 0, 0, // +0, 0, 0, 1, 1, 0, 0, 0, 0, 0, // +0, 0, 0, 1, 1, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 1, 1, 0, 0, 0, 0, 0, // +0, 0, 0, 1, 1, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +}, + + // Char 64 +{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 1, 1, 1, 1, 0, 0, // +0, 0, 0, 1, 1, 0, 0, 1, 1, 0, // +0, 0, 1, 1, 0, 0, 0, 0, 1, 0, // +0, 0, 1, 0, 0, 0, 0, 0, 1, 1, // +0, 1, 1, 0, 1, 1, 1, 1, 1, 1, // +0, 1, 1, 0, 1, 0, 1, 1, 1, 1, // +0, 1, 0, 1, 1, 0, 1, 0, 1, 1, // +0, 1, 0, 1, 1, 0, 1, 0, 1, 1, // +0, 1, 0, 1, 1, 0, 1, 0, 1, 0, // +0, 1, 0, 1, 1, 1, 1, 1, 1, 0, // +0, 1, 1, 0, 1, 0, 0, 1, 0, 0, // +0, 1, 1, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 1, 1, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 1, 1, 1, 1, 1, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +}, + + // Char 65 +{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 1, 1, 1, 0, 0, 0, // +0, 0, 0, 0, 1, 1, 1, 0, 0, 0, // +0, 0, 0, 1, 1, 0, 1, 0, 0, 0, // +0, 0, 0, 1, 1, 0, 1, 1, 0, 0, // +0, 0, 0, 1, 0, 0, 1, 1, 0, 0, // +0, 0, 1, 1, 0, 0, 1, 1, 0, 0, // +0, 0, 1, 1, 1, 1, 1, 1, 1, 0, // +0, 0, 1, 1, 1, 1, 1, 1, 1, 0, // +0, 1, 1, 0, 0, 0, 0, 0, 1, 0, // +0, 1, 1, 0, 0, 0, 0, 0, 1, 1, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +}, + + // Char 66 +{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 1, 1, 1, 1, 1, 1, 0, 0, // +0, 0, 1, 1, 0, 0, 1, 1, 1, 0, // +0, 0, 1, 1, 0, 0, 0, 1, 1, 0, // +0, 0, 1, 1, 0, 0, 0, 1, 0, 0, // +0, 0, 1, 1, 1, 1, 1, 1, 0, 0, // +0, 0, 1, 1, 1, 1, 1, 1, 1, 0, // +0, 0, 1, 1, 0, 0, 0, 1, 1, 0, // +0, 0, 1, 1, 0, 0, 0, 1, 1, 0, // +0, 0, 1, 1, 0, 0, 1, 1, 1, 0, // +0, 0, 1, 1, 1, 1, 1, 1, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +}, + + // Char 67 +{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 1, 1, 1, 1, 1, 1, 0, // +0, 0, 1, 1, 0, 0, 0, 0, 0, 0, // +0, 0, 1, 1, 0, 0, 0, 0, 0, 0, // +0, 1, 1, 0, 0, 0, 0, 0, 0, 0, // +0, 1, 1, 0, 0, 0, 0, 0, 0, 0, // +0, 1, 1, 0, 0, 0, 0, 0, 0, 0, // +0, 1, 1, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 1, 1, 0, 0, 0, 0, 0, 0, // +0, 0, 1, 1, 1, 0, 0, 1, 1, 0, // +0, 0, 0, 1, 1, 1, 1, 1, 1, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +}, + + // Char 68 +{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 1, 1, 1, 1, 1, 1, 0, 0, 0, // +0, 1, 1, 0, 0, 1, 1, 1, 0, 0, // +0, 1, 1, 0, 0, 0, 1, 1, 0, 0, // +0, 1, 1, 0, 0, 0, 0, 1, 0, 0, // +0, 1, 1, 0, 0, 0, 0, 1, 0, 0, // +0, 1, 1, 0, 0, 0, 0, 1, 0, 0, // +0, 1, 1, 0, 0, 0, 1, 1, 0, 0, // +0, 1, 1, 0, 0, 0, 1, 1, 0, 0, // +0, 1, 1, 1, 1, 1, 1, 1, 0, 0, // +0, 1, 1, 1, 1, 1, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +}, + + // Char 69 +{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 1, 1, 1, 1, 1, 1, 0, 0, // +0, 0, 1, 1, 0, 0, 0, 0, 0, 0, // +0, 0, 1, 1, 0, 0, 0, 0, 0, 0, // +0, 0, 1, 1, 0, 0, 0, 0, 0, 0, // +0, 0, 1, 1, 1, 1, 1, 1, 0, 0, // +0, 0, 1, 1, 1, 1, 1, 1, 0, 0, // +0, 0, 1, 1, 0, 0, 0, 0, 0, 0, // +0, 0, 1, 1, 0, 0, 0, 0, 0, 0, // +0, 0, 1, 1, 0, 0, 0, 0, 0, 0, // +0, 0, 1, 1, 1, 1, 1, 1, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +}, + + // Char 70 +{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 1, 1, 1, 1, 1, 1, 1, 0, // +0, 0, 1, 1, 0, 0, 0, 0, 0, 0, // +0, 0, 1, 1, 0, 0, 0, 0, 0, 0, // +0, 0, 1, 1, 0, 0, 0, 0, 0, 0, // +0, 0, 1, 1, 1, 1, 1, 1, 0, 0, // +0, 0, 1, 1, 1, 1, 1, 1, 0, 0, // +0, 0, 1, 1, 0, 0, 0, 0, 0, 0, // +0, 0, 1, 1, 0, 0, 0, 0, 0, 0, // +0, 0, 1, 1, 0, 0, 0, 0, 0, 0, // +0, 0, 1, 1, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +}, + + // Char 71 +{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 1, 1, 1, 1, 1, 1, 0, 0, // +0, 1, 1, 1, 0, 0, 0, 1, 0, 0, // +0, 1, 1, 0, 0, 0, 0, 0, 0, 0, // +0, 1, 1, 0, 0, 0, 0, 0, 0, 0, // +0, 1, 1, 0, 1, 1, 1, 1, 0, 0, // +0, 1, 1, 0, 1, 1, 1, 1, 0, 0, // +0, 1, 1, 0, 0, 0, 1, 1, 0, 0, // +0, 1, 1, 0, 0, 0, 1, 1, 0, 0, // +0, 1, 1, 1, 0, 0, 1, 1, 0, 0, // +0, 0, 1, 1, 1, 1, 1, 1, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +}, + + // Char 72 +{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 1, 0, 0, 0, 0, 1, 1, 0, // +0, 0, 1, 0, 0, 0, 0, 1, 1, 0, // +0, 0, 1, 0, 0, 0, 0, 1, 1, 0, // +0, 0, 1, 0, 0, 0, 0, 1, 1, 0, // +0, 0, 1, 1, 1, 1, 1, 1, 1, 0, // +0, 0, 1, 1, 1, 1, 1, 1, 1, 0, // +0, 0, 1, 0, 0, 0, 0, 1, 1, 0, // +0, 0, 1, 0, 0, 0, 0, 1, 1, 0, // +0, 0, 1, 0, 0, 0, 0, 1, 1, 0, // +0, 0, 1, 0, 0, 0, 0, 1, 1, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +}, + + // Char 73 +{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 1, 1, 1, 1, 1, 1, 1, 0, // +0, 0, 0, 0, 1, 1, 0, 0, 0, 0, // +0, 0, 0, 0, 1, 1, 0, 0, 0, 0, // +0, 0, 0, 0, 1, 1, 0, 0, 0, 0, // +0, 0, 0, 0, 1, 1, 0, 0, 0, 0, // +0, 0, 0, 0, 1, 1, 0, 0, 0, 0, // +0, 0, 0, 0, 1, 1, 0, 0, 0, 0, // +0, 0, 0, 0, 1, 1, 0, 0, 0, 0, // +0, 0, 0, 0, 1, 1, 0, 0, 0, 0, // +0, 0, 1, 1, 1, 1, 1, 1, 1, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +}, + + // Char 74 +{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 1, 1, 1, 1, 1, 1, 0, 0, // +0, 0, 0, 0, 0, 0, 1, 1, 0, 0, // +0, 0, 0, 0, 0, 0, 1, 1, 0, 0, // +0, 0, 0, 0, 0, 0, 1, 1, 0, 0, // +0, 0, 0, 0, 0, 0, 1, 1, 0, 0, // +0, 0, 0, 0, 0, 0, 1, 1, 0, 0, // +0, 0, 0, 0, 0, 0, 1, 1, 0, 0, // +0, 0, 0, 0, 0, 0, 1, 1, 0, 0, // +0, 0, 1, 1, 0, 1, 1, 1, 0, 0, // +0, 0, 1, 1, 1, 1, 1, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +}, + + // Char 75 +{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 1, 1, 0, 0, 0, 1, 1, 0, // +0, 0, 1, 1, 0, 0, 1, 1, 0, 0, // +0, 0, 1, 1, 0, 1, 1, 0, 0, 0, // +0, 0, 1, 1, 1, 1, 0, 0, 0, 0, // +0, 0, 1, 1, 1, 0, 0, 0, 0, 0, // +0, 0, 1, 1, 1, 1, 0, 0, 0, 0, // +0, 0, 1, 1, 1, 1, 1, 0, 0, 0, // +0, 0, 1, 1, 0, 1, 1, 1, 0, 0, // +0, 0, 1, 1, 0, 0, 1, 1, 0, 0, // +0, 0, 1, 1, 0, 0, 0, 1, 1, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +}, + + // Char 76 +{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 1, 1, 0, 0, 0, 0, 0, // +0, 0, 0, 1, 1, 0, 0, 0, 0, 0, // +0, 0, 0, 1, 1, 0, 0, 0, 0, 0, // +0, 0, 0, 1, 1, 0, 0, 0, 0, 0, // +0, 0, 0, 1, 1, 0, 0, 0, 0, 0, // +0, 0, 0, 1, 1, 0, 0, 0, 0, 0, // +0, 0, 0, 1, 1, 0, 0, 0, 0, 0, // +0, 0, 0, 1, 1, 0, 0, 0, 0, 0, // +0, 0, 0, 1, 1, 0, 0, 0, 0, 0, // +0, 0, 0, 1, 1, 1, 1, 1, 1, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +}, + + // Char 77 +{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 1, 1, 0, 0, 0, 1, 1, 0, // +0, 0, 1, 1, 0, 0, 1, 1, 1, 0, // +0, 0, 1, 1, 1, 0, 1, 1, 1, 0, // +0, 0, 1, 0, 1, 0, 1, 0, 1, 0, // +0, 1, 1, 0, 1, 1, 1, 0, 1, 0, // +0, 1, 1, 0, 1, 1, 0, 0, 1, 0, // +0, 1, 1, 0, 0, 1, 0, 0, 1, 0, // +0, 1, 1, 0, 0, 0, 0, 0, 1, 0, // +0, 1, 1, 0, 0, 0, 0, 0, 1, 1, // +0, 1, 1, 0, 0, 0, 0, 0, 1, 1, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +}, + + // Char 78 +{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 1, 1, 0, 0, 0, 1, 1, 0, // +0, 0, 1, 1, 1, 0, 0, 1, 1, 0, // +0, 0, 1, 1, 1, 0, 0, 1, 1, 0, // +0, 0, 1, 0, 1, 1, 0, 1, 1, 0, // +0, 0, 1, 0, 1, 1, 0, 1, 1, 0, // +0, 0, 1, 0, 0, 1, 0, 1, 1, 0, // +0, 0, 1, 0, 0, 1, 1, 1, 1, 0, // +0, 0, 1, 0, 0, 0, 1, 1, 1, 0, // +0, 0, 1, 0, 0, 0, 1, 1, 1, 0, // +0, 0, 1, 0, 0, 0, 0, 1, 1, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +}, + + // Char 79 +{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 1, 1, 1, 1, 1, 0, 0, // +0, 0, 1, 1, 0, 0, 1, 1, 1, 0, // +0, 1, 1, 0, 0, 0, 0, 1, 1, 0, // +0, 1, 1, 0, 0, 0, 0, 1, 1, 0, // +0, 1, 1, 0, 0, 0, 0, 1, 1, 0, // +0, 1, 1, 0, 0, 0, 0, 1, 1, 0, // +0, 1, 1, 0, 0, 0, 0, 1, 1, 0, // +0, 1, 1, 0, 0, 0, 0, 1, 1, 0, // +0, 0, 1, 1, 0, 0, 1, 1, 0, 0, // +0, 0, 0, 1, 1, 1, 1, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +}, + + // Char 80 +{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 1, 1, 1, 1, 1, 1, 0, // +0, 0, 0, 1, 1, 0, 0, 1, 1, 0, // +0, 0, 0, 1, 1, 0, 0, 0, 1, 1, // +0, 0, 0, 1, 1, 0, 0, 0, 1, 1, // +0, 0, 0, 1, 1, 0, 0, 1, 1, 0, // +0, 0, 0, 1, 1, 1, 1, 1, 0, 0, // +0, 0, 0, 1, 1, 0, 0, 0, 0, 0, // +0, 0, 0, 1, 1, 0, 0, 0, 0, 0, // +0, 0, 0, 1, 1, 0, 0, 0, 0, 0, // +0, 0, 0, 1, 1, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +}, + + // Char 81 +{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 1, 1, 1, 1, 1, 0, 0, 0, // +0, 0, 1, 1, 0, 0, 1, 1, 0, 0, // +0, 1, 1, 0, 0, 0, 0, 1, 1, 0, // +0, 1, 1, 0, 0, 0, 0, 1, 1, 0, // +0, 1, 1, 0, 0, 0, 0, 1, 1, 0, // +0, 1, 1, 0, 0, 0, 0, 1, 1, 0, // +0, 1, 1, 0, 0, 0, 0, 1, 1, 0, // +0, 1, 1, 0, 0, 0, 0, 1, 0, 0, // +0, 1, 1, 1, 0, 0, 1, 1, 0, 0, // +0, 0, 1, 1, 1, 1, 1, 0, 0, 0, // +0, 0, 0, 0, 1, 1, 0, 0, 0, 0, // +0, 0, 0, 0, 1, 1, 1, 1, 1, 0, // +0, 0, 0, 0, 0, 1, 1, 1, 1, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +}, + + // Char 82 +{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 1, 1, 1, 1, 1, 1, 0, 0, 0, // +0, 1, 1, 0, 0, 1, 1, 1, 0, 0, // +0, 1, 1, 0, 0, 0, 1, 1, 0, 0, // +0, 1, 1, 0, 0, 0, 1, 1, 0, 0, // +0, 1, 1, 1, 1, 1, 1, 0, 0, 0, // +0, 1, 1, 1, 1, 1, 0, 0, 0, 0, // +0, 1, 1, 0, 0, 1, 1, 0, 0, 0, // +0, 1, 1, 0, 0, 0, 1, 0, 0, 0, // +0, 1, 1, 0, 0, 0, 1, 1, 0, 0, // +0, 1, 1, 0, 0, 0, 1, 1, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +}, + + // Char 83 +{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 1, 1, 1, 1, 1, 0, 0, // +0, 0, 1, 1, 0, 0, 0, 0, 0, 0, // +0, 0, 1, 1, 0, 0, 0, 0, 0, 0, // +0, 0, 1, 1, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 1, 1, 1, 1, 0, 0, 0, // +0, 0, 0, 0, 0, 1, 1, 1, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 1, 1, 0, // +0, 0, 0, 0, 0, 0, 0, 1, 1, 0, // +0, 0, 1, 0, 0, 0, 1, 1, 1, 0, // +0, 0, 1, 1, 1, 1, 1, 1, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +}, + + // Char 84 +{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 1, 1, 1, 1, 1, 1, 1, 1, 0, // +0, 0, 0, 0, 1, 1, 0, 0, 0, 0, // +0, 0, 0, 0, 1, 1, 0, 0, 0, 0, // +0, 0, 0, 0, 1, 1, 0, 0, 0, 0, // +0, 0, 0, 0, 1, 1, 0, 0, 0, 0, // +0, 0, 0, 0, 1, 1, 0, 0, 0, 0, // +0, 0, 0, 0, 1, 1, 0, 0, 0, 0, // +0, 0, 0, 0, 1, 1, 0, 0, 0, 0, // +0, 0, 0, 0, 1, 1, 0, 0, 0, 0, // +0, 0, 0, 0, 1, 1, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +}, + + // Char 85 +{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 1, 1, 0, 0, 0, 0, 1, 1, 0, // +0, 1, 1, 0, 0, 0, 0, 1, 1, 0, // +0, 1, 1, 0, 0, 0, 0, 1, 1, 0, // +0, 1, 1, 0, 0, 0, 0, 1, 1, 0, // +0, 1, 1, 0, 0, 0, 0, 1, 1, 0, // +0, 1, 1, 0, 0, 0, 0, 1, 1, 0, // +0, 0, 1, 0, 0, 0, 0, 1, 1, 0, // +0, 0, 1, 0, 0, 0, 0, 1, 1, 0, // +0, 0, 1, 1, 0, 0, 1, 1, 0, 0, // +0, 0, 0, 1, 1, 1, 1, 1, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +}, + + // Char 86 +{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 1, 1, 0, 0, 0, 0, 1, 1, // +0, 0, 1, 1, 0, 0, 0, 0, 1, 1, // +0, 0, 1, 1, 0, 0, 0, 0, 1, 1, // +0, 0, 0, 1, 1, 0, 0, 0, 1, 0, // +0, 0, 0, 1, 1, 0, 0, 1, 1, 0, // +0, 0, 0, 1, 1, 0, 0, 1, 1, 0, // +0, 0, 0, 0, 1, 0, 0, 1, 0, 0, // +0, 0, 0, 0, 1, 1, 1, 1, 0, 0, // +0, 0, 0, 0, 1, 1, 1, 1, 0, 0, // +0, 0, 0, 0, 0, 1, 1, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +}, + + // Char 87 +{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 1, 1, 0, 0, 0, 0, 1, 1, 0, // +0, 1, 1, 0, 0, 0, 0, 1, 1, 0, // +0, 1, 1, 0, 0, 0, 0, 1, 1, 0, // +0, 1, 1, 0, 1, 1, 0, 1, 1, 0, // +0, 1, 1, 0, 1, 1, 0, 1, 1, 0, // +0, 1, 1, 1, 1, 1, 0, 1, 1, 0, // +0, 1, 1, 1, 1, 1, 1, 1, 1, 0, // +0, 1, 1, 1, 0, 1, 1, 1, 0, 0, // +0, 1, 1, 1, 0, 0, 1, 1, 0, 0, // +0, 1, 1, 1, 0, 0, 1, 1, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +}, + + // Char 88 +{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 1, 1, 0, 0, 0, 1, 1, 0, 0, // +0, 1, 1, 1, 0, 0, 1, 1, 0, 0, // +0, 0, 1, 1, 0, 1, 1, 0, 0, 0, // +0, 0, 0, 1, 1, 1, 0, 0, 0, 0, // +0, 0, 0, 1, 1, 1, 0, 0, 0, 0, // +0, 0, 0, 1, 1, 1, 0, 0, 0, 0, // +0, 0, 1, 1, 1, 1, 1, 0, 0, 0, // +0, 0, 1, 1, 0, 1, 1, 0, 0, 0, // +0, 1, 1, 0, 0, 0, 1, 1, 0, 0, // +0, 1, 1, 0, 0, 0, 0, 1, 1, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +}, + + // Char 89 +{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 1, 1, 0, 0, 0, 0, 0, 1, 0, // +0, 0, 1, 1, 0, 0, 0, 1, 1, 0, // +0, 0, 1, 1, 0, 0, 0, 1, 0, 0, // +0, 0, 0, 1, 1, 0, 1, 1, 0, 0, // +0, 0, 0, 1, 1, 1, 1, 0, 0, 0, // +0, 0, 0, 0, 1, 1, 1, 0, 0, 0, // +0, 0, 0, 0, 0, 1, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 1, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 1, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 1, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +}, + + // Char 90 +{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 1, 1, 1, 1, 1, 1, 1, 0, // +0, 0, 0, 0, 0, 0, 1, 1, 0, 0, // +0, 0, 0, 0, 0, 0, 1, 1, 0, 0, // +0, 0, 0, 0, 0, 1, 1, 0, 0, 0, // +0, 0, 0, 0, 1, 1, 0, 0, 0, 0, // +0, 0, 0, 0, 1, 1, 0, 0, 0, 0, // +0, 0, 0, 1, 1, 0, 0, 0, 0, 0, // +0, 0, 1, 1, 0, 0, 0, 0, 0, 0, // +0, 0, 1, 1, 0, 0, 0, 0, 0, 0, // +0, 0, 1, 1, 1, 1, 1, 1, 1, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +}, + + // Char 91 +{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 1, 1, 1, 1, 0, 0, 0, // +0, 0, 0, 1, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 1, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 1, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 1, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 1, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 1, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 1, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 1, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 1, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 1, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 1, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 1, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 1, 1, 1, 1, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +}, + + // Char 92 +{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 1, 1, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 1, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 1, 1, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 1, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 1, 1, 0, 0, 0, 0, 0, // +0, 0, 0, 1, 1, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 1, 1, 0, 0, 0, 0, // +0, 0, 0, 0, 1, 1, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 1, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 1, 1, 0, 0, 0, // +0, 0, 0, 0, 0, 1, 1, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 1, 1, 0, 0, // +0, 0, 0, 0, 0, 0, 1, 1, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +}, + + // Char 93 +{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 1, 1, 1, 1, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 1, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 1, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 1, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 1, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 1, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 1, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 1, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 1, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 1, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 1, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 1, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 1, 0, 0, 0, // +0, 0, 0, 1, 1, 1, 1, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +}, + + // Char 94 +{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 1, 1, 0, 0, 0, 0, // +0, 0, 0, 1, 1, 1, 1, 0, 0, 0, // +0, 0, 0, 1, 0, 0, 1, 0, 0, 0, // +0, 0, 1, 1, 0, 0, 1, 1, 0, 0, // +0, 1, 1, 0, 0, 0, 0, 1, 1, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +}, + + // Char 95 +{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +1, 1, 1, 1, 1, 1, 1, 1, 1, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +}, + + // Char 96 +{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 1, 1, 1, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 1, 1, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +}, + + // Char 97 +{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 1, 1, 1, 1, 1, 0, 0, // +0, 0, 1, 1, 0, 0, 1, 1, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 1, 1, 0, // +0, 0, 0, 0, 1, 1, 1, 1, 1, 0, // +0, 0, 1, 1, 1, 1, 1, 1, 1, 0, // +0, 0, 1, 1, 0, 0, 0, 1, 1, 0, // +0, 0, 1, 1, 0, 0, 1, 1, 1, 0, // +0, 0, 0, 1, 1, 1, 1, 1, 1, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +}, + + // Char 98 +{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 1, 1, 0, 0, 0, 0, 0, 0, // +0, 0, 1, 1, 0, 0, 0, 0, 0, 0, // +0, 0, 1, 1, 0, 0, 0, 0, 0, 0, // +0, 0, 1, 1, 1, 1, 1, 1, 0, 0, // +0, 0, 1, 1, 1, 0, 1, 1, 0, 0, // +0, 0, 1, 1, 0, 0, 0, 1, 1, 0, // +0, 0, 1, 1, 0, 0, 0, 1, 1, 0, // +0, 0, 1, 1, 0, 0, 0, 1, 1, 0, // +0, 0, 1, 1, 0, 0, 0, 1, 1, 0, // +0, 0, 1, 1, 0, 0, 1, 1, 0, 0, // +0, 0, 1, 1, 1, 1, 1, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +}, + + // Char 99 +{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 1, 1, 1, 1, 0, 0, 0, // +0, 0, 1, 1, 0, 0, 1, 0, 0, 0, // +0, 1, 1, 0, 0, 0, 0, 0, 0, 0, // +0, 1, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 1, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 1, 1, 0, 0, 0, 0, 0, 0, 0, // +0, 1, 1, 1, 0, 0, 1, 0, 0, 0, // +0, 0, 1, 1, 1, 1, 1, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +}, + + // Char 100 +{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 1, 1, 0, 0, // +0, 0, 0, 0, 0, 0, 1, 1, 0, 0, // +0, 0, 0, 0, 0, 0, 1, 1, 0, 0, // +0, 0, 0, 1, 1, 1, 1, 1, 0, 0, // +0, 0, 1, 1, 0, 0, 1, 1, 0, 0, // +0, 1, 1, 0, 0, 0, 1, 1, 0, 0, // +0, 1, 1, 0, 0, 0, 1, 1, 0, 0, // +0, 1, 1, 0, 0, 0, 1, 1, 0, 0, // +0, 1, 1, 0, 0, 0, 1, 1, 0, 0, // +0, 0, 1, 1, 0, 1, 1, 1, 0, 0, // +0, 0, 1, 1, 1, 1, 1, 1, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +}, + + // Char 101 +{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 1, 1, 1, 1, 0, 0, 0, // +0, 0, 1, 1, 0, 0, 1, 1, 0, 0, // +0, 1, 1, 0, 0, 0, 1, 1, 0, 0, // +0, 1, 1, 1, 1, 1, 1, 1, 0, 0, // +0, 1, 1, 1, 1, 1, 1, 1, 0, 0, // +0, 1, 1, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 1, 1, 0, 0, 0, 0, 0, 0, // +0, 0, 1, 1, 1, 1, 1, 1, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +}, + + // Char 102 +{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 1, 1, 1, 1, 0, 0, // +0, 0, 0, 1, 1, 0, 0, 0, 0, 0, // +0, 0, 0, 1, 1, 0, 0, 0, 0, 0, // +0, 0, 0, 1, 1, 0, 0, 0, 0, 0, // +1, 1, 1, 1, 1, 1, 1, 1, 0, 0, // +0, 1, 1, 1, 1, 1, 1, 1, 0, 0, // +0, 0, 0, 1, 1, 0, 0, 0, 0, 0, // +0, 0, 0, 1, 1, 0, 0, 0, 0, 0, // +0, 0, 0, 1, 1, 0, 0, 0, 0, 0, // +0, 0, 0, 1, 1, 0, 0, 0, 0, 0, // +0, 0, 0, 1, 1, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +}, + + // Char 103 +{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 1, 1, 1, 1, 1, 1, 0, 0, // +0, 1, 1, 0, 0, 1, 1, 1, 0, 0, // +0, 1, 1, 0, 0, 0, 1, 0, 0, 0, // +0, 1, 1, 0, 0, 0, 1, 0, 0, 0, // +0, 1, 1, 1, 1, 1, 1, 0, 0, 0, // +0, 1, 1, 0, 1, 0, 0, 0, 0, 0, // +0, 1, 1, 1, 0, 0, 0, 0, 0, 0, // +0, 1, 1, 1, 1, 1, 1, 1, 0, 0, // +0, 1, 1, 0, 0, 0, 1, 1, 0, 0, // +0, 1, 1, 0, 0, 0, 1, 1, 0, 0, // +0, 1, 1, 1, 1, 1, 1, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +}, + + // Char 104 +{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 1, 1, 0, 0, 0, 0, 0, 0, // +0, 0, 1, 1, 0, 0, 0, 0, 0, 0, // +0, 0, 1, 1, 0, 0, 0, 0, 0, 0, // +0, 0, 1, 1, 1, 1, 1, 1, 0, 0, // +0, 0, 1, 1, 1, 0, 1, 1, 0, 0, // +0, 0, 1, 1, 0, 0, 0, 1, 0, 0, // +0, 0, 1, 1, 0, 0, 0, 1, 0, 0, // +0, 0, 1, 1, 0, 0, 0, 1, 1, 0, // +0, 0, 1, 1, 0, 0, 0, 1, 1, 0, // +0, 0, 1, 1, 0, 0, 0, 1, 1, 0, // +0, 0, 1, 1, 0, 0, 0, 1, 1, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +}, + + // Char 105 +{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 1, 1, 0, 0, 0, 0, // +0, 0, 0, 0, 1, 1, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 1, 1, 1, 1, 0, 0, 0, 0, // +0, 0, 0, 0, 1, 1, 0, 0, 0, 0, // +0, 0, 0, 0, 1, 1, 0, 0, 0, 0, // +0, 0, 0, 0, 1, 1, 0, 0, 0, 0, // +0, 0, 0, 0, 1, 1, 0, 0, 0, 0, // +0, 0, 0, 0, 1, 1, 0, 0, 0, 0, // +0, 0, 0, 0, 1, 1, 0, 0, 0, 0, // +0, 0, 1, 1, 1, 1, 1, 1, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +}, + + // Char 106 +{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 1, 1, 0, 0, 0, // +0, 0, 0, 0, 0, 1, 1, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 1, 1, 1, 1, 1, 0, 0, 0, // +0, 0, 0, 0, 0, 1, 1, 0, 0, 0, // +0, 0, 0, 0, 0, 1, 1, 0, 0, 0, // +0, 0, 0, 0, 0, 1, 1, 0, 0, 0, // +0, 0, 0, 0, 0, 1, 1, 0, 0, 0, // +0, 0, 0, 0, 0, 1, 1, 0, 0, 0, // +0, 0, 0, 0, 0, 1, 1, 0, 0, 0, // +0, 0, 0, 0, 0, 1, 1, 0, 0, 0, // +0, 0, 0, 0, 0, 1, 1, 0, 0, 0, // +0, 0, 0, 0, 0, 1, 1, 0, 0, 0, // +0, 1, 1, 1, 1, 1, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +}, + + // Char 107 +{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 1, 1, 0, 0, 0, 0, 0, 0, // +0, 0, 1, 1, 0, 0, 0, 0, 0, 0, // +0, 0, 1, 1, 0, 0, 0, 0, 0, 0, // +0, 0, 1, 1, 0, 0, 0, 1, 1, 0, // +0, 0, 1, 1, 0, 0, 1, 1, 0, 0, // +0, 0, 1, 1, 0, 1, 1, 0, 0, 0, // +0, 0, 1, 1, 1, 1, 0, 0, 0, 0, // +0, 0, 1, 1, 1, 1, 1, 0, 0, 0, // +0, 0, 1, 1, 0, 1, 1, 1, 0, 0, // +0, 0, 1, 1, 0, 0, 1, 1, 1, 0, // +0, 0, 1, 1, 0, 0, 0, 1, 1, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +}, + + // Char 108 +{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 1, 1, 1, 1, 0, 0, 0, 0, // +0, 0, 0, 0, 1, 1, 0, 0, 0, 0, // +0, 0, 0, 0, 1, 1, 0, 0, 0, 0, // +0, 0, 0, 0, 1, 1, 0, 0, 0, 0, // +0, 0, 0, 0, 1, 1, 0, 0, 0, 0, // +0, 0, 0, 0, 1, 1, 0, 0, 0, 0, // +0, 0, 0, 0, 1, 1, 0, 0, 0, 0, // +0, 0, 0, 0, 1, 1, 0, 0, 0, 0, // +0, 0, 0, 0, 1, 1, 0, 0, 0, 0, // +0, 0, 0, 0, 1, 1, 0, 0, 0, 0, // +0, 0, 1, 1, 1, 1, 1, 1, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +}, + + // Char 109 +{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 1, 1, 1, 1, 0, 1, 1, 1, 0, // +0, 1, 1, 1, 1, 1, 1, 1, 1, 0, // +0, 1, 1, 0, 1, 1, 0, 1, 1, 0, // +0, 1, 1, 0, 1, 1, 0, 1, 1, 0, // +0, 1, 1, 0, 1, 1, 0, 1, 1, 0, // +0, 1, 1, 0, 1, 1, 0, 1, 1, 0, // +0, 1, 1, 0, 1, 1, 0, 1, 1, 0, // +0, 1, 1, 0, 1, 1, 0, 1, 1, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +}, + + // Char 110 +{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 1, 1, 0, 1, 1, 1, 0, 0, 0, // +0, 1, 1, 1, 1, 0, 1, 1, 0, 0, // +0, 1, 1, 0, 0, 0, 1, 1, 0, 0, // +0, 1, 1, 0, 0, 0, 1, 1, 0, 0, // +0, 1, 1, 0, 0, 0, 1, 1, 0, 0, // +0, 1, 1, 0, 0, 0, 1, 1, 0, 0, // +0, 1, 1, 0, 0, 0, 1, 1, 0, 0, // +0, 1, 1, 0, 0, 0, 1, 1, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +}, + + // Char 111 +{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 1, 1, 1, 1, 1, 0, 0, // +0, 0, 1, 1, 1, 0, 1, 1, 1, 0, // +0, 0, 1, 1, 0, 0, 0, 1, 1, 0, // +0, 0, 1, 1, 0, 0, 0, 1, 1, 0, // +0, 0, 1, 1, 0, 0, 0, 1, 1, 0, // +0, 0, 1, 1, 0, 0, 0, 1, 1, 0, // +0, 0, 1, 1, 0, 0, 1, 1, 1, 0, // +0, 0, 0, 1, 1, 1, 1, 1, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +}, + + // Char 112 +{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 1, 0, 1, 1, 1, 1, 0, 0, 0, // +0, 1, 1, 1, 0, 1, 1, 0, 0, 0, // +0, 1, 1, 0, 0, 0, 1, 1, 0, 0, // +0, 1, 1, 0, 0, 0, 1, 1, 0, 0, // +0, 1, 1, 0, 0, 0, 1, 1, 0, 0, // +0, 1, 1, 0, 0, 0, 1, 1, 0, 0, // +0, 1, 1, 0, 0, 1, 1, 0, 0, 0, // +0, 1, 1, 1, 1, 1, 0, 0, 0, 0, // +0, 1, 1, 0, 0, 0, 0, 0, 0, 0, // +0, 1, 1, 0, 0, 0, 0, 0, 0, 0, // +0, 1, 1, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +}, + + // Char 113 +{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 1, 1, 1, 1, 1, 0, 0, // +0, 0, 1, 1, 0, 0, 1, 1, 0, 0, // +0, 1, 1, 0, 0, 0, 1, 1, 0, 0, // +0, 1, 1, 0, 0, 0, 1, 1, 0, 0, // +0, 1, 1, 0, 0, 0, 1, 1, 0, 0, // +0, 1, 1, 0, 0, 0, 1, 1, 0, 0, // +0, 1, 1, 1, 1, 1, 1, 1, 0, 0, // +0, 0, 1, 1, 1, 0, 1, 1, 0, 0, // +0, 0, 0, 0, 0, 0, 1, 1, 0, 0, // +0, 0, 0, 0, 0, 0, 1, 1, 0, 0, // +0, 0, 0, 0, 0, 0, 1, 1, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +}, + + // Char 114 +{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 1, 1, 0, 1, 1, 1, 0, // +0, 0, 0, 1, 1, 1, 1, 0, 1, 1, // +0, 0, 0, 1, 1, 0, 0, 0, 1, 1, // +0, 0, 0, 1, 1, 0, 0, 0, 0, 0, // +0, 0, 0, 1, 1, 0, 0, 0, 0, 0, // +0, 0, 0, 1, 1, 0, 0, 0, 0, 0, // +0, 0, 0, 1, 1, 0, 0, 0, 0, 0, // +0, 0, 0, 1, 1, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +}, + + // Char 115 +{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 1, 1, 1, 1, 1, 0, 0, // +0, 0, 1, 1, 0, 0, 0, 0, 0, 0, // +0, 0, 1, 1, 0, 0, 0, 0, 0, 0, // +0, 0, 1, 1, 1, 1, 0, 0, 0, 0, // +0, 0, 0, 0, 1, 1, 1, 1, 0, 0, // +0, 0, 0, 0, 0, 0, 1, 1, 0, 0, // +0, 0, 0, 0, 0, 0, 1, 1, 0, 0, // +0, 0, 1, 1, 1, 1, 1, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +}, + + // Char 116 +{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 1, 1, 0, 0, 0, 0, 0, // +0, 0, 0, 1, 1, 0, 0, 0, 0, 0, // +0, 1, 1, 1, 1, 1, 1, 1, 0, 0, // +0, 0, 0, 1, 1, 0, 0, 0, 0, 0, // +0, 0, 0, 1, 1, 0, 0, 0, 0, 0, // +0, 0, 0, 1, 1, 0, 0, 0, 0, 0, // +0, 0, 0, 1, 1, 0, 0, 0, 0, 0, // +0, 0, 0, 1, 1, 0, 0, 0, 0, 0, // +0, 0, 0, 1, 1, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 1, 1, 1, 1, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +}, + + // Char 117 +{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 1, 1, 0, 0, 0, 1, 1, 0, 0, // +0, 1, 1, 0, 0, 0, 1, 1, 0, 0, // +0, 1, 1, 0, 0, 0, 1, 1, 0, 0, // +0, 1, 1, 0, 0, 0, 1, 1, 0, 0, // +0, 1, 1, 0, 0, 0, 1, 1, 0, 0, // +0, 1, 1, 0, 0, 0, 1, 1, 0, 0, // +0, 1, 1, 1, 0, 1, 1, 1, 0, 0, // +0, 0, 1, 1, 1, 1, 1, 1, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +}, + + // Char 118 +{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 1, 1, 0, 0, 0, 0, 1, 1, 0, // +0, 0, 1, 1, 0, 0, 0, 1, 1, 0, // +0, 0, 1, 1, 0, 0, 0, 1, 0, 0, // +0, 0, 0, 1, 0, 0, 1, 1, 0, 0, // +0, 0, 0, 1, 1, 0, 1, 1, 0, 0, // +0, 0, 0, 1, 1, 1, 1, 0, 0, 0, // +0, 0, 0, 0, 1, 1, 1, 0, 0, 0, // +0, 0, 0, 0, 1, 1, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +}, + + // Char 119 +{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 1, 1, 0, 0, 0, 0, 0, 1, 0, // +0, 1, 1, 0, 0, 0, 0, 0, 1, 0, // +0, 1, 1, 0, 1, 1, 0, 0, 1, 0, // +0, 1, 1, 0, 1, 1, 0, 1, 1, 0, // +0, 0, 1, 0, 1, 1, 1, 1, 1, 0, // +0, 0, 1, 1, 1, 1, 1, 1, 1, 0, // +0, 0, 1, 1, 1, 0, 1, 1, 1, 0, // +0, 0, 1, 1, 0, 0, 1, 1, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +}, + + // Char 120 +{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 1, 1, 0, 0, 0, 0, 1, 1, 0, // +0, 0, 1, 1, 0, 0, 1, 1, 0, 0, // +0, 0, 0, 1, 1, 1, 1, 0, 0, 0, // +0, 0, 0, 1, 1, 1, 0, 0, 0, 0, // +0, 0, 0, 0, 1, 1, 0, 0, 0, 0, // +0, 0, 0, 1, 1, 1, 1, 0, 0, 0, // +0, 0, 1, 1, 0, 0, 1, 1, 0, 0, // +0, 1, 1, 0, 0, 0, 1, 1, 1, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +}, + + // Char 121 +{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 1, 1, 0, 0, 0, 0, 1, 1, 0, // +0, 1, 1, 0, 0, 0, 1, 1, 0, 0, // +0, 0, 1, 0, 0, 0, 1, 1, 0, 0, // +0, 0, 1, 1, 0, 0, 1, 0, 0, 0, // +0, 0, 1, 1, 0, 1, 1, 0, 0, 0, // +0, 0, 0, 1, 1, 1, 1, 0, 0, 0, // +0, 0, 0, 1, 1, 1, 0, 0, 0, 0, // +0, 0, 0, 0, 1, 1, 0, 0, 0, 0, // +0, 0, 0, 0, 1, 0, 0, 0, 0, 0, // +0, 0, 0, 1, 1, 0, 0, 0, 0, 0, // +0, 1, 1, 1, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +}, + + // Char 122 +{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 1, 1, 1, 1, 1, 1, 1, 0, 0, // +0, 0, 1, 1, 1, 1, 1, 1, 0, 0, // +0, 0, 0, 0, 0, 1, 1, 0, 0, 0, // +0, 0, 0, 0, 1, 1, 0, 0, 0, 0, // +0, 0, 0, 1, 1, 0, 0, 0, 0, 0, // +0, 0, 1, 1, 1, 0, 0, 0, 0, 0, // +0, 0, 1, 1, 0, 0, 0, 0, 0, 0, // +0, 1, 1, 1, 1, 1, 1, 1, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +}, + + // Char 123 +{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 1, 1, 1, 0, 0, 0, // +0, 0, 0, 1, 1, 0, 0, 0, 0, 0, // +0, 0, 0, 1, 1, 0, 0, 0, 0, 0, // +0, 0, 0, 1, 1, 0, 0, 0, 0, 0, // +0, 0, 0, 1, 1, 0, 0, 0, 0, 0, // +0, 0, 0, 1, 1, 0, 0, 0, 0, 0, // +0, 1, 1, 1, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 1, 1, 0, 0, 0, 0, 0, // +0, 0, 0, 1, 1, 0, 0, 0, 0, 0, // +0, 0, 0, 1, 1, 0, 0, 0, 0, 0, // +0, 0, 0, 1, 1, 0, 0, 0, 0, 0, // +0, 0, 0, 1, 1, 0, 0, 0, 0, 0, // +0, 0, 0, 1, 1, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 1, 1, 1, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +}, + + // Char 124 +{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 1, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 1, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 1, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 1, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 1, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 1, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 1, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 1, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 1, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 1, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 1, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 1, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 1, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 1, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 1, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 1, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +}, + + // Char 125 +{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 1, 1, 1, 0, 0, 0, // +0, 0, 0, 0, 0, 1, 1, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 1, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 1, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 1, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 1, 1, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 1, 1, 1, // +0, 0, 0, 0, 0, 0, 1, 1, 0, 0, // +0, 0, 0, 0, 0, 0, 1, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 1, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 1, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 1, 0, 0, 0, // +0, 0, 0, 0, 0, 1, 1, 0, 0, 0, // +0, 0, 0, 0, 1, 1, 1, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +}, + + // Char 126 +{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 1, 1, 1, 0, 0, 0, 1, 0, // +0, 0, 1, 1, 1, 1, 0, 0, 1, 0, // +0, 1, 1, 0, 0, 1, 1, 1, 1, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +}, + + // Char 127 +{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +}, + + // Char 128 +{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +}, + + // Char 129 +{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // +}, +}; \ No newline at end of file diff --git a/kernel/src/shared/video/console_video.cpp b/kernel/src/shared/video/console_video.cpp index 138cd927..8850a295 100644 --- a/kernel/src/shared/video/console_video.cpp +++ b/kernel/src/shared/video/console_video.cpp @@ -19,52 +19,83 @@ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #include "shared/video/console_video.hpp" -#include "shared/memory/memory.hpp" -#include "shared/system/io_port.hpp" +#include "shared/logger/logger.hpp" +#include "shared/video/bitmap_font.hpp" -static uint8_t* videoMemory = (uint8_t*) G_CONSOLE_VIDEO_MEMORY; -static uint8_t color = G_CONSOLE_VIDEO_DEFAULT_COLOR; +static volatile uint32_t* videoMemory = nullptr; +static int videoWidth = 0; +static int videoHeight = 0; +static uint64_t videoPitch = 0; + +static uint32_t color = G_CONSOLE_VIDEO_DEFAULT_COLOR; static uint32_t offset = 0; +void consoleVideoInitialize(limine_framebuffer* framebuffer) +{ + videoMemory = static_cast(framebuffer->address); + videoWidth = framebuffer->width; + videoHeight = framebuffer->height; + videoPitch = framebuffer->pitch / (framebuffer->bpp / 8); +} + void consoleVideoPrint(char c) { + int charColumns = videoWidth / bitmapFontCharWidth; + int charRows = videoHeight / bitmapFontCharHeight; + if(c == '\n') { - if(offset % (G_CONSOLE_VIDEO_WIDTH * 2) == 0) - consoleVideoPrint(' '); + offset += charColumns - (offset % charColumns); + } + else + { + if(offset >= charColumns * charRows) + consoleVideoScrollUp(); - while(offset % (G_CONSOLE_VIDEO_WIDTH * 2) != 0) - consoleVideoPrint(' '); + int x = offset % charColumns; + int y = (offset / charColumns) % charRows; - } else - { - videoMemory[offset++] = c; - videoMemory[offset++] = color; + consoleVideoPutChar(x, y, c, color); - if(offset >= (G_CONSOLE_VIDEO_WIDTH * 2 * G_CONSOLE_VIDEO_HEIGHT)) - { - consoleVideoScrollUp(); - } + offset++; } } -void consoleVideoPutChar(uint16_t x, uint16_t y, char c, uint8_t color) +void consoleVideoPutChar(uint16_t x, uint16_t y, char c, uint32_t color) { - videoMemory[y * (G_CONSOLE_VIDEO_WIDTH * 2) + x * 2] = c; - videoMemory[y * (G_CONSOLE_VIDEO_WIDTH * 2) + x * 2 + 1] = color; + uint8_t* fontChar = bitmapFontGetChar(c); + + int onScreenX = x * bitmapFontCharWidth; + if(onScreenX > videoWidth - bitmapFontCharWidth) + return; + + int onScreenY = y * bitmapFontCharHeight;; + if(onScreenY > videoHeight - bitmapFontCharHeight) + return; + + for(int cy = 0; cy < bitmapFontCharHeight; cy++) + { + for(int cx = 0; cx < bitmapFontCharWidth; cx++) + { + videoMemory[(onScreenY + cy) * videoPitch + (onScreenX + cx)] = + (fontChar && fontChar[cy * bitmapFontCharWidth + cx] > 0) ? color : 0; + } + } } -void consoleVideoPutString(uint16_t x, uint16_t y, const char* c, uint8_t color) +void consoleVideoPutString(uint16_t x, uint16_t y, const char* c, uint32_t color) { + int charColumns = videoWidth / bitmapFontCharWidth; + int charRows = videoHeight / bitmapFontCharHeight; while(*c) { consoleVideoPutChar(x++, y, *c, color); - if(x > G_CONSOLE_VIDEO_WIDTH) + if(x > charColumns) { x = 0; y++; } - if(y > G_CONSOLE_VIDEO_HEIGHT) + if(y > charRows) { y = 0; } @@ -74,32 +105,63 @@ void consoleVideoPutString(uint16_t x, uint16_t y, const char* c, uint8_t color) void consoleVideoScrollUp() { - uint32_t screenBytesWithoutLastLine = G_CONSOLE_VIDEO_SCREEN_BYTES - G_CONSOLE_VIDEO_LINE_BYTES; - memoryCopy(videoMemory, videoMemory + G_CONSOLE_VIDEO_LINE_BYTES, screenBytesWithoutLastLine); - offset -= G_CONSOLE_VIDEO_LINE_BYTES; - memorySetWords(videoMemory + screenBytesWithoutLastLine, ((G_CONSOLE_VIDEO_DEFAULT_COLOR << 8) | ' '), G_CONSOLE_VIDEO_WIDTH); + for(int y = 0; y < videoHeight; y++) + { + for(int x = 0; x < videoWidth; x++) + { + videoMemory[y * videoPitch + x] = 0; + } + } + offset = 0; + + // TODO this is quite slow: + // int charColumns = videoWidth / bitmapFontCharWidth; + // int charRows = videoHeight / bitmapFontCharHeight; + // + // for(int y = 0; y < (charRows - 1) * bitmapFontCharHeight; y++) + // { + // for(int x = 0; x < videoWidth; x++) + // { + // videoMemory[y * videoPitch + x] = videoMemory[(y + bitmapFontCharHeight) * videoPitch + x]; + // } + // } + // + // for(int y = (charRows - 1) * bitmapFontCharHeight; y < videoHeight; y++) + // { + // for(int x = 0; x < videoWidth; x++) + // { + // videoMemory[y * videoPitch + x] = 0; + // } + // } + // + // offset -= charColumns; + // if(offset < 0) + // offset = 0; } void consoleVideoClear() { - for(uint32_t i = 0; i < 25; i++) + for(int y = 0; y < videoHeight; y++) { - consoleVideoPrint('\n'); + for(int x = 0; x < videoWidth; x++) + { + videoMemory[y * videoPitch + x] = 0; + } } offset = 0; } -void consoleVideoSetColor(uint8_t newColor) +void consoleVideoSetColor(uint32_t newColor) { color = newColor; } -void consoleVideoSetVisualCursor(int x, int y) +uint32_t consoleVideoGetColor() { + return color; +} - uint16_t position = (y * G_CONSOLE_VIDEO_WIDTH) + x; - ioPortWriteByte(0x3D4, 0x0F); - ioPortWriteByte(0x3D5, (uint8_t) (position & 0xFF)); - ioPortWriteByte(0x3D4, 0x0E); - ioPortWriteByte(0x3D5, (uint8_t) ((position >> 8) & 0xFF)); +void consoleVideoSetVisualCursor(int x, int y) +{ + // TODO: Do we need it? } diff --git a/kernel/src/test/loader/memory/physical.cpp b/kernel/src/test/loader/memory/physical.cpp deleted file mode 100644 index 6d85dc25..00000000 --- a/kernel/src/test/loader/memory/physical.cpp +++ /dev/null @@ -1,114 +0,0 @@ -#include "test/test.hpp" -#include -#include -#include - -// Test unit -#include "loader/memory/physical.cpp" - -g_setup_information setupInformation; - -TEST(memoryPhysicalReadMemoryMapSimple, "Read simple memory map") -{ - setupInformation.multibootInformation = malloc(sizeof(g_multiboot_information)); - - uint32_t mmapLength = (sizeof(g_multiboot_mmap) + sizeof(uint32_t)) * 1; - void* mmap = malloc(mmapLength); - - g_multiboot_mmap* mmap1 = (g_multiboot_mmap*) mmap; - mmap1->size = sizeof(g_multiboot_mmap); - mmap1->baseAddress = 0x00100000; - mmap1->length = 0x0BF00000; // 0x00100000 - 0x0C000000 - mmap1->type = G_MULTIBOOT_MMAP_TYPE_FREE; - setupInformation.multibootInformation->memoryMap = mmap1; - setupInformation.multibootInformation->memoryMapLength = mmapLength; - setupInformation.multibootInformation->flags |= G_MULTIBOOT_FLAGS_MMAP; - - uint32_t required = memoryPhysicalReadMemoryMap(0x05000000, 0); - - void* bitmapMemory = malloc(required); - - uint32_t requiredAfter = memoryPhysicalReadMemoryMap(0x05000000, bitmapMemory); - ASSERT_EQUALS(required, requiredAfter); - - // Bitmap creates 2 splinters since the range is larger than G_BITMAP_MAX_RANGE - g_bitmap_header* splinter1 = (g_bitmap_header*) bitmapMemory; - ASSERT_EQUALS((g_address) 0x05000000, splinter1->baseAddress); - ASSERT_EQUALS((uint32_t) (((0x0A000000 - 0x05000000) / G_PAGE_SIZE) / G_BITMAP_PAGES_PER_ENTRY), splinter1->entryCount); - ASSERT_EQUALS(true, splinter1->hasNext); - - g_bitmap_header* splinter2 = G_BITMAP_NEXT(splinter1); - ASSERT_EQUALS((g_address*) 0x0A000000, (g_address*) splinter2->baseAddress); - ASSERT_EQUALS((uint32_t) (((0x0C000000 - 0x0A000000) / G_PAGE_SIZE) / G_BITMAP_PAGES_PER_ENTRY), splinter2->entryCount); - ASSERT_EQUALS(false, splinter2->hasNext); - - free(bitmapMemory); - free(mmap); - free(setupInformation.multibootInformation); -} - -TEST(memoryPhysicalReadMemoryMapTwoEntries, "Read memory map with two entries") -{ - setupInformation.multibootInformation = malloc(sizeof(g_multiboot_information)); - - uint32_t mmapLength = (sizeof(g_multiboot_mmap) + sizeof(uint32_t)) * 2; - void* mmap = malloc(mmapLength); - - g_multiboot_mmap* mmap1 = (g_multiboot_mmap*) mmap; - mmap1->size = sizeof(g_multiboot_mmap); - mmap1->baseAddress = 0x00100000; - mmap1->length = 0x0BF00000; // 0x00100000 - 0x0C000000 - mmap1->type = G_MULTIBOOT_MMAP_TYPE_FREE; - - g_multiboot_mmap* mmap2 = (g_multiboot_mmap*) ((g_address) mmap + mmap1->size + sizeof(uint32_t)); - mmap2->size = sizeof(g_multiboot_mmap); - mmap2->baseAddress = 0x2A000000; - mmap2->length = 0x10000000; // 0x2A000000 - 0x3A000000 - mmap2->type = G_MULTIBOOT_MMAP_TYPE_FREE; - - setupInformation.multibootInformation->memoryMap = mmap1; - setupInformation.multibootInformation->memoryMapLength = mmapLength; - setupInformation.multibootInformation->flags |= G_MULTIBOOT_FLAGS_MMAP; - - uint32_t required = memoryPhysicalReadMemoryMap(0x05000000, 0); - - void* bitmapMemory = malloc(required); - - uint32_t requiredAfter = memoryPhysicalReadMemoryMap(0x05000000, bitmapMemory); - ASSERT_EQUALS(required, requiredAfter); - - // Bitmap creates 6 splinters since the range is larger than G_BITMAP_MAX_RANGE - g_bitmap_header* splinter1 = (g_bitmap_header*) bitmapMemory; - ASSERT_EQUALS((g_address) 0x05000000, splinter1->baseAddress); - ASSERT_EQUALS((uint32_t) (((0x0A000000 - 0x05000000) / G_PAGE_SIZE) / G_BITMAP_PAGES_PER_ENTRY), splinter1->entryCount); - ASSERT_EQUALS(true, splinter1->hasNext); - - g_bitmap_header* splinter2 = G_BITMAP_NEXT(splinter1); - ASSERT_EQUALS((g_address*) 0x0A000000, (g_address*) splinter2->baseAddress); - ASSERT_EQUALS((uint32_t) (((0x0C000000 - 0x0A000000) / G_PAGE_SIZE) / G_BITMAP_PAGES_PER_ENTRY), splinter2->entryCount); - ASSERT_EQUALS(true, splinter2->hasNext); - - g_bitmap_header* splinter3 = G_BITMAP_NEXT(splinter2); - ASSERT_EQUALS((g_address*) 0x2A000000, (g_address*) splinter3->baseAddress); - ASSERT_EQUALS((uint32_t) (((0x2F000000 - 0x2A000000) / G_PAGE_SIZE) / G_BITMAP_PAGES_PER_ENTRY), splinter3->entryCount); - ASSERT_EQUALS(true, splinter3->hasNext); - - g_bitmap_header* splinter4 = G_BITMAP_NEXT(splinter3); - ASSERT_EQUALS((g_address*) 0x2F000000, (g_address*) splinter4->baseAddress); - ASSERT_EQUALS((uint32_t) (((0x34000000 - 0x2F000000) / G_PAGE_SIZE) / G_BITMAP_PAGES_PER_ENTRY), splinter4->entryCount); - ASSERT_EQUALS(true, splinter4->hasNext); - - g_bitmap_header* splinter5 = G_BITMAP_NEXT(splinter4); - ASSERT_EQUALS((g_address*) 0x34000000, (g_address*) splinter5->baseAddress); - ASSERT_EQUALS((uint32_t) (((0x39000000 - 0x34000000) / G_PAGE_SIZE) / G_BITMAP_PAGES_PER_ENTRY), splinter5->entryCount); - ASSERT_EQUALS(true, splinter5->hasNext); - - g_bitmap_header* splinter6 = G_BITMAP_NEXT(splinter5); - ASSERT_EQUALS((g_address*) 0x39000000, (g_address*) splinter6->baseAddress); - ASSERT_EQUALS((uint32_t) (((0x3A000000 - 0x39000000) / G_PAGE_SIZE) / G_BITMAP_PAGES_PER_ENTRY), splinter6->entryCount); - ASSERT_EQUALS(false, splinter6->hasNext); - - free(bitmapMemory); - free(mmap); - free(setupInformation.multibootInformation); -} diff --git a/kernel/src/test/shared/memory/bitmap_page_allocator.cpp b/kernel/src/test/shared/memory/bitmap_page_allocator.cpp deleted file mode 100644 index 697994d2..00000000 --- a/kernel/src/test/shared/memory/bitmap_page_allocator.cpp +++ /dev/null @@ -1,153 +0,0 @@ -#include "test/test.hpp" -#include -#include -#include - -// Test unit -#include "shared/memory/bitmap_page_allocator.cpp" - -TEST(bitmapPageAllocator, "Simple single-bitmap test") -{ - // Means memory range of 0x80000 - uint32_t entryCount = 16; - void* bitmapArray = malloc((sizeof(g_bitmap_header) + sizeof(g_bitmap_entry) * entryCount) * 1); - - g_bitmap_header* bitmap1 = (g_bitmap_header*) bitmapArray; - bitmap1->baseAddress = 0x10000000; - bitmap1->entryCount = entryCount; - bitmap1->hasNext = false; - - g_bitmap_page_allocator allocator; - bitmapPageAllocatorInitialize(&allocator, (g_bitmap_header*) bitmapArray); - - g_bitmap_entry* entries1 = (g_bitmap_entry*) ((g_address) bitmap1 + sizeof(g_bitmap_header)); - for(uint32_t i = 0; i < entryCount; i++) - entries1[i] = 0b11111111; - - // Mark some pages as free and expect to get them back - entries1[2] = 0b11110111; - entries1[15] = 0b01111111; - - ASSERT_EQUALS((void*) 0x10013000ul, (void*) bitmapPageAllocatorAllocate(&allocator)); - ASSERT_EQUALS((void*) 0x1007f000ul, (void*) bitmapPageAllocatorAllocate(&allocator)); - - for(uint32_t i = 0; i < entryCount; i++) - { - ASSERT_EQUALS((uint8_t) 0b11111111, entries1[i]); - } - - // Free a valid and an invalid address - bitmapPageAllocatorMarkFree(&allocator, 0x10051000ul); - bitmapPageAllocatorMarkFree(&allocator, 0x20000000ul); - - for(uint32_t i = 0; i < entryCount; i++) - { - if(i == 10) - ASSERT_EQUALS((uint8_t) 0b11111101, entries1[10]); - else - ASSERT_EQUALS((uint8_t) 0b11111111, entries1[i]); - } - - free(bitmapArray); -} - -TEST(bitmapPageAllocatorMultiple, "Multiple-bitmap test") -{ - // Means memory range of 0x80000 - uint32_t entryCount = 16; - void* bitmapArray = malloc((sizeof(g_bitmap_header) + sizeof(g_bitmap_entry) * entryCount) * 2); - - g_bitmap_header* bitmap1 = (g_bitmap_header*) bitmapArray; - bitmap1->baseAddress = 0x10000000; - bitmap1->entryCount = entryCount; - bitmap1->hasNext = true; - - g_bitmap_header* bitmap2 = G_BITMAP_NEXT(bitmap1); - bitmap2->baseAddress = 0x4A000000; - bitmap2->entryCount = entryCount; - bitmap2->hasNext = false; - - g_bitmap_page_allocator allocator; - bitmapPageAllocatorInitialize(&allocator, (g_bitmap_header*) bitmapArray); - - g_bitmap_entry* entries1 = (g_bitmap_entry*) ((g_address) bitmap1 + sizeof(g_bitmap_header)); - for(uint32_t i = 0; i < entryCount; i++) - entries1[i] = 0b11111111; - - g_bitmap_entry* entries2 = (g_bitmap_entry*) ((g_address) bitmap2 + sizeof(g_bitmap_header)); - for(uint32_t i = 0; i < entryCount; i++) - entries2[i] = 0b11111111; - - // Mark some pages as free and expect to get them back - entries1[5] = 0b10111111; - entries2[4] = 0b01111111; - - ASSERT_EQUALS((void*) 0x1002e000ul, (void*) bitmapPageAllocatorAllocate(&allocator)); - ASSERT_EQUALS((void*) 0x4a027000ul, (void*) bitmapPageAllocatorAllocate(&allocator)); - - for(uint32_t i = 0; i < entryCount; i++) - ASSERT_EQUALS((uint8_t) 0b11111111, entries1[i]); - - for(uint32_t i = 0; i < entryCount; i++) - ASSERT_EQUALS((uint8_t) 0b11111111, entries2[i]); - - free(bitmapArray); -} - -TEST(bitmapMacros, "Ensure macros calculate what we expect") -{ - { - g_bitmap_header* first = malloc(sizeof(g_bitmap_header)); - first->entryCount = 5; - - g_bitmap_header* next = G_BITMAP_NEXT_UNCHECKED(first); - ASSERT_EQUALS((g_bitmap_header*) (((g_address) first) + sizeof(g_bitmap_header) + 5 * sizeof(g_bitmap_entry)), next); - - free(first); - } - { - g_bitmap_header* first = malloc(sizeof(g_bitmap_header)); - first->entryCount = 5; - first->hasNext = false; - - g_bitmap_header* next = G_BITMAP_NEXT(first); - ASSERT_EQUALS((g_bitmap_header*) nullptr, next); - - free(first); - } - { - g_bitmap_header* first = malloc(sizeof(g_bitmap_header)); - first->entryCount = 5; - first->hasNext = true; - - g_bitmap_header* next = G_BITMAP_NEXT(first); - ASSERT_EQUALS((g_bitmap_header*) (((g_address) first) + sizeof(g_bitmap_header) + 5 * sizeof(g_bitmap_entry)), next); - - free(first); - } - { - ASSERT_EQUALS(0lu, G_OFFSET_TO_BITMAP_INDEX(0x0000)); - ASSERT_EQUALS(0lu, G_OFFSET_TO_BITMAP_BIT(0x0000)); - ASSERT_EQUALS(0x0000lu, G_BITMAP_TO_OFFSET(0, 0)); - - ASSERT_EQUALS(0lu, G_OFFSET_TO_BITMAP_INDEX(0x1000)); - ASSERT_EQUALS(1lu, G_OFFSET_TO_BITMAP_BIT(0x1000)); - ASSERT_EQUALS(0x1000lu, G_BITMAP_TO_OFFSET(0, 1)); - - ASSERT_EQUALS(0lu, G_OFFSET_TO_BITMAP_INDEX(0x7000)); - ASSERT_EQUALS(7lu, G_OFFSET_TO_BITMAP_BIT(0x7000)); - ASSERT_EQUALS(0x7000lu, G_BITMAP_TO_OFFSET(0, 7)); - - ASSERT_EQUALS(1lu, G_OFFSET_TO_BITMAP_INDEX(0x8000)); - ASSERT_EQUALS(0lu, G_OFFSET_TO_BITMAP_BIT(0x8000)); - ASSERT_EQUALS(0x8000lu, G_BITMAP_TO_OFFSET(1, 0)); - - ASSERT_EQUALS(1lu, G_OFFSET_TO_BITMAP_INDEX(0xF000)); - ASSERT_EQUALS(7lu, G_OFFSET_TO_BITMAP_BIT(0xF000)); - ASSERT_EQUALS(0xF000lu, G_BITMAP_TO_OFFSET(1, 7)); - - ASSERT_EQUALS(2lu, G_OFFSET_TO_BITMAP_INDEX(0x10000)); - ASSERT_EQUALS(0lu, G_OFFSET_TO_BITMAP_BIT(0x10000)); - ASSERT_EQUALS(0x10000lu, G_BITMAP_TO_OFFSET(2, 0)); - } -} diff --git a/kernel/src/test/test.cpp b/kernel/src/test/test.cpp deleted file mode 100644 index 25bfdcb2..00000000 --- a/kernel/src/test/test.cpp +++ /dev/null @@ -1,62 +0,0 @@ -#include "test/test.hpp" -#include -#include -#include - -struct test_t -{ - bool (*test)(); - const char* name; - test_t* next; -}; - -test_t* tests = 0; - -void testAdd(const char* name, bool (*func)()) -{ - test_t* n = (test_t*) malloc(sizeof(test_t)); - n->test = func; - n->next = tests; - n->name = name; - tests = n; -} - -int main(int argc, const char** argv) -{ - const char* only = nullptr; - if(argc == 2) - { - only = argv[1]; - } - - for(test_t* test = tests; test; test = test->next) - { - if(only != nullptr && strstr(test->name, only) != test->name) - continue; - - printf("%s", test->name); - try - { - test->test(); - printf(" \e[1;92m✓\e[0m\n"); - } - catch(const char* e) - { - printf(" \e[1;31m❌\e[0m\n"); - printf(" %s\n", e); - } - } -} - -void _panic(int line, const char* msg, ...) -{ - char buf1[BUFLEN]; - va_list valist; - va_start(valist, msg); - vsnprintf(buf1, BUFLEN, msg, valist); - va_end(valist); - - char buf2[BUFLEN]; - snprintf(buf2, BUFLEN, "\t%i: panic: %s", line, buf1); - throw buf2; -} diff --git a/kernel/src/test/test.hpp b/kernel/src/test/test.hpp deleted file mode 100644 index bb42a7af..00000000 --- a/kernel/src/test/test.hpp +++ /dev/null @@ -1,90 +0,0 @@ -#ifndef __TEST__ -#define __TEST__ - -#include -#include - -void testAdd(const char* name, bool (*func)()); - -#define TEST(name, description) \ - bool name(); \ - class name##TestAdder \ - { \ - public: \ - name##TestAdder() \ - { \ - testAdd(#name, name); \ - } \ - }; \ - name##TestAdder name##Adder; \ - bool name() - -#define TOKENPASTE(x, y) x##y -#define TOKENPASTE2(x, y) TOKENPASTE(x, y) -#define MOCK(name) TOKENPASTE2(name, __COUNTER__) - -// Assert and panic calls -#define ASSERT_EQUALS(a, b) assertEquals<>(a, b, __LINE__) -#define ASSERT_NOT_EQUALS(a, b) assertNotEquals<>(a, b, __LINE__) - -#define BUFLEN 512 - -template -void assertEquals(T a, T b, int line) -{ - if(a != b) - { - char buf[BUFLEN]; - snprintf(buf, BUFLEN, "\t%i: assertion failed: expected %lli, got %lli\n", line, a, b); - throw buf; - } -} - -template -void assertEquals(T* a, T* b, int line) -{ - if(a != b) - { - char buf[BUFLEN]; - snprintf(buf, BUFLEN, "\t%i: assertion failed: expected %llx, got %llx\n", line, a, b); - throw buf; - } -} - -template -void assertNotEquals(T a, T b, int line) -{ - if(a == b) - { - char buf[BUFLEN]; - snprintf(buf, BUFLEN, "\t%i: assertion failed: expected not %lli, got %lli\n", line, a, b); - throw buf; - } -} - -void _panic(int line, const char* msg, ...); - -// Mock overrides -#define mutexInitialize(m, ...) -#define _mutexInitialize(m) -#define mutexAcquire(m) -#define mutexRelease(m) - -#define __GHOST_SYS_TYPES__ -#define __GHOST_SYS_TYPES__ -typedef uintptr_t g_address; -typedef g_address g_virtual_address; -typedef g_address g_physical_address; - -#define __PANIC__ -#define panic(msg...) _panic(__LINE__, msg); - -#define __LOGGER__ -#define logInfo(msg...) -#define logInfon(msg...) -#define logWarn(msg...) -#define logWarnn(msg...) -#define logDebug(msg...) -#define logDebugn(msg...) - -#endif diff --git a/libapi/inc/ghost/elf64.h b/libapi/inc/ghost/elf64.h index 7fb7efe2..6423fd60 100644 --- a/libapi/inc/ghost/elf64.h +++ b/libapi/inc/ghost/elf64.h @@ -28,14 +28,14 @@ __BEGIN_C /** * ELF64 types - */ -typedef uint32_t Elf64_Addr; +*/ +typedef uint64_t Elf64_Addr; +typedef uint64_t Elf64_Off; typedef uint16_t Elf64_Half; -typedef uint32_t Elf64_Off; -typedef int32_t Elf64_Sword; typedef uint32_t Elf64_Word; -typedef int64_t Elf64_Sxword; +typedef int32_t Elf64_Sword; typedef uint64_t Elf64_Xword; +typedef int64_t Elf64_Sxword; /** * Ident header @@ -55,14 +55,16 @@ typedef uint64_t Elf64_Xword; #define ELFMAG2 'L' #define ELFMAG3 'F' -#define ELFCLASSNONE 0 #define ELFCLASS32 1 #define ELFCLASS64 2 -#define ELFDATANONE 0 #define ELFDATA2LSB 1 #define ELFDATA2MSB 2 +#define ELFOSABI_SYSV 0 +#define ELFOSABI_HPUX 1 +#define ELFOSABI_STANDALONE 255 + /** * ELF header */ @@ -71,6 +73,8 @@ typedef uint64_t Elf64_Xword; #define ET_EXEC 2 #define ET_DYN 3 #define ET_CORE 4 +#define ET_LOOS 0xFE00 +#define ET_HIOS 0xFEFF #define ET_LOPROC 0xFF00 #define ET_HIPROC 0xFFFF @@ -82,6 +86,7 @@ typedef uint64_t Elf64_Xword; #define EM_88K 5 #define EM_860 6 #define EM_MIPS 8 +#define EM_X86_64 62 #define EV_NONE 0 #define EV_CURRENT 1 @@ -127,13 +132,13 @@ typedef struct typedef struct { Elf64_Word p_type; // Type of the segment + Elf64_Word p_flags; // Segment flags Elf64_Off p_offset; // Offset of the segment in the binary file Elf64_Addr p_vaddr; // Virtual address Elf64_Addr p_paddr; // Not relevant for System V - Elf64_Word p_filesz; // Size of the segment in the binary file - Elf64_Word p_memsz; // Size of the segment in memory - Elf64_Word p_flags; // Segment flags - Elf64_Word p_align; // Alignment information + Elf64_Xword p_filesz; // Size of the segment in the binary file + Elf64_Xword p_memsz; // Size of the segment in memory + Elf64_Xword p_align; // Alignment information } __attribute__((packed)) Elf64_Phdr; /** @@ -141,10 +146,10 @@ typedef struct */ typedef struct { - Elf64_Sword d_tag; // Controls interpretation of d_un, see DT_* + Elf64_Sxword d_tag; // Controls interpretation of d_un, see DT_* union { - Elf64_Word d_val; + Elf64_Xword d_val; Elf64_Addr d_ptr; } d_un; } __attribute__((packed)) Elf64_Dyn; @@ -195,11 +200,11 @@ typedef struct typedef struct { Elf64_Word st_name; // Index to symbol string name - Elf64_Addr st_value; // Value of associated symbol - Elf64_Word st_size; // Size of the symbol uint8_t st_info; // Type and binding attributes - uint8_t st_other; // Undefined + uint8_t st_other; // Visibility Elf64_Half st_shndx; // Section header table index + Elf64_Addr st_value; // Value of associated symbol + Elf64_Xword st_size; // Size of the symbol } Elf64_Sym; #define ELF64_ST_BIND(i) ((i) >> 4) @@ -229,14 +234,14 @@ typedef struct { Elf64_Word sh_name; Elf64_Word sh_type; - Elf64_Word sh_flags; + Elf64_Xword sh_flags; Elf64_Addr sh_addr; Elf64_Off sh_offset; - Elf64_Word sh_size; + Elf64_Xword sh_size; Elf64_Word sh_link; Elf64_Word sh_info; - Elf64_Word sh_addralign; - Elf64_Word sh_entsize; + Elf64_Xword sh_addralign; + Elf64_Xword sh_entsize; } Elf64_Shdr; #define SHT_NULL 0 @@ -251,6 +256,8 @@ typedef struct #define SHT_REL 9 #define SHT_SHLIB 10 #define SHT_DYNSYM 11 +#define SHT_LOOS 0x60000000 +#define SHT_HIOS 0x6fffffff #define SHT_LOPROC 0x70000000 #define SHT_HIPROC 0x7fffffff #define SHT_LOUSER 0x80000000 @@ -262,13 +269,13 @@ typedef struct typedef struct { Elf64_Addr r_offset; - Elf64_Word r_info; + Elf64_Xword r_info; } Elf64_Rel; typedef struct { Elf64_Addr r_offset; - Elf64_Word r_info; + Elf64_Xword r_info; Elf64_Sxword r_addend; } Elf64_Rela; @@ -276,32 +283,49 @@ typedef struct #define ELF64_R_TYPE(i) ((i) & 0xFFFFFFFFL) #define ELF64_R_INFO(s, t) (((s) << 32) + ((t) & 0xFFFFFFFFL)) -#define R_X86_64_NONE 0 -#define R_X86_64_64 1 -#define R_X86_64_PC32 2 -#define R_X86_64_GOT32 3 -#define R_X86_64_PLT32 4 -#define R_X86_64_COPY 5 -#define R_X86_64_GLOB_DAT 6 -#define R_X86_64_JMP_SLOT 7 -#define R_X86_64_RELATIVE 8 -#define R_X86_64_GOTPCREL 9 -#define R_X86_64_32 10 -#define R_X86_64_32S 11 - -// Thread-local storage related relocation types -// TODO Check these -#define R_X86_64_TLS_GD_PLT 12 -#define R_X86_64_TLS_LDM_PLT 13 -#define R_X86_64_TLS_TPOFF 14 -#define R_X86_64_TLS_IE 15 -#define R_X86_64_TLS_GOTIE 16 -#define R_X86_64_TLS_LE 17 -#define R_X86_64_TLS_GD 18 -#define R_X86_64_TLS_LDM 19 -#define R_X86_64_TLS_LDO_32 32 -#define R_X86_64_TLS_DTPMOD32 35 -#define R_X86_64_TLS_DTPOFF32 36 + +#define R_X86_64_NONE 0 +#define R_X86_64_64 1 +#define R_X86_64_PC32 2 +#define R_X86_64_GOT32 3 +#define R_X86_64_PLT32 4 +#define R_X86_64_COPY 5 +#define R_X86_64_GLOB_DAT 6 +#define R_X86_64_JUMP_SLOT 7 +#define R_X86_64_RELATIVE 8 +#define R_X86_64_GOTPCREL 9 +#define R_X86_64_32 10 +#define R_X86_64_32S 11 + +#define R_X86_64_16 12 +#define R_X86_64_PC16 13 +#define R_X86_64_8 14 +#define R_X86_64_PC8 15 + +#define R_X86_64_DTPMOD64 16 +#define R_X86_64_DTPOFF64 17 +#define R_X86_64_TPOFF64 18 +#define R_X86_64_TLSGD 19 +#define R_X86_64_TLSLD 20 +#define R_X86_64_DTPOFF32 21 +#define R_X86_64_GOTTPOFF 22 +#define R_X86_64_TPOFF32 23 +#define R_X86_64_PC64 24 +#define R_X86_64_GOTOFF64 25 +#define R_X86_64_GOTPC32 26 +#define R_X86_64_GOT64 27 +#define R_X86_64_GOTPCREL64 28 +#define R_X86_64_GOTPC64 29 +#define R_X86_64_GOTPLT64 30 +#define R_X86_64_PLTOFF64 31 +#define R_X86_64_SIZE32 32 +#define R_X86_64_SIZE64 33 +#define R_X86_64_GOTPC32_TLSDESC 34 +#define R_X86_64_TLSDESC_CALL 35 +#define R_X86_64_TLSDESC 36 +#define R_X86_64_IRELATIVE 37 +#define R_X86_64_RELATIVE64 38 +#define R_X86_64_NUM 39 __END_C diff --git a/libapi/inc/ghost/memory/types.h b/libapi/inc/ghost/memory/types.h index d8fea349..970821bc 100644 --- a/libapi/inc/ghost/memory/types.h +++ b/libapi/inc/ghost/memory/types.h @@ -65,7 +65,8 @@ typedef g_address g_size; #define G_FP_TO_LINEAR(fp) G_SEGOFF_TO_LINEAR(G_FP_SEG(fp), G_FP_OFF(fp)) #define G_SEGOFF_TO_FP(seg, off) ((g_far_pointer) (((seg & 0xFFFF) << 16) | (off & 0xFFFF))) -#define G_LINEAR_TO_FP(linear) ((linear > 0x100000) ? 0 : ((((linear >> 4) & 0xFFFF) << 16) + (linear & 0xFL))) +#define G_LINEAR_TO_FP(linear) (((((linear) / 16) & 0xFFFF) << 16) | ((linear) % 16)) + __END_C diff --git a/libapi/inc/ghost/syscall/definitions.h b/libapi/inc/ghost/syscall/definitions.h index 6c9656e2..63845b58 100644 --- a/libapi/inc/ghost/syscall/definitions.h +++ b/libapi/inc/ghost/syscall/definitions.h @@ -102,6 +102,7 @@ __BEGIN_C #define G_SYSCALL_TEST 123 #define G_SYSCALL_IRQ_CREATE_REDIRECT 124 #define G_SYSCALL_AWAIT_IRQ 125 +#define G_SYSCALL_GET_EFI_FRAMEBUFFER 126 // Kernquery #define G_SYSCALL_KERNQUERY 129 diff --git a/libapi/inc/ghost/system.h b/libapi/inc/ghost/system.h index 835d0ea8..c66e59a6 100644 --- a/libapi/inc/ghost/system.h +++ b/libapi/inc/ghost/system.h @@ -24,6 +24,7 @@ #include "common.h" #include "stdint.h" #include "system/types.h" +#include "memory/types.h" __BEGIN_C // not implemented warning @@ -102,6 +103,13 @@ void g_io_port_write_byte(uint16_t port, uint8_t data); void g_io_port_write_word(uint16_t port, uint16_t data); void g_io_port_write_dword(uint16_t port, uint32_t data); +/** + * Ask the kernel for the EFI framebuffer data. + * + * @security-level DRIVER + */ +void g_get_efi_framebuffer(g_address* outFramebuffer, uint16_t* outWidth, uint16_t* outHeight, uint16_t* outBpp, uint32_t* outPitch); + __END_C #endif diff --git a/libapi/inc/ghost/system/callstructs.h b/libapi/inc/ghost/system/callstructs.h index 66156bf0..cf59c2b0 100644 --- a/libapi/inc/ghost/system/callstructs.h +++ b/libapi/inc/ghost/system/callstructs.h @@ -42,11 +42,11 @@ __BEGIN_C */ typedef struct { - uint32_t interrupt; - g_vm86_registers in; - g_vm86_registers* out; + uint32_t interrupt; + g_vm86_registers in; + g_vm86_registers* out; - g_vm86_call_status status; + g_vm86_call_status status; }__attribute__((packed)) g_syscall_call_vm86; @@ -56,7 +56,7 @@ typedef struct */ typedef struct { - char* message; + char* message; }__attribute__((packed)) g_syscall_log; /** @@ -65,7 +65,7 @@ typedef struct */ typedef struct { - uint8_t enabled; + uint8_t enabled; }__attribute__((packed)) g_syscall_set_video_log; /** @@ -77,9 +77,9 @@ typedef struct */ typedef struct { - uint32_t test; + uint32_t test; - uint32_t result; + uint32_t result; }__attribute__((packed)) g_syscall_test; /** @@ -87,8 +87,8 @@ typedef struct */ typedef struct { - uint32_t source; - uint32_t irq; + uint32_t source; + uint32_t irq; } __attribute__((packed)) g_syscall_irq_create_redirect; /** @@ -99,10 +99,31 @@ typedef struct */ typedef struct { - uint8_t irq; - uint32_t timeout; + uint8_t irq; + uint32_t timeout; } __attribute__((packed)) g_syscall_await_irq; +/** + * @field address + * framebuffer address + * @field width +* framebuffer width + * @field height +* framebuffer height + * @field bpp +* framebuffer bpp + * @field pitch + * framebuffer pitch + */ +typedef struct +{ + g_address address; + uint16_t width; + uint16_t height; + uint16_t bpp; + uint32_t pitch; +} __attribute__((packed)) g_syscall_get_efi_framebuffer; + __END_C #endif diff --git a/libapi/inc/ghost/tasks/types.h b/libapi/inc/ghost/tasks/types.h index 66a103d5..e084e6c3 100644 --- a/libapi/inc/ghost/tasks/types.h +++ b/libapi/inc/ghost/tasks/types.h @@ -51,7 +51,7 @@ typedef uint8_t g_security_level; */ typedef struct _g_user_threadlocal { - struct _g_user_threadlocal* self; + struct _g_user_threadlocal* self; } g_user_threadlocal; /** @@ -102,16 +102,16 @@ typedef uint8_t g_create_task_status; */ typedef struct _g_object_info { - const char* name; - - void (*init)(void); - void (*fini)(void); - void (**preinitArray)(void); - uint32_t preinitArraySize; - void (**initArray)(void); - uint32_t initArraySize; - void (**finiArray)(void); - uint32_t finiArraySize; + const char* name; + + void (*init)(void); + void (*fini)(void); + void (**preinitArray)(void); + uint32_t preinitArraySize; + void (**initArray)(void); + uint32_t initArraySize; + void (**finiArray)(void); + uint32_t finiArraySize; } __attribute__((packed)) g_object_info; /** @@ -120,17 +120,17 @@ typedef struct _g_object_info */ typedef struct { - /** - * Information about all loaded ELF objects. - */ - g_object_info* objectInfos; - uint32_t objectInfosSize; - - /** - * Provides a pointer to the "syscall" function of the kernel, required when attempting - * to use a system call while within a user-space interrupt service routine. - */ - void (*syscallKernelEntry)(uint32_t, void*); + /** + * Information about all loaded ELF objects. + */ + g_object_info* objectInfos; + uint32_t objectInfosSize; + + /** + * Provides a pointer to the "syscall" function of the kernel, required when attempting + * to use a system call while within a user-space interrupt service routine. + */ + void (*syscallKernelEntry)(uint32_t, void*); } __attribute__((packed)) g_process_info; /** @@ -161,40 +161,40 @@ typedef uint8_t g_spawn_status; typedef uint8_t g_spawn_validation_details; #define G_SPAWN_VALIDATION_SUCCESSFUL ((g_spawn_validation_details) 0) -#define G_SPAWN_VALIDATION_ELF32_NOT_ELF ((g_spawn_validation_details) 1) -#define G_SPAWN_VALIDATION_ELF32_NOT_EXECUTABLE ((g_spawn_validation_details) 2) -#define G_SPAWN_VALIDATION_ELF32_NOT_I386 ((g_spawn_validation_details) 3) -#define G_SPAWN_VALIDATION_ELF32_NOT_32BIT ((g_spawn_validation_details) 4) -#define G_SPAWN_VALIDATION_ELF32_NOT_LITTLE_ENDIAN ((g_spawn_validation_details) 5) -#define G_SPAWN_VALIDATION_ELF32_NOT_STANDARD_ELF ((g_spawn_validation_details) 6) -#define G_SPAWN_VALIDATION_ELF32_IO_ERROR ((g_spawn_validation_details) 7) +#define G_SPAWN_VALIDATION_ELF_NOT_ELF ((g_spawn_validation_details) 1) +#define G_SPAWN_VALIDATION_ELF_NOT_EXECUTABLE ((g_spawn_validation_details) 2) +#define G_SPAWN_VALIDATION_ELF_NOT_I386 ((g_spawn_validation_details) 3) +#define G_SPAWN_VALIDATION_ELF_NOT_64BIT ((g_spawn_validation_details) 4) +#define G_SPAWN_VALIDATION_ELF_NOT_LITTLE_ENDIAN ((g_spawn_validation_details) 5) +#define G_SPAWN_VALIDATION_ELF_NOT_STANDARD_ELF ((g_spawn_validation_details) 6) +#define G_SPAWN_VALIDATION_ELF_IO_ERROR ((g_spawn_validation_details) 7) // command structs typedef struct { - int command; + int command; }__attribute__((packed)) g_spawn_command_header; typedef struct { - g_spawn_command_header header; - g_security_level security_level; - size_t path_bytes; - size_t args_bytes; - size_t workdir_bytes; - g_fd stdin; - g_fd stdout; - g_fd stderr; - // followed by: path, args, workdir + g_spawn_command_header header; + g_security_level security_level; + size_t path_bytes; + size_t args_bytes; + size_t workdir_bytes; + g_fd stdin; + g_fd stdout; + g_fd stderr; + // followed by: path, args, workdir }__attribute__((packed)) g_spawn_command_spawn_request; typedef struct { - g_spawn_status status; - g_pid spawned_process_id; - g_fd stdin_write; - g_fd stdout_read; - g_fd stderr_read; + g_spawn_status status; + g_pid spawned_process_id; + g_fd stdin_write; + g_fd stdout_read; + g_fd stderr_read; }__attribute__((packed)) g_spawn_command_spawn_response; // process configuration buffer lengths diff --git a/libapi/src/syscall/g_syscall.cpp b/libapi/src/syscall/g_syscall.cpp index 15e6a370..7a52bae4 100644 --- a/libapi/src/syscall/g_syscall.cpp +++ b/libapi/src/syscall/g_syscall.cpp @@ -22,8 +22,9 @@ void g_syscall(uint32_t call, g_address data) { - asm volatile("int $0x80" - : - : "a"(call), "b"(data) - : "cc", "memory"); + asm volatile ( + "int $0x80" + :: "a" (call), "D" (data) + : "memory" + ); } diff --git a/libapi/src/system/g_get_efi_framebuffer.cpp b/libapi/src/system/g_get_efi_framebuffer.cpp new file mode 100644 index 00000000..34d5e148 --- /dev/null +++ b/libapi/src/system/g_get_efi_framebuffer.cpp @@ -0,0 +1,39 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * * + * Ghost, a micro-kernel based operating system for the x86 architecture * + * Copyright (C) 2015, Max Schlüssel * + * * + * This program 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. * + * * + * This program 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 this program. If not, see . * + * * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#include "ghost/syscall.h" +#include "ghost/system.h" +#include "ghost/system/callstructs.h" + +/** + * + */ +void g_get_efi_framebuffer(g_address* outFramebuffer, uint16_t* outWidth, uint16_t* outHeight, uint16_t* outBpp, uint32_t* outPitch) +{ + g_syscall_get_efi_framebuffer data; + + g_syscall(G_SYSCALL_GET_EFI_FRAMEBUFFER, (g_address) &data); + + *outFramebuffer = data.address; + *outWidth = data.width; + *outHeight = data.height; + *outBpp = data.bpp; + *outPitch = data.pitch; +} diff --git a/libc/crt/x86_64/crt0.S b/libc/crt/x86_64/crt0.S index 9121769d..e94922e9 100644 --- a/libc/crt/x86_64/crt0.S +++ b/libc/crt/x86_64/crt0.S @@ -27,7 +27,9 @@ # The <_start> function is where the kernel starts the execution. _start: - call __g_main + xorq %rbp, %rbp + andq $-16, %rsp + call __g_main # Endless loop, for the case that bad things happen wait: diff --git a/libc/src/setjmp/i386/longjmp.s b/libc/src/setjmp/i386/longjmp.s index 94393686..495c949d 100644 --- a/libc/src/setjmp/i386/longjmp.s +++ b/libc/src/setjmp/i386/longjmp.s @@ -1,36 +1,16 @@ -#* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * -#* * -#* Ghost, a micro-kernel based operating system for the x86 architecture * -#* Copyright (C) 2015, Max Schlüssel * -#* * -#* This program 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. * -#* * -#* This program 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 this program. If not, see . * -#* * -#* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -.global __longjmp -.global _longjmp .global longjmp -.type __longjmp,@function -.type _longjmp,@function -.type longjmp,@function +.global _longjmp +.global __longjmp +.type longjmp, @function +.type _longjmp, @function +.type __longjmp, @function # # void longjmp(jmp_buf env, int val) # -__longjmp: -_longjmp: longjmp: +_longjmp: +__longjmp: mov 4(%esp), %edx mov 8(%esp), %eax test %eax, %eax diff --git a/libc/src/setjmp/i386/setjmp.s b/libc/src/setjmp/i386/setjmp.s index e5455931..2b9353ea 100644 --- a/libc/src/setjmp/i386/setjmp.s +++ b/libc/src/setjmp/i386/setjmp.s @@ -1,36 +1,16 @@ -#* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * -#* * -#* Ghost, a micro-kernel based operating system for the x86 architecture * -#* Copyright (C) 2015, Max Schlüssel * -#* * -#* This program 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. * -#* * -#* This program 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 this program. If not, see . * -#* * -#* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -.global __setjmp -.global _setjmp .global setjmp -.type __setjmp,@function -.type _setjmp,@function -.type setjmp,@function +.global _setjmp +.global __setjmp +.type setjmp, @function +.type _setjmp, @function +.type __setjmp, @function # # int setjmp(jmp_buf env) # -__setjmp: -_setjmp: setjmp: +_setjmp: +__setjmp: mov 4(%esp), %eax mov %ebx, (%eax) mov %esi, 4(%eax) diff --git a/libc/src/setjmp/x86_64/longjmp.s b/libc/src/setjmp/x86_64/longjmp.s new file mode 100644 index 00000000..5328168f --- /dev/null +++ b/libc/src/setjmp/x86_64/longjmp.s @@ -0,0 +1,21 @@ +.global longjmp +.global _longjmp +.type longjmp, @function +.type _longjmp, @function + +# +# void longjmp(jmp_buf env, int val) +# +longjmp: +_longjmp: + xor %eax, %eax + cmp $1, %esi + adc %esi, %eax + mov (%rdi), %rbx + mov 8(%rdi), %rbp + mov 16(%rdi), %r12 + mov 24(%rdi), %r13 + mov 32(%rdi), %r14 + mov 40(%rdi), %r15 + mov 48(%rdi), %rsp + jmp *56(%rdi) diff --git a/libc/src/setjmp/x86_64/setjmp.s b/libc/src/setjmp/x86_64/setjmp.s new file mode 100644 index 00000000..a971c766 --- /dev/null +++ b/libc/src/setjmp/x86_64/setjmp.s @@ -0,0 +1,25 @@ +.global setjmp +.global _setjmp +.global __setjmp +.type setjmp, @function +.type _setjmp, @function +.type __setjmp, @function + +# +# int setjmp(jmp_buf env) +# +setjmp: +_setjmp: +__setjmp: + mov %rbx, (%rdi) + mov %rbp, 8(%rdi) + mov %r12, 16(%rdi) + mov %r13, 24(%rdi) + mov %r14, 32(%rdi) + mov %r15, 40(%rdi) + lea 8(%rsp), %rdx + mov %rdx, 48(%rdi) + mov (%rsp), %rdx + mov %rdx, 56(%rdi) + xor %eax, %eax + ret diff --git a/libc/src/string/memcpy.c b/libc/src/string/memcpy.c index 558e58a6..4d71708a 100644 --- a/libc/src/string/memcpy.c +++ b/libc/src/string/memcpy.c @@ -30,6 +30,8 @@ void* memcpy(void* dest, const void* src, size_t num) uint8_t* targetPtr = (uint8_t*) dest; const uint8_t* sourcePtr = (const uint8_t*) src; + // TODO qword copying + while(num >= 4) { *(uint32_t*) targetPtr = *(const uint32_t*) sourcePtr; diff --git a/target/build.sh b/target/build.sh index 7de96fcf..fcd52223 100644 --- a/target/build.sh +++ b/target/build.sh @@ -9,28 +9,22 @@ TARGET=$@ with TARGET "pack" -# # Ramdisk build -# with RAMDISK_WRITER "ramdisk-writer" -# # ISO file -# with ISO_SRC "iso" with ISO_TGT "ghost.iso" -with GRUB_MKRESCUE "grub-mkrescue" -# # Binaries to copy -# with KERNEL_BIN "../kernel/kernel" with LOADER_BIN "../kernel/loader" - # Header target_headline $TARGET +# Must have curl +requireTool curl # # Generate the ramdisk file @@ -48,9 +42,19 @@ target_make_iso() { headline "making iso" rm $ISO_TGT cp $KERNEL_BIN "$ISO_SRC/boot/kernel" - cp $LOADER_BIN "$ISO_SRC/boot/loader" - $GRUB_MKRESCUE --output=$ISO_TGT $ISO_SRC + cp "limine-$LIMINE_VERSION/bin/limine-bios.sys" "$ISO_SRC/boot/limine/" + cp "limine-$LIMINE_VERSION/bin/limine-bios-cd.bin" "$ISO_SRC/boot/limine/" + cp "limine-$LIMINE_VERSION/bin/limine-uefi-cd.bin" "$ISO_SRC/boot/limine/" + + xorriso -as mkisofs -R -r -J -b /boot/limine/limine-bios-cd.bin \ + -no-emul-boot -boot-load-size 4 -boot-info-table -hfsplus \ + -apm-block-size 2048 --efi-boot /boot/limine/limine-uefi-cd.bin \ + -efi-boot-part --efi-boot-image --protective-msdos-label \ + iso -o ghost.iso + failOnError + + ./limine-$LIMINE_VERSION/bin/limine bios-install ghost.iso failOnError } @@ -95,6 +99,8 @@ target_pack() { # execute targets +target_verify_limine + for var in $TARGET; do if [[ "$var" == "pack" ]]; then target_pack diff --git a/target/iso/boot/limine/limine.conf b/target/iso/boot/limine/limine.conf new file mode 100644 index 00000000..ca012a24 --- /dev/null +++ b/target/iso/boot/limine/limine.conf @@ -0,0 +1,6 @@ +timeout:0 + +/Ghost + protocol: limine + path: boot():/boot/kernel + module_path: boot():/boot/ramdisk diff --git a/tools/bitmap-font/convert.js b/tools/bitmap-font/convert.js new file mode 100644 index 00000000..9719976f --- /dev/null +++ b/tools/bitmap-font/convert.js @@ -0,0 +1,93 @@ +const fs = require('fs'); +const bmp = require('bmp-js'); + +// Bitmap parameters: +const headerHeight = 10; +const charWidth = 10; +const charHeight = 19; +const spacing = 1; + +/** + * The first character in the bitmap will be treated as this value. For example + * if 33 is set, the first character in the bitmap shall be the '!'. + * + * @type {number} + */ +const asciiOffset = 0; + + +const topComment = `/* + * NOTE: This file is generated by the bitmap-font tool, use it to update it. + */` + +function processBitmap(filePath) { + const {width, height, data} = bmp.decode(fs.readFileSync(filePath)); + const cellWidth = charWidth + spacing; + const cellHeight = charHeight + spacing; + const columns = width / cellWidth; + const rows = (height - headerHeight) / cellHeight; + const charCount = columns * rows; + + + // + // Write the C file + // + let code = `${topComment} +#include + +uint8_t bitmapFontCharWidth = ${charWidth}; +uint8_t bitmapFontCharHeight = ${charHeight}; +uint8_t bitmapFontCharCount = ${charCount}; +uint8_t bitmapFontAsciiOffset = ${asciiOffset}; + +uint8_t bitmapFontCharSet[${charCount}][${charWidth * charHeight}] = { +` + + let charCode = asciiOffset; + for (let row = 0; row < rows; row++) { + for (let col = 0; col < columns; col++) { + + // Convert a char + const topLeftX = (col * cellWidth); + const topLeftY = (headerHeight + row * cellHeight); + + code += `\n // Char ${charCode} \n{` + for (let onCharY = 0; onCharY < charHeight; onCharY++) { + for (let onCharX = 0; onCharX < charWidth; onCharX++) { + const index = ((topLeftY + onCharY) * width + (topLeftX + onCharX)) * 4; + let pixel = data.slice(index, index + 4); + + code += (isBlack(pixel) ? 1 : 0) + ", "; + } + code += " //\n"; + } + code += `}, \n` + + ++charCode; + } + } + code += "};" + + fs.writeFileSync("../../kernel/src/shared/video/bitmap_font_data.cpp", code); + + + // + // Write the header + // + const header = `${topComment} +#ifndef __BITMAP_FONT_DATA__ +#define __BITMAP_FONT_DATA__ +#include + +extern uint8_t bitmapFontCharSet[${charCount}][${charWidth * charHeight}]; +#endif + `; + + fs.writeFileSync("../../kernel/inc/shared/video/bitmap_font_data.hpp", header); +} + +function isBlack(pixel) { + return pixel[0] === 0 && pixel[1] === 0 && pixel[2] === 0; +} + +processBitmap('font.bmp'); diff --git a/tools/bitmap-font/font.bmp b/tools/bitmap-font/font.bmp new file mode 100644 index 00000000..89402b8e Binary files /dev/null and b/tools/bitmap-font/font.bmp differ diff --git a/tools/bitmap-font/package-lock.json b/tools/bitmap-font/package-lock.json new file mode 100644 index 00000000..adfeb70c --- /dev/null +++ b/tools/bitmap-font/package-lock.json @@ -0,0 +1,21 @@ +{ + "name": "bitmap-font", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "bitmap-font", + "version": "1.0.0", + "license": "ISC", + "dependencies": { + "bmp-js": "^0.1.0" + } + }, + "node_modules/bmp-js": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/bmp-js/-/bmp-js-0.1.0.tgz", + "integrity": "sha512-vHdS19CnY3hwiNdkaqk93DvjVLfbEcI8mys4UjuWrlX1haDmroo8o4xCzh4wD6DGV6HxRCyauwhHRqMTfERtjw==" + } + } +} diff --git a/tools/bitmap-font/package.json b/tools/bitmap-font/package.json new file mode 100644 index 00000000..866a6337 --- /dev/null +++ b/tools/bitmap-font/package.json @@ -0,0 +1,13 @@ +{ + "name": "bitmap-font", + "version": "1.0.0", + "description": "", + "scripts": { + "convert": "node convert.js" + }, + "author": "", + "license": "ISC", + "dependencies": { + "bmp-js": "^0.1.0" + } +}