Update kernel

This commit is contained in:
Alex 2023-08-06 04:53:14 +03:00
parent 3b65386399
commit 2c51e4432f
Signed by untrusted user who does not match committer: enderice2
GPG Key ID: EACC3AD603BAB4DD
181 changed files with 21873 additions and 21475 deletions

View File

@ -42,6 +42,18 @@
],
"description": "Create kernel documentation brief."
},
"For Iteratoion": {
"prefix": [
"foritr",
],
"body": [
"forItr(${1:itr}, ${2:container})",
"{",
"\t$0",
"}"
],
"description": "Create for loop with iterator."
},
"License": {
"prefix": [
"license",

View File

@ -11,6 +11,7 @@
"defines": [
"__debug_vscode__",
"KERNEL_NAME=\"Fennix\"",
"KERNEL_ARCH=\"amd64\"",
"KERNEL_VERSION=\"1.0\"",
"GIT_COMMIT=\"0000000000000000000000000000000000000000\"",
"GIT_COMMIT_SHORT=\"0000000\"",
@ -84,6 +85,7 @@
"defines": [
"__debug_vscode__",
"KERNEL_NAME=\"Fennix\"",
"KERNEL_ARCH=\"i386\"",
"KERNEL_VERSION=\"1.0\"",
"GIT_COMMIT=\"0000000000000000000000000000000000000000\"",
"GIT_COMMIT_SHORT=\"0000000\"",
@ -160,6 +162,7 @@
"defines": [
"__debug_vscode__",
"KERNEL_NAME=\"Fennix\"",
"KERNEL_ARCH=\"aarch64\"",
"KERNEL_VERSION=\"1.0\"",
"GIT_COMMIT=\"0000000000000000000000000000000000000000\"",
"GIT_COMMIT_SHORT=\"0000000\"",

78
.vscode/launch.json vendored
View File

@ -74,8 +74,82 @@
"description": "Load /bin/init."
},
{
"text": "add-symbol-file ${workspaceFolder}/../initrd_tmp_data/lib/ld.so",
"description": "Load /lib/ld.so."
"text": "add-symbol-file ${workspaceFolder}/../initrd_tmp_data/usr/bin/doom",
"description": "Load /usr/bin/doom."
},
],
},
{
"name": "Attach to VM w/init",
"type": "cppdbg",
"request": "launch",
"program": "${workspaceFolder}/kernel.fsys",
"cwd": "${workspaceFolder}",
"args": [],
"targetArchitecture": "x64",
"MIMode": "gdb",
"miDebuggerPath": "${workspaceFolder}/../tools/cross/bin/x86_64-fennix-gdb",
"miDebuggerArgs": "",
"externalConsole": false,
"additionalSOLibSearchPath": "${workspaceFolder}",
"customLaunchSetupCommands": [
{
"text": "target remote localhost:1234",
"description": "Connect to QEMU remote debugger"
}
],
"setupCommands": [
{
"description": "Enable pretty-printing for gdb",
"text": "-enable-pretty-printing",
"ignoreFailures": true
},
{
"text": "set breakpoint pending on",
"description": "Make breakpoint pending on future shared library load."
},
{
"text": "file ${workspaceFolder}/kernel.fsys",
"description": "Load binary."
},
{
"text": "add-symbol-file ${workspaceFolder}/../initrd_tmp_data/bin/init",
"description": "Load /bin/init."
},
],
},
{
"name": "Attach to VM w/doom",
"type": "cppdbg",
"request": "launch",
"program": "${workspaceFolder}/kernel.fsys",
"cwd": "${workspaceFolder}",
"args": [],
"targetArchitecture": "x64",
"MIMode": "gdb",
"miDebuggerPath": "${workspaceFolder}/../tools/cross/bin/x86_64-fennix-gdb",
"miDebuggerArgs": "",
"externalConsole": false,
"additionalSOLibSearchPath": "${workspaceFolder}",
"customLaunchSetupCommands": [
{
"text": "target remote localhost:1234",
"description": "Connect to QEMU remote debugger"
}
],
"setupCommands": [
{
"description": "Enable pretty-printing for gdb",
"text": "-enable-pretty-printing",
"ignoreFailures": true
},
{
"text": "set breakpoint pending on",
"description": "Make breakpoint pending on future shared library load."
},
{
"text": "file ${workspaceFolder}/kernel.fsys",
"description": "Load binary."
},
{
"text": "add-symbol-file ${workspaceFolder}/../initrd_tmp_data/usr/bin/doom",

View File

@ -18,6 +18,7 @@
#include <types.h>
#include <memory.hpp>
#include <elf.h>
#include <io.h>
#include "multiboot2.h"
@ -50,7 +51,6 @@ EXTERNC void multiboot_main(uintptr_t Magic, uintptr_t Info)
if (tmp != (tmp | 3))
outb(0x61, tmp | 3);
int pos = 0;
auto InfoAddress = Info;
for (auto Tag = (struct multiboot_tag *)((uint8_t *)InfoAddress + 8);
;
@ -220,7 +220,7 @@ EXTERNC void multiboot_main(uintptr_t Magic, uintptr_t Info)
mb2binfo.Kernel.Symbols.Num = elf->num;
mb2binfo.Kernel.Symbols.EntSize = elf->entsize;
mb2binfo.Kernel.Symbols.Shndx = elf->shndx;
mb2binfo.Kernel.Symbols.Sections = (uintptr_t)&elf->sections;
mb2binfo.Kernel.Symbols.Sections = r_cst(uintptr_t, elf->sections);
break;
}
case MULTIBOOT_TAG_TYPE_APM:

View File

@ -82,8 +82,8 @@ namespace ACPI
{
TaskManager->CreateThread(TaskManager->CreateProcess(nullptr,
"Shutdown",
Tasking::TaskTrustLevel::Kernel),
(Tasking::IP)KST_Shutdown);
Tasking::TaskExecutionMode::Kernel),
Tasking::IP(KST_Shutdown));
}
else
KernelShutdownThread(false);

View File

@ -42,13 +42,13 @@ namespace Memory
{
if ((PDPTE->Entries[Index.PDPTEIndex].Present))
{
if (Type == MapType::OneGB && PDPTE->Entries[Index.PDPTEIndex].PageSize)
if (Type == MapType::OneGiB && PDPTE->Entries[Index.PDPTEIndex].PageSize)
return true;
PDE = (PageDirectoryEntryPtr *)((uintptr_t)PDPTE->Entries[Index.PDPTEIndex].GetAddress() << 12);
if (PDE)
{
if (Type == MapType::TwoMB && PDE->Entries[Index.PDEIndex].PageSize)
if (Type == MapType::TwoMiB && PDE->Entries[Index.PDEIndex].PageSize)
return true;
if ((PDE->Entries[Index.PDEIndex].Present))
@ -133,7 +133,7 @@ namespace Memory
if (PDPTE->Entries[Index.PDPTEIndex].Present)
{
if (PDPTE->Entries[Index.PDPTEIndex].PageSize)
return MapType::OneGB;
return MapType::OneGiB;
PDE = (PageDirectoryEntryPtr *)((uintptr_t)PDPTE->Entries[Index.PDPTEIndex].GetAddress() << 12);
if (PDE)
@ -141,13 +141,13 @@ namespace Memory
if (PDE->Entries[Index.PDEIndex].Present)
{
if (PDE->Entries[Index.PDEIndex].PageSize)
return MapType::TwoMB;
return MapType::TwoMiB;
PTE = (PageTableEntryPtr *)((uintptr_t)PDE->Entries[Index.PDEIndex].GetAddress() << 12);
if (PTE)
{
if (PTE->Entries[Index.PTEIndex].Present)
return MapType::FourKB;
return MapType::FourKiB;
}
}
}
@ -159,12 +159,15 @@ namespace Memory
PageMapLevel5 *Virtual::GetPML5(void *VirtualAddress, MapType Type)
{
UNUSED(VirtualAddress);
UNUSED(Type);
stub; /* TODO */
return nullptr;
}
PageMapLevel4 *Virtual::GetPML4(void *VirtualAddress, MapType Type)
{
UNUSED(Type);
uintptr_t Address = (uintptr_t)VirtualAddress;
Address &= 0xFFFFFFFFFFFFF000;
@ -177,6 +180,7 @@ namespace Memory
PageDirectoryPointerTableEntry *Virtual::GetPDPTE(void *VirtualAddress, MapType Type)
{
UNUSED(Type);
uintptr_t Address = (uintptr_t)VirtualAddress;
Address &= 0xFFFFFFFFFFFFF000;
@ -194,6 +198,7 @@ namespace Memory
PageDirectoryEntry *Virtual::GetPDE(void *VirtualAddress, MapType Type)
{
UNUSED(Type);
uintptr_t Address = (uintptr_t)VirtualAddress;
Address &= 0xFFFFFFFFFFFFF000;
@ -216,6 +221,7 @@ namespace Memory
PageTableEntry *Virtual::GetPTE(void *VirtualAddress, MapType Type)
{
UNUSED(Type);
uintptr_t Address = (uintptr_t)VirtualAddress;
Address &= 0xFFFFFFFFFFFFF000;
@ -270,7 +276,7 @@ namespace Memory
PML4->raw |= DirectoryFlags;
PageDirectoryPointerTableEntry *PDPTE = &PDPTEPtr->Entries[Index.PDPTEIndex];
if (Type == MapType::OneGB)
if (Type == MapType::OneGiB)
{
PDPTE->raw |= Flags;
PDPTE->PageSize = true;
@ -292,7 +298,7 @@ namespace Memory
PDPTE->raw |= DirectoryFlags;
PageDirectoryEntry *PDE = &PDEPtr->Entries[Index.PDEIndex];
if (Type == MapType::TwoMB)
if (Type == MapType::TwoMiB)
{
PDE->raw |= Flags;
PDE->PageSize = true;
@ -375,7 +381,7 @@ namespace Memory
return;
}
if (Type == MapType::OneGB && PDPTE->PageSize)
if (Type == MapType::OneGiB && PDPTE->PageSize)
{
PDPTE->Present = false;
return;
@ -389,7 +395,7 @@ namespace Memory
return;
}
if (Type == MapType::TwoMB && PDE->PageSize)
if (Type == MapType::TwoMiB && PDE->PageSize)
{
PDE->Present = false;
return;

View File

@ -31,11 +31,11 @@ extern "C" void SystemCallHandlerStub();
extern "C" __naked __used __no_stack_protector __aligned(16) void SystemCallHandlerStub()
{
asmv("swapgs\n"); /* Swap GS to get the TCB */
asmv("mov %rsp, %gs:0x8\n"); /* We save the current rsp to TCB->TempStack */
asmv("mov %gs:0x0, %rsp\n"); /* Get TCB->SystemCallStack and set it as rsp */
asmv("swapgs\n"); /* Swap GS to get the gsTCB */
asmv("mov %rsp, %gs:0x8\n"); /* We save the current rsp to gsTCB->TempStack */
asmv("mov %gs:0x0, %rsp\n"); /* Get gsTCB->SystemCallStack and set it as rsp */
asmv("push $0x1b\n"); /* Push user data segment for SyscallsFrame */
asmv("push %gs:0x8\n"); /* Push TCB->TempStack (old rsp) for SyscallsFrame */
asmv("push %gs:0x8\n"); /* Push gsTCB->TempStack (old rsp) for SyscallsFrame */
asmv("push %r11\n"); /* Push the flags for SyscallsFrame */
asmv("push $0x23\n"); /* Push user code segment for SyscallsFrame */
asmv("push %rcx\n"); /* Push the return address for SyscallsFrame + sysretq (https://www.felixcloutier.com/x86/sysret) */
@ -78,7 +78,7 @@ extern "C" __naked __used __no_stack_protector __aligned(16) void SystemCallHand
"pop %rcx\n"
"pop %rbx\n");
/* Restore rsp from TCB->TempStack */
/* Restore rsp from gsTCB->TempStack */
asmv("mov %gs:0x8, %rsp\n");
#ifdef DEBUG
/* Easier to debug stacks */

View File

@ -25,8 +25,7 @@
namespace GlobalDescriptorTable
{
static GlobalDescriptorTableEntries GDTEntriesTemplate = {
.Null =
{
.Null = {
.Limit0 = 0x0,
.BaseLow = 0x0,
.BaseMiddle = 0x0,
@ -36,8 +35,7 @@ namespace GlobalDescriptorTable
.BaseHigh = 0x0,
},
.Code =
{
.Code = {
.Limit0 = 0xFFFF,
.BaseLow = 0x0,
.BaseMiddle = 0x0,

View File

@ -32,43 +32,76 @@ namespace GlobalDescriptorTable
{
struct
{
/** @brief Access bit.
* @note The CPU sets this bit to 1 when the segment is accessed.
/**
* Access bit.
*
* @note The CPU sets this bit to 1 when the segment
* is accessed.
*/
uint8_t A : 1;
/** @brief Readable bit for code segments, writable bit for data segments.
* @details For code segments, this bit must be 1 for the segment to be readable.
* @details For data segments, this bit must be 1 for the segment to be writable.
/**
* Readable bit for code segments, writable bit for data
* segments.
*
* Code Segment:
* This bit must be 1 for the segment to be readable.
*
* Data Segment:
* This bit must be 1 for the segment to be writable.
*/
uint8_t RW : 1;
/** @brief Direction bit for data segments, conforming bit for code segments.
* @details For data segments, this bit must be 1 for the segment to grow up (higher addresses).
* @details For code segments, this bit must be 1 for code in the segment to be able to be executed from an equal or lower privilege level.
/**
* Direction bit for data segments, conforming bit for
* code segments.
*
* Code Segment:
* This bit must be 1 for code in the segment to be
* able to be executed from an equal or lower privilege
* level.
*
* Data Segment:
* This bit must be 1 for the segment to grow up (higher
* addresses).
*/
uint8_t DC : 1;
/** @brief Executable bit.
* @details This bit must be 1 for code-segment descriptors.
* @details This bit must be 0 for data-segment and system descriptors.
/**
* Executable bit.
*
* This bit must be 1 for code-segment descriptors.
*
* This bit must be 0 for data-segment and system
* descriptors.
*/
uint8_t E : 1;
/** @brief Descriptor type.
* @details This bit must be 0 for system descriptors.
* @details This bit must be 1 for code or data segment descriptor.
/**
* Descriptor type.
*
* This bit must be 0 for system descriptors.
*
* This bit must be 1 for code or data segment
* descriptor.
*/
uint8_t S : 1;
/** @brief Descriptor privilege level.
* @details This field determines the privilege level of the segment.
* @details 0 = kernel mode, 3 = user mode.
/**
* Descriptor privilege level.
*
* This field determines the privilege level of the
* segment.
*
* 0 = kernel mode
* 3 = user mode
*/
uint8_t DPL : 2;
/** @brief Present bit.
* @details This bit must be 1 for all valid descriptors.
/**
* Present bit.
*
* This bit must be 1 for all valid descriptors.
*/
uint8_t P : 1;
} __packed;
@ -94,99 +127,163 @@ namespace GlobalDescriptorTable
struct GlobalDescriptorTableEntry
{
/** @brief Limit 0:15 */
/**
* Limit 0:15
*/
uint16_t Limit0 : 16;
/** @brief Low Base 0:15 */
/**
* Low Base 0:15
*/
uint16_t BaseLow : 16;
/** @brief Middle Base 16:23 */
/**
* Middle Base 16:23
*/
uint8_t BaseMiddle : 8;
/** @brief Access */
/**
* Access
*/
union GlobalDescriptorTableAccess
{
struct
{
/** @brief Access bit.
* @note The CPU sets this bit to 1 when the segment is accessed.
/**
* Access bit.
*
* @note The CPU sets this bit to 1 when the segment
* is accessed.
*/
uint8_t A : 1;
/** @brief Readable bit for code segments, writable bit for data segments.
* @details For code segments, this bit must be 1 for the segment to be readable.
* @details For data segments, this bit must be 1 for the segment to be writable.
/**
* Readable bit for code segments, writable bit for
* data segments.
*
* Code Segment:
* This bit must be 1 for the segment to be readable.
*
* Data Segment:
* This bit must be 1 for the segment to be writable.
*/
uint8_t RW : 1;
/** @brief Direction bit for data segments, conforming bit for code segments.
* @details For data segments, this bit must be 1 for the segment to grow up (higher addresses).
* @details For code segments, this bit must be 1 for code in the segment to be able to be executed from an equal or lower privilege level.
/**
* Direction bit for data segments, conforming bit for
* code segments.
*
* Code Segment:
* This bit must be 1 for code in the segment to be able
* to be executed from an equal or lower privilege level.
*
* Data Segment:
* This bit must be 1 for the segment to grow up (higher
* addresses).
*/
uint8_t DC : 1;
/** @brief Executable bit.
* @details This bit must be 1 for code-segment descriptors.
* @details This bit must be 0 for data-segment and system descriptors.
/**
* Executable bit.
*
* This bit must be 1 for code-segment descriptors.
*
* This bit must be 0 for data-segment and
* system descriptors.
*/
uint8_t E : 1;
/** @brief Descriptor type.
* @details This bit must be 0 for system descriptors.
* @details This bit must be 1 for code or data segment descriptor.
/**
* Descriptor type.
*
* This bit must be 0 for system descriptors.
*
* This bit must be 1 for code or data segment
* descriptor.
*/
uint8_t S : 1;
/** @brief Descriptor privilege level.
* @details This field determines the privilege level of the segment.
* @details 0 = kernel mode, 3 = user mode.
/**
* Descriptor privilege level.
*
* This field determines the privilege level of the
* segment.
*
* 0 = kernel mode
* 3 = user mode
*/
uint8_t DPL : 2;
/** @brief Present bit.
* @details This bit must be 1 for all valid descriptors.
/**
* Present bit.
*
* This bit must be 1 for all valid descriptors.
*/
uint8_t P : 1;
} __packed;
uint8_t Raw : 8;
} Access;
// /** @brief Limit 16:19 */
// /** Limit 16:19 */
// uint16_t Limit1 : 4;
/** @brief Flags */
/**
* Flags
*/
union GlobalDescriptorTableFlags
{
struct
{
uint8_t Reserved : 4; /* FIXME: Without this, the kernel crashes. */
/** @brief Available bit.
* @details This bit is available for use by system software.
/* FIXME: Without this, the kernel crashes. */
uint8_t Reserved : 4;
/**
* Available bit.
*
* This bit is available for use by system software.
*/
uint8_t AVL : 1;
/** @brief Long mode.
* @details If the long mode bit is clear, the segment is in 32-bit protected mode.
* @details If the long mode bit is set, the segment is in 64-bit long mode.
/**
* Long mode.
*
* If the long mode bit is clear, the segment is in
* 32-bit protected mode.
*
* If the long mode bit is set, the segment is in
* 64-bit long mode.
*/
uint8_t L : 1;
/** @brief Size flag.
* @details If the size bit is clear, the segment is in 16-bit protected mode.
* @details If the size bit is set, the segment is in 32-bit protected mode.
/**
* Size flag.
*
* If the size bit is clear, the segment is in
* 16-bit protected mode.
*
* If the size bit is set, the segment is in
* 32-bit protected mode.
*/
uint8_t DB : 1;
/** @brief Granularity bit.
* @details If the granularity bit is clear, the segment limit is in 1 B blocks.
* @details If the granularity bit is set, the segment limit is in 4 KiB blocks.
/**
* Granularity bit.
*
* If the granularity bit is clear, the segment limit
* is in 1 B blocks.
*
* If the granularity bit is set, the segment limit is
* in 4 KiB blocks.
*/
uint8_t G : 1;
} __packed;
uint8_t Raw : 8;
} Flags;
/** @brief High Base 24:31 */
/**
* High Base 24:31
*/
uint8_t BaseHigh : 8;
} __packed;
@ -202,9 +299,14 @@ namespace GlobalDescriptorTable
struct GlobalDescriptorTableDescriptor
{
/** @brief GDT entries length */
/**
* GDT entries length
*/
uint16_t Length;
/** @brief GDT entries address */
/**
* GDT entries address
*/
GlobalDescriptorTableEntries *Entries;
} __packed;

View File

@ -34,7 +34,7 @@ namespace Memory
if ((PDE->raw & Flag) > 0)
{
if (Type == MapType::FourMB && PDE->PageSize)
if (Type == MapType::FourMiB && PDE->PageSize)
return true;
PTE = (PageTableEntryPtr *)((uintptr_t)PDE->GetAddress() << 12);
@ -86,13 +86,13 @@ namespace Memory
if (PDE->Present)
{
if (PDE->PageSize)
return MapType::FourMB;
return MapType::FourMiB;
PTE = (PageTableEntryPtr *)((uintptr_t)PDE->GetAddress() << 12);
if (PTE)
{
if (PTE->Entries[Index.PTEIndex].Present)
return MapType::FourKB;
return MapType::FourKiB;
}
}
return MapType::NoMapType;
@ -143,7 +143,7 @@ namespace Memory
uint64_t DirectoryFlags = Flags & 0x3F;
PageDirectoryEntry *PDE = &this->Table->Entries[Index.PDEIndex];
if (Type == MapType::FourMB)
if (Type == MapType::FourMiB)
{
PDE->raw |= (uintptr_t)Flags;
PDE->PageSize = true;
@ -218,7 +218,7 @@ namespace Memory
return;
}
if (Type == MapType::FourMB && PDE->PageSize)
if (Type == MapType::FourMiB && PDE->PageSize)
{
PDE->Present = false;
return;

View File

@ -226,14 +226,14 @@ namespace GlobalDescriptorTable
size_t Limit = Base + sizeof(TaskStateSegment);
gdt[Core].Entries->TaskStateSegment.Limit = Limit & 0xFFFF;
gdt[Core].Entries->TaskStateSegment.BaseLow = Base & 0xFFFF;
gdt[Core].Entries->TaskStateSegment.BaseMiddle = (Base >> 16) & 0xFF;
gdt[Core].Entries->TaskStateSegment.BaseHigh = (Base >> 24) & 0xFF;
gdt[Core].Entries->TaskStateSegment.BaseMiddle = uint8_t((Base >> 16) & 0xFF);
gdt[Core].Entries->TaskStateSegment.BaseHigh = uint8_t((Base >> 24) & 0xFF);
gdt[Core].Entries->TaskStateSegment.BaseUpper = s_cst(uint32_t, (Base >> 32) & 0xFFFFFFFF);
gdt[Core].Entries->TaskStateSegment.Access = {.A = 1, .RW = 0, .DC = 0, .E = 1, .S = 0, .DPL = 0, .P = 1};
gdt[Core].Entries->TaskStateSegment.Granularity = (0 << 4) | ((Limit >> 16) & 0xF);
tss[Core].IOMapBaseAddressOffset = sizeof(TaskStateSegment);
tss[Core].StackPointer[0] = (uint64_t)CPUStackPointer[Core] + STACK_SIZE;
tss[Core].StackPointer[0] = (uint32_t)CPUStackPointer[Core] + STACK_SIZE;
tss[Core].StackPointer[1] = 0x0;
tss[Core].StackPointer[2] = 0x0;
@ -241,7 +241,7 @@ namespace GlobalDescriptorTable
{
void *NewStack = KernelAllocator.RequestPages(TO_PAGES(STACK_SIZE + 1));
tss[Core].InterruptStackTable[i] = (uint64_t)NewStack + STACK_SIZE;
tss[Core].InterruptStackTable[i] = (uint32_t)NewStack + STACK_SIZE;
memset((void *)(tss[Core].InterruptStackTable[i] - STACK_SIZE), 0, STACK_SIZE);
debug("IST-%d: %#lx-%#lx", i, NewStack, (uintptr_t)NewStack + STACK_SIZE);
}
@ -253,20 +253,7 @@ namespace GlobalDescriptorTable
SafeFunction void SetKernelStack(void *Stack)
{
long CPUID = GetCurrentCPU()->ID;
if (Stack != nullptr)
tss[CPUID].StackPointer[0] = (uint64_t)Stack;
else
tss[CPUID].StackPointer[0] = (uint64_t)CPUStackPointer[CPUID] + STACK_SIZE;
/*
FIXME: There's a bug in kernel which if
we won't update "tss[CPUID].StackPointer[0]"
with the current stack pointer, the kernel
will crash.
*/
asmv("mov %%esp, %0"
: "=r"(tss[CPUID].StackPointer[0]));
}
void *GetKernelStack() { return (void *)tss[GetCurrentCPU()->ID].StackPointer[0]; }
void *GetKernelStack() { return (void *)nullptr; }
}

View File

@ -28,7 +28,7 @@ namespace CPU
{
static bool SSEEnabled = false;
char *Vendor()
const char *Vendor()
{
static char Vendor[13] = {0};
if (Vendor[0] != 0)
@ -52,7 +52,7 @@ namespace CPU
return Vendor;
}
char *Name()
const char *Name()
{
static char Name[49] = {0};
if (Name[0] != 0)
@ -98,7 +98,7 @@ namespace CPU
return Name;
}
char *Hypervisor()
const char *Hypervisor()
{
static char Hypervisor[13] = {0};
if (Hypervisor[0] != 0)
@ -255,8 +255,7 @@ namespace CPU
bool SSEEnableAfter = false;
/* Not sure if my code is not working properly or something else is the issue. */
if ((strcmp(Hypervisor(), x86_CPUID_VENDOR_TCG) != 0 &&
strcmp(Hypervisor(), x86_CPUID_VENDOR_VIRTUALBOX) != 0) &&
if ((strcmp(Hypervisor(), x86_CPUID_VENDOR_VIRTUALBOX) != 0) &&
SSESupport)
{
debug("Enabling SSE support...");
@ -438,16 +437,16 @@ namespace CPU
#endif
}
uintptr_t Counter()
uint64_t Counter()
{
// TODO: Get the counter from the x2APIC or any other timer that is available. (TSC is not available on all CPUs)
uintptr_t Counter;
#if defined(a64)
uint64_t Counter;
#if defined(a86)
uint32_t eax, edx;
asmv("rdtsc"
: "=A"(Counter));
#elif defined(a32)
asmv("rdtsc"
: "=A"(Counter));
: "=a"(eax),
"=d"(edx));
Counter = ((uint64_t)eax) | (((uint64_t)edx) << 32);
#elif defined(aa64)
asmv("mrs %0, cntvct_el0"
: "=r"(Counter));

View File

@ -161,10 +161,10 @@ namespace CrashHandler
break;
}
}
EHPrint(" \e00AAFF%ldMB / %ldMB (%ldMB Reserved)",
TO_MB(KernelAllocator.GetUsedMemory()),
TO_MB(KernelAllocator.GetTotalMemory()),
TO_MB(KernelAllocator.GetReservedMemory()));
EHPrint(" \e00AAFF%ld MiB / %ld MiB (%ld MiB Reserved)",
TO_MiB(KernelAllocator.GetUsedMemory()),
TO_MiB(KernelAllocator.GetTotalMemory()),
TO_MiB(KernelAllocator.GetReservedMemory()));
EHPrint(" \eAA0F0F%s", CPU::Hypervisor());
EHPrint(" \eAAF00F%s", CPU::Vendor());
EHPrint(" \eAA00FF%s", CPU::Name());
@ -884,7 +884,9 @@ namespace CrashHandler
debug("CPU %ld data is valid", data->ID);
if (data->CurrentThread->Security.IsCritical)
{
debug("Critical thread \"%s\"(%d) died", data->CurrentThread->Name, data->CurrentThread->ID);
debug("Critical thread \"%s\"(%d) died",
data->CurrentThread->Name,
data->CurrentThread->ID);
if (TaskManager)
TaskManager->Panic();
ForceUnlock = true;
@ -893,7 +895,8 @@ namespace CrashHandler
}
else
{
debug("Current thread is valid %#lx", data->CurrentThread);
debug("Current thread is valid %#lx",
data->CurrentThread.load());
UserModeExceptionHandler(Frame);
return;
}

View File

@ -52,9 +52,11 @@ namespace CrashHandler
if (cpu)
{
EHPrint("\eE46CEBCPU Data Address: %#lx\n", cpu);
EHPrint("Core Stack: %#lx, Core ID: %ld, Error Code: %ld\n", cpu->Stack, cpu->ID, cpu->ErrorCode);
EHPrint("Core Stack: %#lx, Core ID: %ld, Error Code: %ld\n",
cpu->Stack, cpu->ID, cpu->ErrorCode);
EHPrint("Is Active: %s\n", cpu->IsActive ? "true" : "false");
EHPrint("Current Process: %#lx, Current Thread: %#lx\n", cpu->CurrentProcess, cpu->CurrentThread);
EHPrint("Current Process: %#lx, Current Thread: %#lx\n",
cpu->CurrentProcess.load(), cpu->CurrentThread.load());
EHPrint("Arch Specific Data: %#lx\n", cpu->Data);
EHPrint("Checksum: 0x%X\n", cpu->Checksum);
}
@ -128,7 +130,7 @@ namespace CrashHandler
#endif
#if defined(a86)
EHPrint("\eA0A0A0DR6: B0:%s B1:%s B2:%s B3:%s BD:%s BS:%s BT:%s\n",
EHPrint("\eA0A0A0DR6: B0:%s B1:%s B2:%s B3:%s\n BD:%s BS:%s BT:%s\n",
data.dr6.B0 ? "True " : "False", data.dr6.B1 ? "True " : "False", data.dr6.B2 ? "True " : "False", data.dr6.B3 ? "True " : "False",
data.dr6.BD ? "True " : "False", data.dr6.BS ? "True " : "False", data.dr6.BT ? "True " : "False");

View File

@ -311,7 +311,7 @@ namespace CrashHandler
case CPU::x86::PageFault:
{
EHPrint("Exception: Page Fault\n");
EHPrint("The processor attempted to access a page that is not present.\n");
EHPrint("The processor attempted to access a page that is not present/accessible.\n");
CPU::x64::PageFaultErrorCode params = {.raw = (uint32_t)Frame->ErrorCode};
#if defined(a64)

View File

@ -41,8 +41,8 @@ namespace CrashHandler
"AAFF00", // Ready
"00AA00", // Running
"FFAA00", // Sleeping
"FFAA00", // Waiting
"FF0088", // Stopped
"FFAA00", // Blocked
"FF0088", // Zombie
"FF0000", // Terminated
};
@ -51,8 +51,8 @@ namespace CrashHandler
"Ready", // Ready
"Running", // Running
"Sleeping", // Sleeping
"Waiting", // Waiting
"Stopped", // Stopped
"Blocked", // Blocked
"Zombie", // Zombie
"Terminated", // Terminated
};
@ -62,9 +62,11 @@ namespace CrashHandler
if (data.Thread)
#if defined(a64)
EHPrint("\eFAFAFACrash occurred in thread \eAA0F0F%s\eFAFAFA(%ld) at \e00AAAA%#lx\n", data.Thread->Name, data.Thread->ID, data.Frame->rip);
EHPrint("\eFAFAFACrash occurred in thread \eAA0F0F%s\eFAFAFA(%ld) at \e00AAAA%#lx\n",
data.Thread->Name, data.Thread->ID, data.Frame->rip);
#elif defined(a32)
EHPrint("\eFAFAFACrash occurred in thread \eAA0F0F%s\eFAFAFA(%ld) at \e00AAAA%#lx\n", data.Thread->Name, data.Thread->ID, data.Frame->eip);
EHPrint("\eFAFAFACrash occurred in thread \eAA0F0F%s\eFAFAFA(%ld) at \e00AAAA%#lx\n",
data.Thread->Name, data.Thread->ID, data.Frame->eip);
#elif defined(aa64)
#endif
@ -72,12 +74,14 @@ namespace CrashHandler
foreach (auto Process in Plist)
{
EHPrint("\e%s-> \eFAFAFA%s\eCCCCCC(%ld) \e00AAAA%s\eFAFAFA PT:\e00AAAA%#lx\n",
StatusColor[Process->Status], Process->Name, Process->ID, StatusString[Process->Status],
StatusColor[Process->Status.load()], Process->Name,
Process->ID, StatusString[Process->Status.load()],
Process->PageTable);
foreach (auto Thread in Process->Threads)
EHPrint("\e%s -> \eFAFAFA%s\eCCCCCC(%ld) \e00AAAA%s\eFAFAFA Stack:\e00AAAA%#lx\n",
StatusColor[Thread->Status], Thread->Name, Thread->ID, StatusString[Thread->Status],
StatusColor[Thread->Status.load()], Thread->Name,
Thread->ID, StatusString[Thread->Status.load()],
Thread->Stack);
}
}

View File

@ -47,7 +47,7 @@ SafeFunction void UserModeExceptionHandler(CHArchTrapFrame *Frame)
CriticalSection cs;
debug("Interrupts? %s.", cs.IsInterruptsEnabled() ? "Yes" : "No");
fixme("Handling user mode exception");
TaskManager->GetCurrentThread()->Status = Tasking::TaskStatus::Stopped;
thisThread->Status = Tasking::TaskStatus::Zombie;
CPUData *CurCPU = GetCurrentCPU();
{
@ -354,7 +354,7 @@ SafeFunction void UserModeExceptionHandler(CHArchTrapFrame *Frame)
if (CurCPU->CurrentThread->Stack->Expand(CrashHandler::PageFaultAddress))
{
debug("Stack expanded");
TaskManager->GetCurrentThread()->Status = Tasking::TaskStatus::Ready;
thisThread->Status = Tasking::TaskStatus::Ready;
return;
}
break;
@ -389,7 +389,7 @@ SafeFunction void UserModeExceptionHandler(CHArchTrapFrame *Frame)
}
}
TaskManager->GetCurrentThread()->Status = Tasking::TaskStatus::Terminated;
thisThread->Status = Tasking::TaskStatus::Terminated;
__sync;
error("End of report.");
CPU::Interrupts(CPU::Enable);

View File

@ -29,7 +29,7 @@ namespace Disk
void Manager::FetchDisks(unsigned long DriverUID)
{
KernelCallback callback{};
callback.Reason = FetchReason;
callback.Reason = QueryReason;
DriverManager->IOCB(DriverUID, &callback);
this->AvailablePorts = callback.DiskCallback.Fetch.Ports;
this->BytesPerSector = callback.DiskCallback.Fetch.BytesPerSector;

View File

@ -83,29 +83,29 @@ namespace Driver
{
debug("Searching for driver %ld", DUID);
foreach (auto Drv in Drivers)
forItr(Drv, Drivers)
{
if (Drv.DriverUID != DUID)
if (Drv->DriverUID != DUID)
continue;
KernelCallback callback{};
callback.Reason = StopReason;
debug("Stopping & unloading driver %ld [%#lx]", Drv.DriverUID, Drv.Address);
this->IOCB(Drv.DriverUID, &callback);
debug("Stopping & unloading driver %ld [%#lx]", Drv->DriverUID, Drv->Address);
this->IOCB(Drv->DriverUID, &callback);
for (size_t j = 0; j < sizeof(Drv.InterruptHook) / sizeof(Drv.InterruptHook[0]); j++)
for (size_t j = 0; j < sizeof(Drv->InterruptHook) / sizeof(Drv->InterruptHook[0]); j++)
{
if (!Drv.InterruptHook[j])
if (!Drv->InterruptHook[j])
continue;
debug("Interrupt hook %#lx", Drv.InterruptHook[j]);
delete Drv.InterruptHook[j], Drv.InterruptHook[j] = nullptr;
debug("Interrupt hook %#lx", Drv->InterruptHook[j]);
delete Drv->InterruptHook[j], Drv->InterruptHook[j] = nullptr;
}
if (Drv.MemTrk)
delete Drv.MemTrk, Drv.MemTrk = nullptr;
if (Drv->MemTrk)
delete Drv->MemTrk, Drv->MemTrk = nullptr;
Drivers.remove(Drv);
Drivers.erase(Drv);
return true;
}
return false;
@ -157,7 +157,7 @@ namespace Driver
return DriverCode::OK;
}
DriverCode Driver::LoadDriver(uintptr_t DriverAddress, uintptr_t Size)
DriverCode Driver::LoadDriver(uintptr_t DriverAddress, size_t Size)
{
Fex *DrvHdr = (Fex *)DriverAddress;
if (DrvHdr->Magic[0] != 'F' || DrvHdr->Magic[1] != 'E' || DrvHdr->Magic[2] != 'X' || DrvHdr->Magic[3] != '\0')
@ -201,22 +201,23 @@ namespace Driver
StartAHCI();
StartVMwareMouse();
StartPS2Mouse();
StartPS2Keyboard();
StartATA();
StartAC97();
StartRTL8139();
StartPCNET();
StartGigabit();
VirtualFileSystem::File DriverDirectory = vfs->Open(Config.DriverDirectory);
if (!DriverDirectory.IsOK())
RefNode *DriverDirectory = vfs->Open(Config.DriverDirectory);
if (!DriverDirectory)
{
KPrint("\eE85230Failed to open driver directory: %s! (Status: %#lx)", Config.DriverDirectory, DriverDirectory.Status);
vfs->Close(DriverDirectory);
KPrint("\eE85230Failed to open %s: %d)",
Config.DriverDirectory, errno);
return;
}
debug("Loading drivers from %s", Config.DriverDirectory);
foreach (auto DrvFile in DriverDirectory.GetChildren())
foreach (auto DrvFile in DriverDirectory->GetNode()->Children)
{
if (DrvFile->Flags != VirtualFileSystem::NodeFlags::FILE)
continue;
@ -241,7 +242,7 @@ namespace Driver
}
}
}
vfs->Close(DriverDirectory);
delete DriverDirectory;
}
Driver::Driver() {}

View File

@ -34,6 +34,9 @@ namespace Driver
DriverCode Driver::DriverLoadBindInput(uintptr_t DriverAddress, size_t Size, bool IsBuiltIn)
{
stub;
UNUSED(DriverAddress);
UNUSED(Size);
UNUSED(IsBuiltIn);
return DriverCode::NOT_IMPLEMENTED;
}
}

View File

@ -33,7 +33,7 @@ namespace Driver
{
DriverCode Driver::DriverLoadBindInterrupt(uintptr_t DriverAddress, size_t Size, bool IsBuiltIn)
{
Memory::MemMgr *mem = new Memory::MemMgr(nullptr, TaskManager->GetCurrentProcess()->memDirectory);
Memory::MemMgr *mem = new Memory::MemMgr(nullptr, thisProcess->memDirectory);
BuiltInDriverInfo *bidi = (BuiltInDriverInfo *)DriverAddress;
Fex *fex = nullptr;

View File

@ -61,7 +61,7 @@ namespace Driver
debug("[%ld] VendorID: %#x; DeviceID: %#x",
devices.size(), PCIDevice->VendorID, PCIDevice->DeviceID);
Memory::MemMgr *mem = new Memory::MemMgr(nullptr, TaskManager->GetCurrentProcess()->memDirectory);
Memory::MemMgr *mem = new Memory::MemMgr(nullptr, thisProcess->memDirectory);
BuiltInDriverInfo *bidi = (BuiltInDriverInfo *)DriverAddress;
Fex *fex = nullptr;

View File

@ -34,6 +34,9 @@ namespace Driver
DriverCode Driver::DriverLoadBindProcess(uintptr_t DriverAddress, size_t Size, bool IsBuiltIn)
{
stub;
UNUSED(DriverAddress);
UNUSED(Size);
UNUSED(IsBuiltIn);
return DriverCode::NOT_IMPLEMENTED;
}
}

View File

@ -70,10 +70,12 @@ namespace Interrupts
CoreData->Stack = (uintptr_t)KernelAllocator.RequestPages(TO_PAGES(STACK_SIZE + 1)) + STACK_SIZE;
if (CoreData->Checksum != CPU_DATA_CHECKSUM)
{
KPrint("CPU %d checksum mismatch! %x != %x", Core, CoreData->Checksum, CPU_DATA_CHECKSUM);
KPrint("CPU %d checksum mismatch! %x != %x",
Core, CoreData->Checksum, CPU_DATA_CHECKSUM);
CPU::Stop();
}
debug("Stack for core %d is %#lx (Address: %#lx)", Core, CoreData->Stack, CoreData->Stack - STACK_SIZE);
debug("Stack for core %d is %#lx (Address: %#lx)",
Core, CoreData->Stack, CoreData->Stack - STACK_SIZE);
InitializeSystemCalls();
#elif defined(a32)
GlobalDescriptorTable::Init(Core);
@ -165,12 +167,13 @@ namespace Interrupts
foreach (auto ev in RegisteredEvents)
{
#if defined(a86)
if ((ev.ID + CPU::x86::IRQ0) == static_cast<int>(Frame->InterruptNumber))
if ((ev.ID + CPU::x86::IRQ0) == s_cst(int, Frame->InterruptNumber))
#elif defined(aa64)
if (ev.ID == static_cast<int>(Frame->InterruptNumber))
if (ev.ID == s_cst(int, Frame->InterruptNumber))
#endif
{
((Handler *)ev.Data)->OnInterruptReceived(Frame);
Handler *hnd = (Handler *)ev.Data;
hnd->OnInterruptReceived(Frame);
InterruptHandled = true;
}
}
@ -220,11 +223,12 @@ namespace Interrupts
Handler::~Handler()
{
debug("Unregistering interrupt handler for IRQ%d.", this->InterruptNumber);
for (size_t i = 0; i < RegisteredEvents.size(); i++)
forItr(itr, RegisteredEvents)
{
if (RegisteredEvents[i].ID == this->InterruptNumber)
if (itr->ID == this->InterruptNumber)
{
RegisteredEvents.remove(i);
RegisteredEvents.erase(itr);
return;
}
}

View File

@ -27,6 +27,7 @@
#endif
#ifdef PRINT_BACKTRACE
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wframe-address"
void PrintStacktrace(LockClass::SpinLockData *Lock)
@ -39,26 +40,31 @@ void PrintStacktrace(LockClass::SpinLockData *Lock)
uintptr_t ReturnAddress;
};
char DbgAttempt[1024] = "\0";
char DbgHolder[1024] = "\0";
// char DbgAttempt[1024] = "\0";
// char DbgHolder[1024] = "\0";
std::string DbgAttempt = "\0";
std::string DbgHolder = "\0";
StackFrame *FrameAttempt = (StackFrame *)Lock->StackPointerAttempt.load();
StackFrame *FrameHolder = (StackFrame *)Lock->StackPointerHolder.load();
while (Memory::Virtual().Check(FrameAttempt))
{
sprintf(DbgAttempt + strlen(DbgAttempt), "%s<-", KernelSymbolTable->GetSymbolFromAddress(FrameAttempt->ReturnAddress));
DbgAttempt.concat(KernelSymbolTable->GetSymbolFromAddress(FrameAttempt->ReturnAddress));
DbgAttempt.concat("<-");
FrameAttempt = (StackFrame *)FrameAttempt->BasePointer;
}
debug("Attempt: %s", DbgAttempt.c_str());
while (Memory::Virtual().Check(FrameHolder))
{
sprintf(DbgHolder + strlen(DbgHolder), "%s<-", KernelSymbolTable->GetSymbolFromAddress(FrameHolder->ReturnAddress));
DbgHolder.concat(KernelSymbolTable->GetSymbolFromAddress(FrameHolder->ReturnAddress));
DbgHolder.concat("<-");
FrameHolder = (StackFrame *)FrameHolder->BasePointer;
}
debug("Attempt: %s", DbgAttempt);
debug("Holder: %s", DbgHolder);
debug("Holder: %s", DbgHolder.c_str());
// debug("\t\t%s<-%s<-%s<-%s<-%s<-%s<-%s<-%s<-%s<-%s",
// KernelSymbolTable->GetSymbolFromAddress((uintptr_t)__builtin_return_address(0)),
@ -73,6 +79,15 @@ void PrintStacktrace(LockClass::SpinLockData *Lock)
// KernelSymbolTable->GetSymbolFromAddress((uintptr_t)__builtin_return_address(9)));
}
}
#pragma GCC diagnostic pop
#endif
#ifdef DEBUG
#define DEADLOCK_TIMEOUT 0x100000
#define DEADLOCK_TIMEOUT_DEBUGGER 0x1000
#else
#define DEADLOCK_TIMEOUT 0x10000000
#define DEADLOCK_TIMEOUT_DEBUGGER 0x100000
#endif
bool ForceUnlock = false;
@ -80,11 +95,24 @@ std::atomic_size_t LocksCount = 0;
size_t GetLocksCount() { return LocksCount.load(); }
void LockClass::DeadLock(SpinLockData Lock)
void LockClass::Yield()
{
if (CPU::Interrupts(CPU::Check) &&
TaskManager &&
!TaskManager->IsPanic())
{
TaskManager->Yield();
}
CPU::Pause();
}
void LockClass::DeadLock(SpinLockData &Lock)
{
if (ForceUnlock)
{
warn("Unlocking lock '%s' which it was held by '%s'...", Lock.AttemptingToGet, Lock.CurrentHolder);
warn("Unlocking lock '%s' which it was held by '%s'...",
Lock.AttemptingToGet, Lock.CurrentHolder);
this->DeadLocks = 0;
this->Unlock();
return;
@ -116,8 +144,7 @@ void LockClass::DeadLock(SpinLockData Lock)
this->Unlock();
}
if (TaskManager && !TaskManager->IsPanic())
TaskManager->Schedule();
this->Yield();
}
int LockClass::Lock(const char *FunctionName)
@ -127,16 +154,13 @@ int LockClass::Lock(const char *FunctionName)
Retry:
int i = 0;
while (IsLocked.exchange(true, std::memory_order_acquire) && ++i < (DebuggerIsAttached ? 0x100000 : 0x10000000))
while (IsLocked.exchange(true, std::memory_order_acquire) &&
++i < (DebuggerIsAttached ? DEADLOCK_TIMEOUT_DEBUGGER : DEADLOCK_TIMEOUT))
{
/* FIXME */
// if (TaskManager && !TaskManager->IsPanic())
// TaskManager->Schedule();
// else
CPU::Pause();
this->Yield();
}
if (i >= (DebuggerIsAttached ? 0x100000 : 0x10000000))
if (i >= (DebuggerIsAttached ? DEADLOCK_TIMEOUT_DEBUGGER : DEADLOCK_TIMEOUT))
{
DeadLock(LockData);
goto Retry;
@ -167,7 +191,7 @@ int LockClass::Unlock()
return 0;
}
void LockClass::TimeoutDeadLock(SpinLockData Lock, uint64_t Timeout)
void LockClass::TimeoutDeadLock(SpinLockData &Lock, uint64_t Timeout)
{
CPUData *CoreData = GetCurrentCPU();
long CCore = 0xdead;
@ -189,12 +213,12 @@ void LockClass::TimeoutDeadLock(SpinLockData Lock, uint64_t Timeout)
if (Timeout < Counter)
{
warn("Unlocking lock '%s' because of timeout. (%ld < %ld)", Lock.AttemptingToGet, Timeout, Counter);
warn("Unlocking lock '%s' because of timeout. (%ld < %ld)",
Lock.AttemptingToGet, Timeout, Counter);
this->Unlock();
}
if (TaskManager && !TaskManager->IsPanic())
TaskManager->Schedule();
this->Yield();
}
int LockClass::TimeoutLock(const char *FunctionName, uint64_t Timeout)
@ -208,19 +232,17 @@ int LockClass::TimeoutLock(const char *FunctionName, uint64_t Timeout)
std::atomic_uint64_t Target = 0;
Retry:
int i = 0;
while (IsLocked.exchange(true, std::memory_order_acquire) && ++i < (DebuggerIsAttached ? 0x100000 : 0x10000000))
while (IsLocked.exchange(true, std::memory_order_acquire) &&
++i < (DebuggerIsAttached ? DEADLOCK_TIMEOUT_DEBUGGER : DEADLOCK_TIMEOUT))
{
/* FIXME */
// if (TaskManager && !TaskManager->IsPanic())
// TaskManager->Schedule();
// else
CPU::Pause();
this->Yield();
}
if (i >= (DebuggerIsAttached ? 0x100000 : 0x10000000))
if (i >= (DebuggerIsAttached ? DEADLOCK_TIMEOUT_DEBUGGER : DEADLOCK_TIMEOUT))
{
if (Target.load() == 0)
Target.store(TimeManager->CalculateTarget(Timeout, Time::Units::Milliseconds));
Target.store(TimeManager->CalculateTarget(Timeout,
Time::Units::Milliseconds));
TimeoutDeadLock(LockData, Target.load());
goto Retry;
}

View File

@ -22,7 +22,7 @@ Xalloc_def;
#define XALLOC_CONCAT(x, y) x##y
#define XStoP(d) (((d) + PAGE_SIZE - 1) / PAGE_SIZE)
#define XPtoS(d) ((d)*PAGE_SIZE)
#define Xalloc_BlockChecksum 0xA110C
#define Xalloc_BlockSanityKey 0xA110C
extern "C" void *Xalloc_REQUEST_PAGES(Xsize_t Pages);
extern "C" void Xalloc_FREE_PAGES(void *Address, Xsize_t Pages);
@ -55,7 +55,7 @@ namespace Xalloc
public:
void *Address = nullptr;
int Checksum = Xalloc_BlockChecksum;
int Sanity = Xalloc_BlockSanityKey;
Xsize_t Size = 0;
Block *Next = nullptr;
Block *Last = nullptr;
@ -63,7 +63,7 @@ namespace Xalloc
bool Check()
{
if (this->Checksum != Xalloc_BlockChecksum)
if (this->Sanity != Xalloc_BlockSanityKey)
return false;
return true;
}
@ -168,8 +168,8 @@ namespace Xalloc
{
if (!CurrentBlock->Check())
{
Xalloc_err("Block %#lx has an invalid checksum! (%#x != %#x)",
(Xuint64_t)CurrentBlock, CurrentBlock->Checksum, Xalloc_BlockChecksum);
Xalloc_err("Block %#lx has an invalid sanity key! (%#x != %#x)",
(Xuint64_t)CurrentBlock, CurrentBlock->Sanity, Xalloc_BlockSanityKey);
while (Xalloc_StopOnFail)
;
}
@ -210,8 +210,8 @@ namespace Xalloc
{
if (!CurrentBlock->Check())
{
Xalloc_err("Block %#lx has an invalid checksum! (%#x != %#x)",
(Xuint64_t)CurrentBlock, CurrentBlock->Checksum, Xalloc_BlockChecksum);
Xalloc_err("Block %#lx has an invalid sanity key! (%#x != %#x)",
(Xuint64_t)CurrentBlock, CurrentBlock->Sanity, Xalloc_BlockSanityKey);
while (Xalloc_StopOnFail)
;
}

View File

@ -51,7 +51,7 @@ PageTable *KernelPageTable = nullptr;
bool Page1GBSupport = false;
bool PSESupport = false;
static MemoryAllocatorType AllocatorType = MemoryAllocatorType::Pages;
MemoryAllocatorType AllocatorType = MemoryAllocatorType::Pages;
Xalloc::V1 *XallocV1Allocator = nullptr;
#ifdef DEBUG
@ -94,7 +94,7 @@ NIF void MapFromZero(PageTable *PT)
// (void *)Physical4KBSectionStart,
// MemSize - Physical4KBSectionStart,
// PTFlag::RW,
// Virtual::MapType::OneGB);
// Virtual::MapType::OneGiB);
va.Map((void *)0, (void *)0, MemSize, PTFlag::RW);
}
@ -167,8 +167,10 @@ NIF void MapKernel(PageTable *PT)
uintptr_t KernelBssStart = (uintptr_t)&_kernel_bss_start;
uintptr_t KernelBssEnd = (uintptr_t)&_kernel_bss_end;
#ifdef DEBUG
uintptr_t KernelStart = (uintptr_t)&_kernel_start;
uintptr_t KernelEnd = (uintptr_t)&_kernel_end;
#endif
uintptr_t KernelFileStart = (uintptr_t)bInfo.Kernel.FileBase;
uintptr_t KernelFileEnd = KernelFileStart + bInfo.Kernel.Size;
@ -180,12 +182,12 @@ NIF void MapKernel(PageTable *PT)
debug("Kernel: %#lx-%#lx", KernelStart, KernelEnd);
debug("Kernel file: %#lx-%#lx", KernelFileStart, KernelFileEnd);
debug("File size: %ld KB", TO_KB(bInfo.Kernel.Size));
debug(".bootstrap size: %ld KB", TO_KB(BootstrapEnd - BootstrapStart));
debug(".text size: %ld KB", TO_KB(KernelTextEnd - KernelTextStart));
debug(".data size: %ld KB", TO_KB(KernelDataEnd - KernelDataStart));
debug(".rodata size: %ld KB", TO_KB(KernelRoDataEnd - KernelRoDataStart));
debug(".bss size: %ld KB", TO_KB(KernelBssEnd - KernelBssStart));
debug("File size: %ld KiB", TO_KiB(bInfo.Kernel.Size));
debug(".bootstrap size: %ld KiB", TO_KiB(BootstrapEnd - BootstrapStart));
debug(".text size: %ld KiB", TO_KiB(KernelTextEnd - KernelTextStart));
debug(".data size: %ld KiB", TO_KiB(KernelDataEnd - KernelDataStart));
debug(".rodata size: %ld KiB", TO_KiB(KernelRoDataEnd - KernelRoDataStart));
debug(".bss size: %ld KiB", TO_KiB(KernelBssEnd - KernelBssStart));
uintptr_t BaseKernelMapAddress = (uintptr_t)bInfo.Kernel.PhysicalBase;
debug("Base kernel map address: %#lx", BaseKernelMapAddress);
@ -336,10 +338,10 @@ NIF void InitializeMemoryManagement()
trace("Initializing Physical Memory Manager");
// KernelAllocator = Physical(); <- Already called in the constructor
KernelAllocator.Init();
debug("Memory Info: %lldMB / %lldMB (%lldMB reserved)",
TO_MB(KernelAllocator.GetUsedMemory()),
TO_MB(KernelAllocator.GetTotalMemory()),
TO_MB(KernelAllocator.GetReservedMemory()));
debug("Memory Info:\n\n%lld MiB / %lld MiB (%lld MiB reserved)\n",
TO_MiB(KernelAllocator.GetUsedMemory()),
TO_MiB(KernelAllocator.GetTotalMemory()),
TO_MiB(KernelAllocator.GetReservedMemory()));
/* -- Debugging --
size_t bmap_size = KernelAllocator.GetPageBitmap().Size;
@ -401,20 +403,17 @@ NIF void InitializeMemoryManagement()
#endif
CPU::PageTable(KernelPageTable);
debug("Page table updated.");
if (strstr(bInfo.Kernel.CommandLine, "xallocv1"))
{
/* FIXME: Read kernel config */
XallocV1Allocator = new Xalloc::V1((void *)KERNEL_HEAP_BASE, false, false);
AllocatorType = MemoryAllocatorType::XallocV1;
trace("XallocV1 Allocator initialized (%p)", XallocV1Allocator);
}
else if (strstr(bInfo.Kernel.CommandLine, "liballoc11"))
{
AllocatorType = MemoryAllocatorType::liballoc11;
}
}
void *malloc(size_t Size)
{
assert(Size > 0);
#ifdef DEBUG_ALLOCATIONS_SL
SmartLockClass lock___COUNTER__(AllocatorLock, (KernelSymbolTable ? KernelSymbolTable->GetSymbolFromAddress((uintptr_t)__builtin_return_address(0)) : "Unknown"));
#endif
@ -471,6 +470,8 @@ void *malloc(size_t Size)
void *calloc(size_t n, size_t Size)
{
assert(Size > 0);
#ifdef DEBUG_ALLOCATIONS_SL
SmartLockClass lock___COUNTER__(AllocatorLock, (KernelSymbolTable ? KernelSymbolTable->GetSymbolFromAddress((uintptr_t)__builtin_return_address(0)) : "Unknown"));
#endif
@ -527,6 +528,8 @@ void *calloc(size_t n, size_t Size)
void *realloc(void *Address, size_t Size)
{
assert(Size > 0);
#ifdef DEBUG_ALLOCATIONS_SL
SmartLockClass lock___COUNTER__(AllocatorLock, (KernelSymbolTable ? KernelSymbolTable->GetSymbolFromAddress((uintptr_t)__builtin_return_address(0)) : "Unknown"));
#endif
@ -583,6 +586,8 @@ void *realloc(void *Address, size_t Size)
void free(void *Address)
{
assert(Address != nullptr);
#ifdef DEBUG_ALLOCATIONS_SL
SmartLockClass lock___COUNTER__(AllocatorLock, (KernelSymbolTable ? KernelSymbolTable->GetSymbolFromAddress((uintptr_t)__builtin_return_address(0)) : "Unknown"));
#endif
@ -636,6 +641,8 @@ void free(void *Address)
void *operator new(std::size_t Size)
{
assert(Size > 0);
#ifdef DEBUG_ALLOCATIONS_SL
SmartLockClass lock___COUNTER__(OperatorAllocatorLock, (KernelSymbolTable ? KernelSymbolTable->GetSymbolFromAddress((uintptr_t)__builtin_return_address(0)) : "Unknown"));
#endif
@ -667,6 +674,8 @@ void *operator new(std::size_t Size)
void *operator new[](std::size_t Size)
{
assert(Size > 0);
#ifdef DEBUG_ALLOCATIONS_SL
SmartLockClass lock___COUNTER__(OperatorAllocatorLock, (KernelSymbolTable ? KernelSymbolTable->GetSymbolFromAddress((uintptr_t)__builtin_return_address(0)) : "Unknown"));
#endif
@ -698,6 +707,8 @@ void *operator new[](std::size_t Size)
void *operator new(std::size_t Size, std::align_val_t Alignment)
{
assert(Size > 0);
#ifdef DEBUG_ALLOCATIONS_SL
SmartLockClass lock___COUNTER__(OperatorAllocatorLock, (KernelSymbolTable ? KernelSymbolTable->GetSymbolFromAddress((uintptr_t)__builtin_return_address(0)) : "Unknown"));
#endif
@ -712,9 +723,15 @@ void *operator new(std::size_t Size, std::align_val_t Alignment)
strcpy_unsafe(LockTmpStr, __FUNCTION__);
strcat_unsafe(LockTmpStr, "_memTrk");
mExtTrkLock.TimeoutLock(LockTmpStr, 10000);
#if defined(a64) || defined(aa64)
sprintf(mExtTrkLog, "new( %ld %#lx )=%p~%p\n\r",
Size, (uintptr_t)Alignment,
ret, __builtin_return_address(0));
#elif defined(a32)
sprintf(mExtTrkLog, "new( %ld %#x )=%p~%p\n\r",
Size, (uintptr_t)Alignment,
ret, __builtin_return_address(0));
#endif
UniversalAsynchronousReceiverTransmitter::UART mTrkUART = UniversalAsynchronousReceiverTransmitter::UART(UniversalAsynchronousReceiverTransmitter::COM3);
for (short i = 0; i < MEM_TRK_MAX_SIZE; i++)
{
@ -730,6 +747,8 @@ void *operator new(std::size_t Size, std::align_val_t Alignment)
void operator delete(void *Pointer)
{
assert(Pointer != nullptr);
#ifdef DEBUG_ALLOCATIONS_SL
SmartLockClass lock___COUNTER__(OperatorAllocatorLock, (KernelSymbolTable ? KernelSymbolTable->GetSymbolFromAddress((uintptr_t)__builtin_return_address(0)) : "Unknown"));
#endif
@ -760,6 +779,8 @@ void operator delete(void *Pointer)
void operator delete[](void *Pointer)
{
assert(Pointer != nullptr);
#ifdef DEBUG_ALLOCATIONS_SL
SmartLockClass lock___COUNTER__(OperatorAllocatorLock, (KernelSymbolTable ? KernelSymbolTable->GetSymbolFromAddress((uintptr_t)__builtin_return_address(0)) : "Unknown"));
#endif
@ -790,7 +811,9 @@ void operator delete[](void *Pointer)
void operator delete(void *Pointer, long unsigned int Size)
{
UNUSED(Size);
assert(Pointer != nullptr);
assert(Size > 0);
#ifdef DEBUG_ALLOCATIONS_SL
SmartLockClass lock___COUNTER__(OperatorAllocatorLock, (KernelSymbolTable ? KernelSymbolTable->GetSymbolFromAddress((uintptr_t)__builtin_return_address(0)) : "Unknown"));
#endif
@ -821,7 +844,9 @@ void operator delete(void *Pointer, long unsigned int Size)
void operator delete[](void *Pointer, long unsigned int Size)
{
UNUSED(Size);
assert(Pointer != nullptr);
assert(Size > 0);
#ifdef DEBUG_ALLOCATIONS_SL
SmartLockClass lock___COUNTER__(OperatorAllocatorLock, (KernelSymbolTable ? KernelSymbolTable->GetSymbolFromAddress((uintptr_t)__builtin_return_address(0)) : "Unknown"));
#endif

View File

@ -27,13 +27,13 @@ namespace Memory
if (!Size)
Size = node->Length;
if ((size_t)node->Offset > node->Length)
if (RefOffset > node->Length)
return 0;
if (node->Offset + Size > node->Length)
Size = node->Length - node->Offset;
if (RefOffset + (off_t)Size > node->Length)
Size = node->Length - RefOffset;
memcpy(Buffer, (uint8_t *)(node->Address + node->Offset), Size);
memcpy(Buffer, (uint8_t *)(node->Address + RefOffset), Size);
return Size;
}
@ -42,13 +42,13 @@ namespace Memory
if (!Size)
Size = node->Length;
if ((size_t)node->Offset > node->Length)
if (RefOffset > node->Length)
return 0;
if (node->Offset + Size > node->Length)
Size = node->Length - node->Offset;
if (RefOffset + (off_t)Size > node->Length)
Size = node->Length - RefOffset;
memcpy((uint8_t *)(node->Address + node->Offset), Buffer, Size);
memcpy((uint8_t *)(node->Address + RefOffset), Buffer, Size);
return Size;
}
@ -110,7 +110,11 @@ namespace Memory
if (this->Directory)
{
char FileName[64];
#if defined(a64) || defined(aa64)
sprintf(FileName, "%lx-%ld", (uintptr_t)Address, Count);
#elif defined(a32)
sprintf(FileName, "%x-%ld", (uintptr_t)Address, Count);
#endif
VirtualFileSystem::Node *n = vfs->Create(FileName, VirtualFileSystem::NodeFlags::FILE, this->Directory);
if (n)
{
@ -143,7 +147,11 @@ namespace Memory
if (this->Directory)
{
char FileName[64];
#if defined(a64) || defined(aa64)
sprintf(FileName, "%lx-%ld", (uintptr_t)Address, Count);
#elif defined(a32)
sprintf(FileName, "%x-%ld", (uintptr_t)Address, Count);
#endif
VirtualFileSystem::Node *n = vfs->Create(FileName, VirtualFileSystem::NodeFlags::FILE, this->Directory);
if (n) // If null, error or file already exists
{
@ -166,9 +174,9 @@ namespace Memory
void MemMgr::FreePages(void *Address, size_t Count)
{
SmartLock(MgrLock);
for (size_t i = 0; i < AllocatedPagesList.size(); i++)
forItr(itr, AllocatedPagesList)
{
if (AllocatedPagesList[i].Address == Address)
if (itr->Address == Address)
{
/** TODO: Advanced checks. Allow if the page count is less than the requested one.
* This will allow the user to free only a part of the allocated pages.
@ -176,9 +184,9 @@ namespace Memory
* But this will be in a separate function because we need to specify if we
* want to free from the start or from the end and return the new address.
*/
if (AllocatedPagesList[i].PageCount != Count)
if (itr->PageCount != Count)
{
error("Page count mismatch! (Allocated: %lld, Requested: %lld)", AllocatedPagesList[i].PageCount, Count);
error("Page count mismatch! (Allocated: %lld, Requested: %lld)", itr->PageCount, Count);
return;
}
@ -195,13 +203,16 @@ namespace Memory
if (this->Directory)
{
char FileName[64];
#if defined(a64) || defined(aa64)
sprintf(FileName, "%lx-%ld", (uintptr_t)Address, Count);
VirtualFileSystem::FileStatus s = vfs->Delete(FileName, false, this->Directory);
if (s != VirtualFileSystem::FileStatus::OK)
#elif defined(a32)
sprintf(FileName, "%x-%ld", (uintptr_t)Address, Count);
#endif
if (!vfs->Delete(FileName, false, this->Directory))
error("Failed to delete file %s", FileName);
}
AllocatedPagesList.remove(i);
AllocatedPagesList.erase(itr);
return;
}
}
@ -210,20 +221,23 @@ namespace Memory
void MemMgr::DetachAddress(void *Address)
{
SmartLock(MgrLock);
for (size_t i = 0; i < AllocatedPagesList.size(); i++)
forItr(itr, AllocatedPagesList)
{
if (AllocatedPagesList[i].Address == Address)
if (itr->Address == Address)
{
if (this->Directory)
{
char FileName[64];
sprintf(FileName, "%lx-%ld", (uintptr_t)Address, AllocatedPagesList[i].PageCount);
VirtualFileSystem::FileStatus s = vfs->Delete(FileName, false, this->Directory);
if (s != VirtualFileSystem::FileStatus::OK)
#if defined(a64) || defined(aa64)
sprintf(FileName, "%lx-%ld", (uintptr_t)Address, itr->PageCount);
#elif defined(a32)
sprintf(FileName, "%x-%ld", (uintptr_t)Address, itr->PageCount);
#endif
if (!vfs->Delete(FileName, false, this->Directory))
error("Failed to delete file %s", FileName);
}
AllocatedPagesList.remove(i);
AllocatedPagesList.erase(itr);
return;
}
}
@ -244,7 +258,8 @@ namespace Memory
}
this->Directory = Directory;
debug("+ %#lx", this);
debug("+ %#lx %s", this,
KernelSymbolTable ? KernelSymbolTable->GetSymbolFromAddress((uintptr_t)__builtin_return_address(0)) : "");
}
MemMgr::~MemMgr()
@ -266,6 +281,7 @@ namespace Memory
vfs->Delete(Child, true);
}
debug("- %#lx", this);
debug("- %#lx %s", this,
KernelSymbolTable ? KernelSymbolTable->GetSymbolFromAddress((uintptr_t)__builtin_return_address(0)) : "");
}
}

View File

@ -28,26 +28,22 @@ namespace Memory
{
uint64_t Physical::GetTotalMemory()
{
SmartLock(this->MemoryLock);
return this->TotalMemory;
return this->TotalMemory.load();
}
uint64_t Physical::GetFreeMemory()
{
SmartLock(this->MemoryLock);
return this->FreeMemory;
return this->FreeMemory.load();
}
uint64_t Physical::GetReservedMemory()
{
SmartLock(this->MemoryLock);
return this->ReservedMemory;
return this->ReservedMemory.load();
}
uint64_t Physical::GetUsedMemory()
{
SmartLock(this->MemoryLock);
return this->UsedMemory;
return this->UsedMemory.load();
}
bool Physical::SwapPage(void *Address)
@ -123,11 +119,14 @@ namespace Memory
if (TaskManager && !TaskManager->IsPanic())
{
error("Out of memory! Killing current process...");
TaskManager->KillProcess(TaskManager->GetCurrentProcess(), Tasking::KILL_OOM);
TaskManager->Schedule();
TaskManager->KillProcess(thisProcess, Tasking::KILL_OOM);
TaskManager->Yield();
}
error("Out of memory! (Free: %ldMB; Used: %ldMB; Reserved: %ldMB)", TO_MB(FreeMemory), TO_MB(UsedMemory), TO_MB(ReservedMemory));
error("Out of memory! (Free: %ld MiB; Used: %ld MiB; Reserved: %ld MiB)",
TO_MiB(FreeMemory), TO_MiB(UsedMemory), TO_MiB(ReservedMemory));
KPrint("Out of memory! (Free: %ld MiB; Used: %ld MiB; Reserved: %ld MiB)",
TO_MiB(FreeMemory), TO_MiB(UsedMemory), TO_MiB(ReservedMemory));
CPU::Stop();
__builtin_unreachable();
}
@ -190,11 +189,14 @@ namespace Memory
if (TaskManager && !TaskManager->IsPanic())
{
error("Out of memory! Killing current process...");
TaskManager->KillProcess(TaskManager->GetCurrentProcess(), Tasking::KILL_OOM);
TaskManager->Schedule();
TaskManager->KillProcess(thisProcess, Tasking::KILL_OOM);
TaskManager->Yield();
}
error("Out of memory! (Free: %ldMB; Used: %ldMB; Reserved: %ldMB)", TO_MB(FreeMemory), TO_MB(UsedMemory), TO_MB(ReservedMemory));
error("Out of memory! (Free: %ld MiB; Used: %ld MiB; Reserved: %ld MiB)",
TO_MiB(FreeMemory), TO_MiB(UsedMemory), TO_MiB(ReservedMemory));
KPrint("Out of memory! (Free: %ld MiB; Used: %ld MiB; Reserved: %ld MiB)",
TO_MiB(FreeMemory), TO_MiB(UsedMemory), TO_MiB(ReservedMemory));
CPU::Halt(true);
__builtin_unreachable();
}
@ -213,7 +215,8 @@ namespace Memory
if (unlikely(PageBitmap[Index] == false))
{
warn("Tried to free an already free page. (%p)", Address);
warn("Tried to free an already free page. (%p)",
Address);
return;
}
@ -298,7 +301,9 @@ namespace Memory
void Physical::LockPages(void *Address, size_t PageCount)
{
if (unlikely(Address == nullptr || PageCount == 0))
warn("Trying to lock %s%s.", Address ? "null address" : "", PageCount ? "0 pages" : "");
warn("Trying to lock %s%s.",
Address ? "null address" : "",
PageCount ? "0 pages" : "");
for (size_t i = 0; i < PageCount; i++)
this->LockPage((void *)((uintptr_t)Address + (i * PAGE_SIZE)));
@ -324,7 +329,9 @@ namespace Memory
void Physical::ReservePages(void *Address, size_t PageCount)
{
if (unlikely(Address == nullptr || PageCount == 0))
warn("Trying to reserve %s%s.", Address ? "null address" : "", PageCount ? "0 pages" : "");
warn("Trying to reserve %s%s.",
Address ? "null address" : "",
PageCount ? "0 pages" : "");
for (size_t t = 0; t < PageCount; t++)
{
@ -363,7 +370,9 @@ namespace Memory
void Physical::UnreservePages(void *Address, size_t PageCount)
{
if (unlikely(Address == nullptr || PageCount == 0))
warn("Trying to unreserve %s%s.", Address ? "null address" : "", PageCount ? "0 pages" : "");
warn("Trying to unreserve %s%s.",
Address ? "null address" : "",
PageCount ? "0 pages" : "");
for (size_t t = 0; t < PageCount; t++)
{
@ -387,7 +396,8 @@ namespace Memory
SmartLock(this->MemoryLock);
uint64_t MemorySize = bInfo.Memory.Size;
debug("Memory size: %lld bytes (%ld pages)", MemorySize, TO_PAGES(MemorySize));
debug("Memory size: %lld bytes (%ld pages)",
MemorySize, TO_PAGES(MemorySize));
TotalMemory = MemorySize;
FreeMemory = MemorySize;
@ -405,16 +415,16 @@ namespace Memory
uintptr_t RegionAddress = (uintptr_t)bInfo.Memory.Entry[i].BaseAddress;
uintptr_t RegionSize = bInfo.Memory.Entry[i].Length;
/* We don't want to use 0 as a memory address. */
if (RegionAddress == 0x0)
/* We don't want to use the first 1MB of memory. */
if (RegionAddress <= 0xFFFFF)
continue;
if ((BitmapSize + 0x100) > RegionSize)
{
debug("Region %p-%p (%dMB) is too small for bitmap.",
debug("Region %p-%p (%d MiB) is too small for bitmap.",
(void *)RegionAddress,
(void *)(RegionAddress + RegionSize),
TO_MB(RegionSize));
TO_MiB(RegionSize));
continue;
}
@ -429,10 +439,10 @@ namespace Memory
if ((BitmapSize + 0x100) > BitmapAddressSize)
{
debug("Region %p-%p (%dMB) is too small for bitmap.",
debug("Region %p-%p (%d MiB) is too small for bitmap.",
(void *)RegionAddress,
(void *)(RegionAddress + BitmapAddressSize),
TO_MB(BitmapAddressSize));
TO_MiB(BitmapAddressSize));
continue;
}
@ -453,16 +463,16 @@ namespace Memory
if ((BitmapSize + 0x100) > BitmapAddressSize)
{
debug("Region %p-%p (%dMB) is too small for bitmap.",
debug("Region %p-%p (%d MiB) is too small for bitmap.",
(void *)BitmapAddress,
(void *)(BitmapAddress + BitmapAddressSize),
TO_MB(BitmapAddressSize));
TO_MiB(BitmapAddressSize));
continue;
}
debug("Found free memory for bitmap: %p (%dMB)",
debug("Found free memory for bitmap: %p (%d MiB)",
(void *)BitmapAddress,
TO_MB(BitmapAddressSize));
TO_MiB(BitmapAddressSize));
break;
}
}

View File

@ -18,6 +18,7 @@
#include <memory.hpp>
#include <debug.h>
#include <elf.h>
#ifdef DEBUG
#include <uart.hpp>
#endif
@ -44,7 +45,13 @@ namespace Memory
for (uint64_t i = 0; i < bInfo.Memory.Entries; i++)
{
if (bInfo.Memory.Entry[i].Type == Usable)
this->UnreservePages(bInfo.Memory.Entry[i].BaseAddress, TO_PAGES(bInfo.Memory.Entry[i].Length));
{
if (uintptr_t(bInfo.Memory.Entry[i].BaseAddress) <= 0xFFFFF)
continue;
this->UnreservePages(bInfo.Memory.Entry[i].BaseAddress,
TO_PAGES(bInfo.Memory.Entry[i].Length));
}
}
debug("Reserving 0x0-0xFFFFF range...");
@ -57,18 +64,72 @@ namespace Memory
*/
this->ReservePages((void *)0x0, TO_PAGES(0xFFFFF));
debug("Reserving bitmap region %#lx-%#lx...", PageBitmap.Buffer, (void *)((uintptr_t)PageBitmap.Buffer + PageBitmap.Size));
debug("Reserving bitmap region %#lx-%#lx...",
PageBitmap.Buffer,
(void *)((uintptr_t)PageBitmap.Buffer + PageBitmap.Size));
this->ReservePages(PageBitmap.Buffer, TO_PAGES(PageBitmap.Size));
debug("Reserving kernel physical region %#lx-%#lx...", bInfo.Kernel.PhysicalBase, (void *)((uintptr_t)bInfo.Kernel.PhysicalBase + bInfo.Kernel.Size));
debug("Reserving kernel physical region %#lx-%#lx...",
bInfo.Kernel.PhysicalBase,
(void *)((uintptr_t)bInfo.Kernel.PhysicalBase + bInfo.Kernel.Size));
this->ReservePages(bInfo.Kernel.PhysicalBase, TO_PAGES(bInfo.Kernel.Size));
debug("Reserving kernel file and symbols...");
if (bInfo.Kernel.FileBase)
this->ReservePages(bInfo.Kernel.FileBase, TO_PAGES(bInfo.Kernel.Size));
if (bInfo.Kernel.Symbols.Num && bInfo.Kernel.Symbols.EntSize && bInfo.Kernel.Symbols.Shndx)
this->ReservePages((void *)bInfo.Kernel.Symbols.Sections, TO_PAGES(bInfo.Kernel.Symbols.Num * bInfo.Kernel.Symbols.EntSize));
if (bInfo.Kernel.Symbols.Num &&
bInfo.Kernel.Symbols.EntSize &&
bInfo.Kernel.Symbols.Shndx)
{
char *sections = reinterpret_cast<char *>(bInfo.Kernel.Symbols.Sections);
uint8_t *StringAddress = nullptr;
Elf_Sym *Symbols = nullptr;
#if defined(a64) || defined(aa64)
Elf64_Xword SymbolSize = 0;
Elf64_Xword StringSize = 0;
#elif defined(a32)
Elf32_Word SymbolSize = 0;
Elf32_Word StringSize = 0;
#endif
for (size_t i = 0; i < bInfo.Kernel.Symbols.Num; ++i)
{
Elf_Shdr *sym = (Elf_Shdr *)&sections[bInfo.Kernel.Symbols.EntSize * i];
Elf_Shdr *str = (Elf_Shdr *)&sections[bInfo.Kernel.Symbols.EntSize *
sym->sh_link];
if (sym->sh_type == SHT_SYMTAB &&
str->sh_type == SHT_STRTAB)
{
Symbols = (Elf_Sym *)sym->sh_addr;
StringAddress = (uint8_t *)str->sh_addr;
SymbolSize = (int)sym->sh_size;
StringSize = (int)str->sh_size;
debug("Symbol table found, %d entries",
SymbolSize / sym->sh_entsize);
break;
}
}
if (Symbols)
{
debug("Reserving symbol table region %#lx-%#lx...",
Symbols, (void *)((uintptr_t)Symbols + SymbolSize));
this->ReservePages(Symbols, TO_PAGES(SymbolSize));
}
if (StringAddress)
{
debug("Reserving string table region %#lx-%#lx...",
StringAddress, (void *)((uintptr_t)StringAddress + StringSize));
this->ReservePages(StringAddress, TO_PAGES(StringSize));
}
}
debug("Reserving kernel modules...");
@ -78,13 +139,17 @@ namespace Memory
continue;
debug("Reserving module %s (%#lx-%#lx)...", bInfo.Modules[i].CommandLine,
bInfo.Modules[i].Address, (void *)((uintptr_t)bInfo.Modules[i].Address + bInfo.Modules[i].Size));
bInfo.Modules[i].Address,
(void *)((uintptr_t)bInfo.Modules[i].Address + bInfo.Modules[i].Size));
this->ReservePages((void *)bInfo.Modules[i].Address, TO_PAGES(bInfo.Modules[i].Size));
this->ReservePages((void *)bInfo.Modules[i].Address,
TO_PAGES(bInfo.Modules[i].Size));
}
#if defined(a86)
debug("Reserving RSDT region %#lx-%#lx...", bInfo.RSDP, (void *)((uintptr_t)bInfo.RSDP + sizeof(BootInfo::RSDPInfo)));
debug("Reserving RSDT region %#lx-%#lx...", bInfo.RSDP,
(void *)((uintptr_t)bInfo.RSDP + sizeof(BootInfo::RSDPInfo)));
this->ReservePages(bInfo.RSDP, TO_PAGES(sizeof(BootInfo::RSDPInfo)));
ACPI::ACPI::ACPIHeader *ACPIPtr = nullptr;
@ -115,23 +180,27 @@ namespace Memory
}
#endif
size_t TableSize = ((ACPIPtr->Length - sizeof(ACPI::ACPI::ACPIHeader)) / (XSDT ? 8 : 4));
size_t TableSize = ((ACPIPtr->Length - sizeof(ACPI::ACPI::ACPIHeader)) /
(XSDT ? 8 : 4));
debug("Reserving %d ACPI tables...", TableSize);
for (size_t t = 0; t < TableSize; t++)
{
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wint-to-pointer-cast"
// TODO: Should I be concerned about unaligned memory access?
ACPI::ACPI::ACPIHeader *SDTHdr = nullptr;
if (XSDT)
SDTHdr = (ACPI::ACPI::ACPIHeader *)(*(uint64_t *)((uint64_t)ACPIPtr + sizeof(ACPI::ACPI::ACPIHeader) + (t * 8)));
SDTHdr =
(ACPI::ACPI::ACPIHeader *)(*(uint64_t *)((uint64_t)ACPIPtr +
sizeof(ACPI::ACPI::ACPIHeader) +
(t * 8)));
else
SDTHdr = (ACPI::ACPI::ACPIHeader *)(*(uint32_t *)((uint64_t)ACPIPtr + sizeof(ACPI::ACPI::ACPIHeader) + (t * 4)));
SDTHdr =
(ACPI::ACPI::ACPIHeader *)(*(uint32_t *)((uint64_t)ACPIPtr +
sizeof(ACPI::ACPI::ACPIHeader) +
(t * 4)));
#pragma GCC diagnostic pop
this->ReservePages(SDTHdr, TO_PAGES(SDTHdr->Length));
}

15
Core/Memory/SmartHeap.cpp Normal file
View File

@ -0,0 +1,15 @@
#include <memory.hpp>
namespace Memory
{
SmartHeap::SmartHeap(size_t Size)
{
this->Object = kmalloc(Size);
this->ObjectSize = Size;
}
SmartHeap::~SmartHeap()
{
kfree(this->Object);
}
}

View File

@ -42,10 +42,10 @@ namespace Power
warn("Executing the second attempt to reboot...");
// second attempt to reboot
// https://wiki.osdev.org/Reboot
uint8_t temp;
/* Second attempt to reboot */
asmv("cli");
uint8_t temp;
do
{
temp = inb(0x64);
@ -62,10 +62,14 @@ namespace Power
if (((ACPI::ACPI *)this->acpi)->FADT)
if (((ACPI::DSDT *)this->dsdt)->ACPIShutdownSupported)
((ACPI::DSDT *)this->dsdt)->Shutdown();
/* TODO: If no ACPI, display "It is now safe to turn off your computer" */
/* FIXME: Detect emulators and use their shutdown methods */
#ifdef DEBUG
outl(0xB004, 0x2000); // for qemu
outl(0x604, 0x2000); // if qemu not working, bochs and older versions of qemu
outl(0x4004, 0x3400); // virtual box
#endif
CPU::Stop();
}
@ -81,11 +85,6 @@ namespace Power
this->madt = new ACPI::MADT(((ACPI::ACPI *)acpi)->MADT);
trace("Power manager initialized");
}
Power::~Power()
{
debug("Destructor called");
}
}
#elif defined(a32)
@ -106,10 +105,6 @@ namespace Power
{
error("Power not implemented for i386");
}
Power::~Power()
{
}
}
#elif defined(aa64)
@ -130,10 +125,6 @@ namespace Power
{
error("Power not implemented for aarch64");
}
Power::~Power()
{
}
}
#endif

View File

@ -27,131 +27,134 @@ namespace SymbolResolver
{
const NIF char *Symbols::GetSymbolFromAddress(uintptr_t Address)
{
Symbols::SymbolTable Result{0, (char *)"<unknown>"};
for (int64_t i = 0; i < this->TotalEntries; i++)
if (this->SymTable[i].Address <= Address && this->SymTable[i].Address > Result.Address)
Result = this->SymTable[i];
SymbolTable Result{};
foreach (auto tbl in this->SymTable)
{
if (tbl.Address <= Address &&
tbl.Address > Result.Address)
Result = tbl;
}
// debug("Address: %#lx, Function: %s",
// Address, Result.FunctionName);
return Result.FunctionName;
}
void Symbols::AddSymbol(uintptr_t Address, const char *Name)
{
if (this->TotalEntries >= 0x10000)
{
error("Symbol table is full");
return;
SymbolTable tbl{};
tbl.Address = Address;
tbl.FunctionName = (char *)Name;
this->SymTable.push_back(tbl);
this->SymbolTableExists = true;
}
this->SymTable[this->TotalEntries].Address = Address;
strcpy(this->SymTable[this->TotalEntries].FunctionName, Name);
this->TotalEntries++;
}
__no_sanitize("alignment") void Symbols::AddBySymbolInfo(uint64_t Num, uint64_t EntSize, uint64_t Shndx, uintptr_t Sections)
__no_sanitize("alignment") void Symbols::AddSymbolInfoFromGRUB(uint64_t Num,
uint64_t EntSize,
__unused uint64_t Shndx,
uintptr_t Sections)
{
#ifdef a32
fixme("Function not working on 32-bit");
return;
#endif
if (this->TotalEntries >= 0x10000)
{
error("Symbol table is full");
return;
}
char *sections = reinterpret_cast<char *>(Sections);
Elf_Sym *Symbols = nullptr;
uint8_t *StringAddress = nullptr;
#if defined(a64) || defined(aa64)
Elf64_Shdr *ElfSections = (Elf64_Shdr *)(Sections);
Elf64_Sym *ElfSymbols = nullptr;
Elf64_Xword SymbolSize = 0;
// Elf64_Xword StringSize = 0;
#elif defined(a32)
Elf32_Shdr *ElfSections = (Elf32_Shdr *)(Sections);
Elf32_Sym *ElfSymbols = nullptr;
Elf32_Word SymbolSize = 0;
// Elf32_Word StringSize = 0;
#endif
char *strtab = nullptr;
int64_t TotalEntries = 0;
for (uint64_t i = 0; i < Num; i++)
switch (ElfSections[i].sh_type)
for (size_t i = 0; i < Num; ++i)
{
case SHT_SYMTAB:
#if defined(a64) || defined(aa64)
ElfSymbols = (Elf64_Sym *)(Sections + ElfSections[i].sh_offset);
this->TotalEntries = ElfSections[i].sh_size / sizeof(Elf64_Sym);
#elif defined(a32)
ElfSymbols = (Elf32_Sym *)(Sections + ElfSections[i].sh_offset);
this->TotalEntries = ElfSections[i].sh_size / sizeof(Elf32_Sym);
#endif
if (this->TotalEntries >= 0x10000)
this->TotalEntries = 0x10000 - 1;
Elf_Shdr *sym = (Elf_Shdr *)&sections[EntSize * i];
Elf_Shdr *str = (Elf_Shdr *)&sections[EntSize * sym->sh_link];
debug("Symbol table found, %d entries", this->TotalEntries);
break;
case SHT_STRTAB:
if (Shndx == i)
if (sym->sh_type == SHT_SYMTAB &&
str->sh_type == SHT_STRTAB)
{
debug("String table found, %d entries", ElfSections[i].sh_size);
}
else
{
strtab = (char *)(Sections + ElfSections[i].sh_offset);
debug("String table found, %d entries", ElfSections[i].sh_size);
}
break;
default:
Symbols = (Elf_Sym *)sym->sh_addr;
StringAddress = (uint8_t *)str->sh_addr;
SymbolSize = (int)sym->sh_size;
// StringSize = (int)str->sh_size;
// TotalEntries = Section.sh_size / sizeof(Elf64_Sym)
TotalEntries = sym->sh_size / sym->sh_entsize;
debug("Symbol table found, %d entries",
SymbolSize / sym->sh_entsize);
UNUSED(SymbolSize);
break;
}
}
if (ElfSymbols != nullptr && strtab != nullptr)
if (Symbols != nullptr && StringAddress != nullptr)
{
int64_t Index, MinimumIndex;
for (int64_t i = 0; i < this->TotalEntries - 1; i++)
for (int64_t i = 0; i < TotalEntries - 1; i++)
{
MinimumIndex = i;
for (Index = i + 1; Index < this->TotalEntries; Index++)
if (ElfSymbols[Index].st_value < ElfSymbols[MinimumIndex].st_value)
for (Index = i + 1; Index < TotalEntries; Index++)
if (Symbols[Index].st_value < Symbols[MinimumIndex].st_value)
MinimumIndex = Index;
#if defined(a64) || defined(aa64)
Elf64_Sym tmp = ElfSymbols[MinimumIndex];
#elif defined(a32)
Elf32_Sym tmp = ElfSymbols[MinimumIndex];
#endif
ElfSymbols[MinimumIndex] = ElfSymbols[i];
ElfSymbols[i] = tmp;
Elf_Sym tmp = Symbols[MinimumIndex];
Symbols[MinimumIndex] = Symbols[i];
Symbols[i] = tmp;
}
while (ElfSymbols[0].st_value == 0)
while (Symbols[0].st_value == 0)
{
if (this->TotalEntries <= 0)
if (TotalEntries <= 0)
break;
ElfSymbols++;
this->TotalEntries--;
Symbols++;
TotalEntries--;
}
if (this->TotalEntries <= 0)
if (TotalEntries <= 0)
{
error("Symbol table is empty");
return;
}
trace("Symbol table loaded, %d entries (%ldKB)", this->TotalEntries, TO_KB(this->TotalEntries * sizeof(SymbolTable)));
for (int64_t i = 0, g = this->TotalEntries; i < g; i++)
debug("Symbol table loaded, %d entries (%ld KiB)",
TotalEntries, TO_KiB(TotalEntries * sizeof(SymbolTable)));
Elf_Sym *sym = nullptr;
const char *name = nullptr;
for (int64_t i = 0, g = TotalEntries; i < g; i++)
{
this->SymTable[i].Address = ElfSymbols[i].st_value;
this->SymTable[i].FunctionName = &strtab[ElfSymbols[i].st_name];
sym = &Symbols[i];
name = (const char *)&StringAddress[Symbols[i].st_name];
if (strlen(name) == 0)
continue;
SymbolTable tbl{};
tbl.Address = sym->st_value;
tbl.FunctionName = (char *)name;
this->SymTable.push_back(tbl);
this->SymbolTableExists = true;
// debug("Symbol %d: %#llx %s", i, this->SymTable[i].Address, this->SymTable[i].FunctionName);
// debug("Symbol %d: %#lx %s(%#lx)",
// i, tbl.Address,
// tbl.FunctionName,
// name);
}
}
}
Symbols::Symbols(uintptr_t ImageAddress)
void Symbols::AppendSymbols(uintptr_t ImageAddress, uintptr_t BaseAddress)
{
/* FIXME: Get only the required headers instead of the whole file */
if (ImageAddress == 0 || Memory::Virtual().Check((void *)ImageAddress) == false)
{
error("Invalid image address %#lx", ImageAddress);
return;
}
this->Image = (void *)ImageAddress;
debug("Solving symbols for address: %#llx", ImageAddress);
#if defined(a64) || defined(aa64)
Elf64_Ehdr *Header = (Elf64_Ehdr *)ImageAddress;
#elif defined(a32)
@ -165,30 +168,20 @@ namespace SymbolResolver
error("Invalid ELF header");
return;
}
#if defined(a64) || defined(aa64)
Elf64_Shdr *ElfSections = (Elf64_Shdr *)(ImageAddress + Header->e_shoff);
Elf64_Sym *ElfSymbols = nullptr;
#elif defined(a32)
Elf32_Shdr *ElfSections = (Elf32_Shdr *)(ImageAddress + Header->e_shoff);
Elf32_Sym *ElfSymbols = nullptr;
#endif
Elf_Shdr *ElfSections = (Elf_Shdr *)(ImageAddress + Header->e_shoff);
Elf_Sym *ElfSymbols = nullptr;
char *strtab = nullptr;
int64_t TotalEntries = 0;
for (uint16_t i = 0; i < Header->e_shnum; i++)
{
switch (ElfSections[i].sh_type)
{
case SHT_SYMTAB:
#if defined(a64) || defined(aa64)
ElfSymbols = (Elf64_Sym *)(ImageAddress + ElfSections[i].sh_offset);
this->TotalEntries = ElfSections[i].sh_size / sizeof(Elf64_Sym);
#elif defined(a32)
ElfSymbols = (Elf32_Sym *)(ImageAddress + ElfSections[i].sh_offset);
this->TotalEntries = ElfSections[i].sh_size / sizeof(Elf32_Sym);
#endif
if (this->TotalEntries >= 0x10000)
this->TotalEntries = 0x10000 - 1;
debug("Symbol table found, %d entries", this->TotalEntries);
ElfSymbols = (Elf_Sym *)(ImageAddress + ElfSections[i].sh_offset);
TotalEntries = ElfSections[i].sh_size / sizeof(Elf_Sym);
debug("Symbol table found, %d entries", TotalEntries);
break;
case SHT_STRTAB:
if (Header->e_shstrndx == i)
@ -204,21 +197,18 @@ namespace SymbolResolver
default:
break;
}
}
if (ElfSymbols != nullptr && strtab != nullptr)
{
int64_t Index, MinimumIndex;
for (int64_t i = 0; i < this->TotalEntries - 1; i++)
for (int64_t i = 0; i < TotalEntries - 1; i++)
{
MinimumIndex = i;
for (Index = i + 1; Index < this->TotalEntries; Index++)
for (Index = i + 1; Index < TotalEntries; Index++)
if (ElfSymbols[Index].st_value < ElfSymbols[MinimumIndex].st_value)
MinimumIndex = Index;
#if defined(a64) || defined(aa64)
Elf64_Sym tmp = ElfSymbols[MinimumIndex];
#elif defined(a32)
Elf32_Sym tmp = ElfSymbols[MinimumIndex];
#endif
Elf_Sym tmp = ElfSymbols[MinimumIndex];
ElfSymbols[MinimumIndex] = ElfSymbols[i];
ElfSymbols[i] = tmp;
}
@ -226,19 +216,37 @@ namespace SymbolResolver
while (ElfSymbols[0].st_value == 0)
{
ElfSymbols++;
this->TotalEntries--;
TotalEntries--;
}
trace("Symbol table loaded, %d entries (%ldKB)", this->TotalEntries, TO_KB(this->TotalEntries * sizeof(SymbolTable)));
for (int64_t i = 0, g = this->TotalEntries; i < g; i++)
trace("Symbol table loaded, %d entries (%ld KiB)",
TotalEntries, TO_KiB(TotalEntries * sizeof(SymbolTable)));
/* TODO: maybe a checker for duplicated addresses? */
Elf_Sym *sym = nullptr;
const char *name = nullptr;
for (int64_t i = 0, g = TotalEntries; i < g; i++)
{
this->SymTable[i].Address = ElfSymbols[i].st_value;
this->SymTable[i].FunctionName = &strtab[ElfSymbols[i].st_name];
sym = &ElfSymbols[i];
name = &strtab[ElfSymbols[i].st_name];
SymbolTable tbl{};
tbl.Address = sym->st_value + BaseAddress;
tbl.FunctionName = (char *)name;
this->SymTable.push_back(tbl);
this->SymbolTableExists = true;
// debug("Symbol %d: %#llx %s", i, this->SymTable[i].Address, this->SymTable[i].FunctionName);
// debug("Symbol %d: %#llx %s", i,
// this->SymTable[i].Address,
// this->SymTable[i].FunctionName);
}
}
}
Symbols::Symbols(uintptr_t ImageAddress)
{
this->Image = (void *)ImageAddress;
this->AppendSymbols(ImageAddress);
}
Symbols::~Symbols() {}
}

View File

@ -35,12 +35,12 @@ namespace Time
bool HighPrecisionEventTimer::Sleep(size_t Duration, Units Unit)
{
#if defined(a64)
size_t Target = mminq(&((HPET *)hpet)->MainCounterValue) + (Duration * ConvertUnit(Unit)) / clk;
uint64_t Target = mminq(&((HPET *)hpet)->MainCounterValue) + (Duration * ConvertUnit(Unit)) / clk;
while (mminq(&((HPET *)hpet)->MainCounterValue) < Target)
CPU::Pause();
return true;
#elif defined(a32)
size_t Target = mminl(&((HPET *)hpet)->MainCounterValue) + (Duration * ConvertUnit(Unit)) / clk;
uint64_t Target = mminl(&((HPET *)hpet)->MainCounterValue) + (Duration * ConvertUnit(Unit)) / clk;
while (mminl(&((HPET *)hpet)->MainCounterValue) < Target)
CPU::Pause();
return true;
@ -48,7 +48,7 @@ namespace Time
return false;
}
size_t HighPrecisionEventTimer::GetCounter()
uint64_t HighPrecisionEventTimer::GetCounter()
{
#if defined(a64)
return mminq(&((HPET *)hpet)->MainCounterValue);
@ -57,7 +57,7 @@ return false;
#endif
}
size_t HighPrecisionEventTimer::CalculateTarget(size_t Target, Units Unit)
uint64_t HighPrecisionEventTimer::CalculateTarget(uint64_t Target, Units Unit)
{
#if defined(a64)
return mminq(&((HPET *)hpet)->MainCounterValue) + (Target * ConvertUnit(Unit)) / clk;
@ -66,13 +66,13 @@ return false;
#endif
}
size_t HighPrecisionEventTimer::GetNanosecondsSinceClassCreation()
uint64_t HighPrecisionEventTimer::GetNanosecondsSinceClassCreation()
{
#if defined(a86)
size_t Subtraction = this->GetCounter() - this->ClassCreationTime;
uint64_t Subtraction = this->GetCounter() - this->ClassCreationTime;
if (Subtraction <= 0 || this->clk <= 0)
return 0;
return Subtraction / (this->clk / ConvertUnit(Units::Nanoseconds));
return uint64_t(Subtraction / (this->clk / ConvertUnit(Units::Nanoseconds)));
#endif
}
@ -86,6 +86,7 @@ return false;
this->hpet = (HPET *)HPET_HDR->Address.Address;
trace("%s timer is at address %016p", HPET_HDR->Header.OEMID, (void *)HPET_HDR->Address.Address);
clk = s_cst(uint32_t, (uint64_t)this->hpet->GeneralCapabilities >> 32);
debug("HPET clock is %u Hz", clk);
#ifdef a64
mmoutq(&this->hpet->GeneralConfiguration, 0);
mmoutq(&this->hpet->MainCounterValue, 0);

View File

@ -34,31 +34,31 @@ namespace Time
bool TimeStampCounter::Sleep(size_t Duration, Units Unit)
{
#if defined(a86)
size_t Target = this->GetCounter() + (Duration * ConvertUnit(Unit)) / this->clk;
uint64_t Target = this->GetCounter() + (Duration * ConvertUnit(Unit)) / this->clk;
while (this->GetCounter() < Target)
CPU::Pause();
return true;
#endif
}
size_t TimeStampCounter::GetCounter()
uint64_t TimeStampCounter::GetCounter()
{
#if defined(a86)
return CPU::Counter();
#endif
}
size_t TimeStampCounter::CalculateTarget(size_t Target, Units Unit)
uint64_t TimeStampCounter::CalculateTarget(uint64_t Target, Units Unit)
{
#if defined(a86)
return this->GetCounter() + (Target * ConvertUnit(Unit)) / this->clk;
return uint64_t((this->GetCounter() + (Target * ConvertUnit(Unit))) / this->clk);
#endif
}
size_t TimeStampCounter::GetNanosecondsSinceClassCreation()
uint64_t TimeStampCounter::GetNanosecondsSinceClassCreation()
{
#if defined(a86)
return (this->GetCounter() - this->ClassCreationTime) / this->clk;
return uint64_t((this->GetCounter() - this->ClassCreationTime) / this->clk);
#endif
}

View File

@ -61,90 +61,90 @@ namespace Time
}
}
size_t time::GetCounter()
uint64_t time::GetCounter()
{
switch (ActiveTimer)
{
case NONE:
error("No timer is active");
return false;
return 0;
case RTC:
fixme("RTC sleep not implemented");
return false;
return 0;
case PIT:
fixme("PIT sleep not implemented");
return false;
return 0;
case HPET:
return this->hpet->GetCounter();
case ACPI:
fixme("ACPI sleep not implemented");
return false;
return 0;
case APIC:
fixme("APIC sleep not implemented");
return false;
return 0;
case TSC:
return this->tsc->GetCounter();
default:
error("Unknown timer");
return false;
return 0;
}
}
size_t time::CalculateTarget(size_t Target, Units Unit)
uint64_t time::CalculateTarget(uint64_t Target, Units Unit)
{
switch (ActiveTimer)
{
case NONE:
error("No timer is active");
return false;
return 0;
case RTC:
fixme("RTC sleep not implemented");
return false;
return 0;
case PIT:
fixme("PIT sleep not implemented");
return false;
return 0;
case HPET:
return this->hpet->CalculateTarget(Target, Unit);
case ACPI:
fixme("ACPI sleep not implemented");
return false;
return 0;
case APIC:
fixme("APIC sleep not implemented");
return false;
return 0;
case TSC:
return this->tsc->CalculateTarget(Target, Unit);
default:
error("Unknown timer");
return false;
return 0;
}
}
size_t time::GetNanosecondsSinceClassCreation()
uint64_t time::GetNanosecondsSinceClassCreation()
{
switch (ActiveTimer)
{
case NONE:
error("No timer is active");
return false;
return 0;
case RTC:
fixme("RTC sleep not implemented");
return false;
return 0;
case PIT:
fixme("PIT sleep not implemented");
return false;
return 0;
case HPET:
return this->hpet->GetNanosecondsSinceClassCreation();
case ACPI:
fixme("ACPI sleep not implemented");
return false;
return 0;
case APIC:
fixme("APIC sleep not implemented");
return false;
return 0;
case TSC:
return this->tsc->GetNanosecondsSinceClassCreation();
default:
error("Unknown timer");
return false;
return 0;
}
}

View File

@ -20,6 +20,8 @@
#include <convert.h>
#include <debug.h>
#ifdef DEBUG
// TODO: implement:
/*
__ubsan_handle_type_mismatch_v1_abort
@ -47,320 +49,320 @@ __ubsan_handle_pointer_overflow_abort
__ubsan_handle_cfi_check_fail
*/
extern void __asan_report_load1(void *unknown)
void __asan_report_load1(void *unknown)
{
ubsan("load1");
UNUSED(unknown);
}
extern void __asan_report_load2(void *unknown)
void __asan_report_load2(void *unknown)
{
ubsan("load2");
UNUSED(unknown);
}
extern void __asan_report_load4(void *unknown)
void __asan_report_load4(void *unknown)
{
ubsan("load4");
UNUSED(unknown);
}
extern void __asan_report_load8(void *unknown)
void __asan_report_load8(void *unknown)
{
ubsan("load8");
UNUSED(unknown);
}
extern void __asan_report_load16(void *unknown)
void __asan_report_load16(void *unknown)
{
ubsan("load16");
UNUSED(unknown);
}
extern void __asan_report_load_n(void *unknown, uintptr_t size)
void __asan_report_load_n(void *unknown, uintptr_t size)
{
ubsan("loadn");
UNUSED(unknown);
UNUSED(size);
}
extern void __asan_report_store1(void *unknown)
void __asan_report_store1(void *unknown)
{
ubsan("store1");
UNUSED(unknown);
}
extern void __asan_report_store2(void *unknown)
void __asan_report_store2(void *unknown)
{
ubsan("store2");
UNUSED(unknown);
}
extern void __asan_report_store4(void *unknown)
void __asan_report_store4(void *unknown)
{
ubsan("store4");
UNUSED(unknown);
}
extern void __asan_report_store8(void *unknown)
void __asan_report_store8(void *unknown)
{
ubsan("store8");
UNUSED(unknown);
}
extern void __asan_report_store16(void *unknown)
void __asan_report_store16(void *unknown)
{
ubsan("store16");
UNUSED(unknown);
}
extern void __asan_report_store_n(void *unknown, uintptr_t size)
void __asan_report_store_n(void *unknown, uintptr_t size)
{
ubsan("storen");
UNUSED(unknown);
UNUSED(size);
}
extern void __asan_report_load1_noabort(void *unknown)
void __asan_report_load1_noabort(void *unknown)
{
ubsan("load1");
UNUSED(unknown);
}
extern void __asan_report_load2_noabort(void *unknown)
void __asan_report_load2_noabort(void *unknown)
{
ubsan("load2");
UNUSED(unknown);
}
extern void __asan_report_load4_noabort(void *unknown)
void __asan_report_load4_noabort(void *unknown)
{
ubsan("load4");
UNUSED(unknown);
}
extern void __asan_report_load8_noabort(void *unknown)
void __asan_report_load8_noabort(void *unknown)
{
ubsan("load8");
UNUSED(unknown);
}
extern void __asan_report_load16_noabort(void *unknown)
void __asan_report_load16_noabort(void *unknown)
{
ubsan("load16");
UNUSED(unknown);
}
extern void __asan_report_load_n_noabort(void *unknown, uintptr_t size)
void __asan_report_load_n_noabort(void *unknown, uintptr_t size)
{
ubsan("loadn");
UNUSED(unknown);
UNUSED(size);
}
extern void __asan_report_store1_noabort(void *unknown)
void __asan_report_store1_noabort(void *unknown)
{
ubsan("store1");
UNUSED(unknown);
}
extern void __asan_report_store2_noabort(void *unknown)
void __asan_report_store2_noabort(void *unknown)
{
ubsan("store2");
UNUSED(unknown);
}
extern void __asan_report_store4_noabort(void *unknown)
void __asan_report_store4_noabort(void *unknown)
{
ubsan("store4");
UNUSED(unknown);
}
extern void __asan_report_store8_noabort(void *unknown)
void __asan_report_store8_noabort(void *unknown)
{
ubsan("store8");
UNUSED(unknown);
}
extern void __asan_report_store16_noabort(void *unknown)
void __asan_report_store16_noabort(void *unknown)
{
ubsan("store16");
UNUSED(unknown);
}
extern void __asan_report_store_n_noabort(void *unknown, uintptr_t size)
void __asan_report_store_n_noabort(void *unknown, uintptr_t size)
{
ubsan("storen");
UNUSED(unknown);
UNUSED(size);
}
extern void __asan_stack_malloc_0(uintptr_t size)
void __asan_stack_malloc_0(uintptr_t size)
{
ubsan("stack malloc 0");
UNUSED(size);
}
extern void __asan_stack_malloc_1(uintptr_t size)
void __asan_stack_malloc_1(uintptr_t size)
{
ubsan("stack malloc 1");
UNUSED(size);
}
extern void __asan_stack_malloc_2(uintptr_t size)
void __asan_stack_malloc_2(uintptr_t size)
{
ubsan("stack malloc 2");
UNUSED(size);
}
extern void __asan_stack_malloc_3(uintptr_t size)
void __asan_stack_malloc_3(uintptr_t size)
{
ubsan("stack malloc 3");
UNUSED(size);
}
extern void __asan_stack_malloc_4(uintptr_t size)
void __asan_stack_malloc_4(uintptr_t size)
{
ubsan("stack malloc 4");
UNUSED(size);
}
extern void __asan_stack_malloc_5(uintptr_t size)
void __asan_stack_malloc_5(uintptr_t size)
{
ubsan("stack malloc 5");
UNUSED(size);
}
extern void __asan_stack_malloc_6(uintptr_t size)
void __asan_stack_malloc_6(uintptr_t size)
{
ubsan("stack malloc 6");
UNUSED(size);
}
extern void __asan_stack_malloc_7(uintptr_t size)
void __asan_stack_malloc_7(uintptr_t size)
{
ubsan("stack malloc 7");
UNUSED(size);
}
extern void __asan_stack_malloc_8(uintptr_t size)
void __asan_stack_malloc_8(uintptr_t size)
{
ubsan("stack malloc 8");
UNUSED(size);
}
extern void __asan_stack_malloc_9(uintptr_t size)
void __asan_stack_malloc_9(uintptr_t size)
{
ubsan("stack malloc 9");
UNUSED(size);
}
extern void __asan_stack_free_0(void *ptr, uintptr_t size)
void __asan_stack_free_0(void *ptr, uintptr_t size)
{
ubsan("stack free 0");
UNUSED(ptr);
UNUSED(size);
}
extern void __asan_stack_free_1(void *ptr, uintptr_t size)
void __asan_stack_free_1(void *ptr, uintptr_t size)
{
ubsan("stack free 1");
UNUSED(ptr);
UNUSED(size);
}
extern void __asan_stack_free_2(void *ptr, uintptr_t size)
void __asan_stack_free_2(void *ptr, uintptr_t size)
{
ubsan("stack free 2");
UNUSED(ptr);
UNUSED(size);
}
extern void __asan_stack_free_3(void *ptr, uintptr_t size)
void __asan_stack_free_3(void *ptr, uintptr_t size)
{
ubsan("stack free 3");
UNUSED(ptr);
UNUSED(size);
}
extern void __asan_stack_free_4(void *ptr, uintptr_t size)
void __asan_stack_free_4(void *ptr, uintptr_t size)
{
ubsan("stack free 4");
UNUSED(ptr);
UNUSED(size);
}
extern void __asan_stack_free_5(void *ptr, uintptr_t size)
void __asan_stack_free_5(void *ptr, uintptr_t size)
{
ubsan("stack free 5");
UNUSED(ptr);
UNUSED(size);
}
extern void __asan_stack_free_6(void *ptr, uintptr_t size)
void __asan_stack_free_6(void *ptr, uintptr_t size)
{
ubsan("stack free 6");
UNUSED(ptr);
UNUSED(size);
}
extern void __asan_stack_free_7(void *ptr, uintptr_t size)
void __asan_stack_free_7(void *ptr, uintptr_t size)
{
ubsan("stack free 7");
UNUSED(ptr);
UNUSED(size);
}
extern void __asan_stack_free_8(void *ptr, uintptr_t size)
void __asan_stack_free_8(void *ptr, uintptr_t size)
{
ubsan("stack free 8");
UNUSED(ptr);
UNUSED(size);
}
extern void __asan_stack_free_9(void *ptr, uintptr_t size)
void __asan_stack_free_9(void *ptr, uintptr_t size)
{
ubsan("stack free 9");
UNUSED(ptr);
UNUSED(size);
}
extern void __asan_poison_stack_memory(void *addr, uintptr_t size)
void __asan_poison_stack_memory(void *addr, uintptr_t size)
{
ubsan("poison stack memory");
UNUSED(addr);
UNUSED(size);
}
extern void __asan_unpoison_stack_memory(void *addr, uintptr_t size)
void __asan_unpoison_stack_memory(void *addr, uintptr_t size)
{
ubsan("unpoison stack memory");
UNUSED(addr);
UNUSED(size);
}
extern void __asan_before_dynamic_init(const char *module_name)
void __asan_before_dynamic_init(const char *module_name)
{
ubsan("before dynamic init");
UNUSED(module_name);
}
extern void __asan_after_dynamic_init(void) { ubsan("after dynamic init"); }
void __asan_after_dynamic_init(void) { ubsan("after dynamic init"); }
extern void __asan_register_globals(void *unknown, size_t size)
void __asan_register_globals(void *unknown, size_t size)
{
ubsan("register_globals");
UNUSED(unknown);
UNUSED(size);
}
extern void __asan_unregister_globals(void) { ubsan("unregister_globals"); }
void __asan_unregister_globals(void) { ubsan("unregister_globals"); }
extern void __asan_init(void) { ubsan("init"); }
extern void __asan_version_mismatch_check_v8(void) { ubsan("version_mismatch_check_v8"); }
extern void __asan_option_detect_stack_use_after_return(void) { ubsan("stack use after return"); }
void __asan_init(void) { ubsan("init"); }
void __asan_version_mismatch_check_v8(void) { ubsan("version_mismatch_check_v8"); }
void __asan_option_detect_stack_use_after_return(void) { ubsan("stack use after return"); }
extern __noreturn void __asan_handle_no_return(void)
__noreturn void __asan_handle_no_return(void)
{
ubsan("no_return");
while (1)
@ -511,3 +513,5 @@ void __ubsan_handle_dynamic_type_cache_miss(struct dynamic_type_cache_miss_data
ubsan("Dynamic type cache miss.");
UNUSED(ptr);
}
#endif

View File

@ -164,11 +164,13 @@ namespace UniversalAsynchronousReceiverTransmitter
SafeFunction NIF Events::~Events()
{
for (size_t i = 0; i < RegisteredEvents.size(); i++)
if (RegisteredEvents[i] == this)
forItr(itr, RegisteredEvents)
{
RegisteredEvents.remove(i);
if (*itr == this)
{
RegisteredEvents.erase(itr);
return;
}
}
}
}

View File

@ -424,7 +424,8 @@ namespace Video
#ifdef DEBUG
FontInfo Info = this->CurrentFont->GetInfo();
debug("Font loaded: %dx%d %s",
Info.Width, Info.Height, Info.Type == FontType::PCScreenFont1 ? "PSF1" : "PSF2");
Info.Width, Info.Height,
Info.Type == FontType::PCScreenFont1 ? "PSF1" : "PSF2");
#endif
}
this->CreateBuffer(Info.Width, Info.Height, 0);

View File

@ -36,9 +36,11 @@ namespace Video
PSF2_HEADER *font2 = (PSF2_HEADER *)KernelAllocator.RequestPages(TO_PAGES(FontDataLength + 1));
memcpy((void *)font2, Start, FontDataLength);
Memory::Virtual().Map((void *)font2, (void *)font2, FontDataLength, Memory::PTFlag::RW);
Memory::Virtual().Map((void *)font2, (void *)font2,
FontDataLength, Memory::PTFlag::RW);
if (font2->magic[0] != PSF2_MAGIC0 || font2->magic[1] != PSF2_MAGIC1 || font2->magic[2] != PSF2_MAGIC2 || font2->magic[3] != PSF2_MAGIC3)
if (font2->magic[0] != PSF2_MAGIC0 || font2->magic[1] != PSF2_MAGIC1 ||
font2->magic[2] != PSF2_MAGIC2 || font2->magic[3] != PSF2_MAGIC3)
{
error("Font2 magic mismatch.");
KernelAllocator.FreePages((void *)font2, TO_PAGES(FontDataLength + 1));
@ -46,7 +48,8 @@ namespace Video
}
this->Info.PSF2Font->Header = font2;
this->Info.PSF2Font->GlyphBuffer = reinterpret_cast<void *>(reinterpret_cast<uintptr_t>(Start) + sizeof(PSF2_HEADER));
this->Info.PSF2Font->GlyphBuffer =
r_cst(void *, r_cst(uintptr_t, Start) + sizeof(PSF2_HEADER));
this->Info.Width = font2->width;
this->Info.Height = font2->height;
}
@ -59,7 +62,8 @@ namespace Video
uint32_t glyphBufferSize = font1->charsize * 256;
if (font1->mode == 1) // 512 glyph mode
glyphBufferSize = font1->charsize * 512;
void *glyphBuffer = reinterpret_cast<void *>(reinterpret_cast<uintptr_t>(Start) + sizeof(PSF1_HEADER));
void *glyphBuffer =
r_cst(void *, r_cst(uintptr_t, Start) + sizeof(PSF1_HEADER));
this->Info.PSF1Font->Header = font1;
this->Info.PSF1Font->GlyphBuffer = glyphBuffer;
UNUSED(glyphBufferSize); // TODO: Use this in the future?

View File

@ -34,7 +34,7 @@
#define __FENNIX_DRIVER_API_H__
/**
* @brief The driver API is a set of functions that the kernel provides to the drivers.
* The driver API is a set of functions that the kernel provides to the drivers.
*
* - The driver is responsible for the memory management.
* - The kernel will NOT free any memory allocated by the driver. On @see StopReason the driver must free all the memory it allocated and disable the hardware it uses.
@ -115,14 +115,14 @@ struct KernelAPI
struct KAPIDriverTalk
{
/** @brief Connects to the network manager */
/** Connects to the network manager */
struct
{
void (*SendPacket)(unsigned int DriverID, unsigned char *Data, unsigned short Size);
void (*ReceivePacket)(unsigned int DriverID, unsigned char *Data, unsigned short Size);
} Network;
/** @brief Connects to the disk manager */
/** Connects to the disk manager */
struct
{
struct
@ -144,24 +144,24 @@ struct KernelAPI
enum CallbackReason
{
/**
* @brief This is used to detect memory corruption, not used.
* This is used to detect memory corruption, not used.
*/
UnknownReason,
/**
* @brief This is called once the kernel is ready to use the driver and call @see ConfigurationReason .
* This is called once the kernel is ready to use the driver and call @see ConfigurationReason .
*/
AcknowledgeReason,
/**
* @brief This is used after the driver is loaded and the kernel is ready to use the driver.
* This is used after the driver is loaded and the kernel is ready to use the driver.
*
* For PCI drivers, @see RawPtr will be the PCI device address.
*/
ConfigurationReason,
/**
* @brief This is used when the kernel wants to stop the driver.
* This is used when the kernel wants to stop the driver.
*
* The memory allocated by the driver will be freed automatically.
*/
@ -175,7 +175,7 @@ enum CallbackReason
/* Driver callbacks for basic usage. */
/**
* @brief This is used when the kernel sends data.
* This is used when the kernel sends data.
*
* - Network
* - Packet
@ -185,13 +185,13 @@ enum CallbackReason
SendReason,
/**
* @brief This is used when the kernel wants to receive data.
* This is used when the kernel wants to receive data.
* Currently not used.
*/
ReceiveReason,
/**
* @brief This is used to adjust driver settings.
* This is used to adjust driver settings.
*
* - Audio
* - Volume
@ -200,7 +200,7 @@ enum CallbackReason
AdjustReason,
/**
* @brief This is used when the kernel wants to fetch information about the driver.
* This is used when the kernel wants to query information about the driver.
*
* - Input
* - Mouse
@ -209,7 +209,19 @@ enum CallbackReason
* - Keyboard
* - Key
*/
FetchReason,
QueryReason,
/**
* This is used when the kernel wants to wait for an event.
*
* - Input
* - Mouse
* - Position
* - Buttons
* - Keyboard
* - Key
*/
PollWaitReason,
};
union KernelCallback
@ -220,7 +232,7 @@ union KernelCallback
void *RawPtr;
unsigned long RawData;
/** @brief When the kernel wants to send a packet. */
/** When the kernel wants to send a packet. */
struct
{
struct
@ -236,7 +248,7 @@ union KernelCallback
} Fetch;
} NetworkCallback;
/** @brief When the kernel wants to write to disk. */
/** When the kernel wants to write to disk. */
struct
{
struct
@ -255,7 +267,7 @@ union KernelCallback
} Fetch;
} DiskCallback;
/** @brief When the kernel wants to get mouse position / keyboard key */
/** When the kernel wants to get mouse position / keyboard key */
struct
{
struct
@ -270,6 +282,16 @@ union KernelCallback
bool Middle;
} Buttons;
} Mouse;
struct
{
/**
* The key.
*
* @note This is a scancode, not a character.
*/
unsigned char Key;
} Keyboard;
} InputCallback;
struct
@ -282,14 +304,14 @@ union KernelCallback
bool _Channels;
/**
* @brief Adjust the volume.
* Adjust the volume.
*
* 0 - 100
*/
unsigned char Volume;
/**
* @brief Adjust the encoding.
* Adjust the encoding.
*
* 0 - None, use default
*
@ -330,7 +352,7 @@ union KernelCallback
unsigned short Encoding;
/**
* @brief Adjust the sample rate.
* Adjust the sample rate.
*
* 0 - 8000 Hz
* 1 - 11025 Hz
@ -345,7 +367,7 @@ union KernelCallback
unsigned char SampleRate;
/**
* @brief Adjust the channels.
* Adjust the channels.
*
* 0 - Mono
* 1 - Stereo

View File

@ -1,171 +0,0 @@
/*
This file is part of Fennix Kernel.
Fennix Kernel is free software: you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation, either version 3 of
the License, or (at your option) any later version.
Fennix Kernel is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
*/
#include <exec.hpp>
#include <msexec.h>
#include "../kernel.h"
#include "../Fex.hpp"
namespace Execute
{
BinaryType GetBinaryType(void *Image)
{
Fex *FexHdr = (Fex *)Image;
Elf32_Ehdr *ELFHeader = (Elf32_Ehdr *)Image;
IMAGE_DOS_HEADER *MZHeader = (IMAGE_DOS_HEADER *)Image;
/* Check Fex magic */
if (FexHdr->Magic[0] == 'F' &&
FexHdr->Magic[1] == 'E' &&
FexHdr->Magic[2] == 'X' &&
FexHdr->Magic[3] == '\0')
{
/* If the fex type is driver, we shouldn't return as Fex. */
if (FexHdr->Type == FexFormatType::FexFormatType_Executable)
{
debug("Image - Fex");
return BinaryType::BinTypeFex;
}
else if (FexHdr->Type == FexFormatType::FexFormatType_Driver)
{
debug("Fex Driver is not supposed to be executed.");
}
}
/* Check ELF magic. */
else if (ELFHeader->e_ident[EI_MAG0] == ELFMAG0 &&
ELFHeader->e_ident[EI_MAG1] == ELFMAG1 &&
ELFHeader->e_ident[EI_MAG2] == ELFMAG2 &&
ELFHeader->e_ident[EI_MAG3] == ELFMAG3)
{
debug("Image - ELF");
return BinaryType::BinTypeELF;
}
/* Every Windows executable starts with MZ header. */
else if (MZHeader->e_magic == IMAGE_DOS_SIGNATURE)
{
IMAGE_NT_HEADERS *PEHeader = (IMAGE_NT_HEADERS *)(((char *)Image) + MZHeader->e_lfanew);
IMAGE_OS2_HEADER *NEHeader = (IMAGE_OS2_HEADER *)(((char *)Image) + MZHeader->e_lfanew);
/* TODO: LE, EDOS */
if (PEHeader->Signature == IMAGE_NT_SIGNATURE)
{
debug("Image - PE");
return BinaryType::BinTypePE;
}
else if (NEHeader->ne_magic == IMAGE_OS2_SIGNATURE)
{
debug("Image - NE");
return BinaryType::BinTypeNE;
}
else
{
debug("Image - MZ");
return BinaryType::BinTypeMZ;
}
}
/* ... */
return BinaryType::BinTypeUnknown;
}
BinaryType GetBinaryType(char *Path)
{
BinaryType Type = BinaryType::BinTypeInvalid;
VirtualFileSystem::File ExFile = vfs->Open(Path);
if (!ExFile.IsOK())
{
vfs->Close(ExFile);
return Type;
}
debug("File opened: %s", Path);
uint8_t *Buffer = new uint8_t[1024];
vfs->Read(ExFile, Buffer, 128);
Fex *FexHdr = (Fex *)Buffer;
Elf32_Ehdr *ELFHeader = (Elf32_Ehdr *)Buffer;
IMAGE_DOS_HEADER *MZHeader = (IMAGE_DOS_HEADER *)Buffer;
/* Check Fex header. */
if (FexHdr->Magic[0] == 'F' &&
FexHdr->Magic[1] == 'E' &&
FexHdr->Magic[2] == 'X' &&
FexHdr->Magic[3] == '\0')
{
/* If the fex type is driver, we shouldn't return as Fex. */
if (FexHdr->Type == FexFormatType::FexFormatType_Executable)
{
debug("Image - Fex");
Type = BinaryType::BinTypeFex;
goto Success;
}
else if (FexHdr->Type == FexFormatType::FexFormatType_Driver)
{
fixme("Fex Driver is not supposed to be executed.");
/* TODO: Driver installation pop-up. */
}
}
/* Check ELF header. */
else if (ELFHeader->e_ident[EI_MAG0] == ELFMAG0 &&
ELFHeader->e_ident[EI_MAG1] == ELFMAG1 &&
ELFHeader->e_ident[EI_MAG2] == ELFMAG2 &&
ELFHeader->e_ident[EI_MAG3] == ELFMAG3)
{
debug("Image - ELF");
Type = BinaryType::BinTypeELF;
goto Success;
}
/* Check MZ header. */
else if (MZHeader->e_magic == IMAGE_DOS_SIGNATURE)
{
vfs->Seek(ExFile, MZHeader->e_lfanew, SEEK_SET);
vfs->Read(ExFile, Buffer, 512);
IMAGE_NT_HEADERS *PEHeader = (IMAGE_NT_HEADERS *)(((char *)Buffer) + MZHeader->e_lfanew);
IMAGE_OS2_HEADER *NEHeader = (IMAGE_OS2_HEADER *)(((char *)Buffer) + MZHeader->e_lfanew);
/* TODO: LE, EDOS */
if (PEHeader->Signature == IMAGE_NT_SIGNATURE)
{
debug("Image - PE");
Type = BinaryType::BinTypePE;
goto Success;
}
else if (NEHeader->ne_magic == IMAGE_OS2_SIGNATURE)
{
debug("Image - NE");
Type = BinaryType::BinTypeNE;
goto Success;
}
else
{
debug("Image - MZ");
Type = BinaryType::BinTypeMZ;
goto Success;
}
}
/* ... */
Type = BinaryType::BinTypeUnknown;
Success:
delete[] Buffer;
vfs->Close(ExFile);
return Type;
}
}

View File

@ -1,187 +0,0 @@
/*
This file is part of Fennix Kernel.
Fennix Kernel is free software: you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation, either version 3 of
the License, or (at your option) any later version.
Fennix Kernel is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
*/
#include <exec.hpp>
#include <memory.hpp>
#include <lock.hpp>
#include <msexec.h>
#include <cwalk.h>
#include <elf.h>
#include <abi.h>
#include "../../kernel.h"
#include "../../Fex.hpp"
using namespace Tasking;
using VirtualFileSystem::File;
using VirtualFileSystem::FileStatus;
using VirtualFileSystem::NodeFlags;
namespace Execute
{
ELFBaseLoad ELFLoad(char *Path,
const char **argv, const char **envp,
TaskCompatibility Compatibility)
{
const char *BaseName;
cwk_path_get_basename(Path, &BaseName, nullptr);
TaskArchitecture Arch = TaskArchitecture::UnknownArchitecture;
File ExFile = vfs->Open(Path);
if (ExFile.Status != FileStatus::OK)
{
vfs->Close(ExFile);
error("Failed to open file: %s", Path);
return {};
}
else if (ExFile.GetFlags() != NodeFlags::FILE)
{
vfs->Close(ExFile);
error("Invalid file path: %s", Path);
return {};
}
else if (GetBinaryType(Path) != BinaryType::BinTypeELF)
{
vfs->Close(ExFile);
error("Invalid file type: %s", Path);
return {};
}
size_t ExFileSize = ExFile.GetLength();
void *ElfFile = KernelAllocator.RequestPages(TO_PAGES(ExFileSize + 1));
vfs->Read(ExFile, (uint8_t *)ElfFile, ExFileSize);
debug("Loaded elf %s at %#lx with the length of %ld",
Path, ElfFile, ExFileSize);
Elf32_Ehdr *ELFHeader = (Elf32_Ehdr *)ElfFile;
switch (ELFHeader->e_machine)
{
case EM_386:
Arch = TaskArchitecture::x32;
break;
case EM_X86_64:
Arch = TaskArchitecture::x64;
break;
case EM_ARM:
Arch = TaskArchitecture::ARM32;
break;
case EM_AARCH64:
Arch = TaskArchitecture::ARM64;
break;
default:
break;
}
// TODO: This shouldn't be ignored
if (ELFHeader->e_ident[EI_CLASS] == ELFCLASS32)
fixme("32-bit ELF");
else if (ELFHeader->e_ident[EI_CLASS] == ELFCLASS64)
fixme("64-bit ELF");
else
fixme("Unknown class %d", ELFHeader->e_ident[EI_CLASS]);
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
if (ELFHeader->e_ident[EI_DATA] != ELFDATA2LSB)
{
fixme("ELF32 LSB expected, got %d", ELFHeader->e_ident[EI_DATA]);
}
#else
if (ELFHeader->e_ident[EI_DATA] != ELFDATA2MSB)
{
fixme("ELF32 MSB expected, got %d", ELFHeader->e_ident[EI_DATA]);
}
#endif
/* ------------------------------------------------------------------------------------------------------------------------------ */
PCB *Process = TaskManager->CreateProcess(TaskManager->GetCurrentProcess(),
BaseName, TaskTrustLevel::User, ElfFile);
Process->SetWorkingDirectory(vfs->GetNodeFromPath(Path)->Parent);
Process->Info.Compatibility = TaskCompatibility::Native;
Process->Info.Architecture = TaskArchitecture::x64;
ELFBaseLoad bl;
ELFObject *obj = new ELFObject(Path, Process);
if (!obj->IsValid())
{
error("Failed to load ELF object");
vfs->Close(ExFile);
TaskManager->RevertProcessCreation(Process);
return {};
}
bl = obj->GetBaseLoadInfo();
/* TODO: Keep only the necessary headers */
Memory::Virtual vmm = Memory::Virtual(Process->PageTable);
for (size_t i = 0; i < TO_PAGES(ExFileSize); i++)
{
void *AddressToMap = (void *)((uintptr_t)ElfFile + (i * PAGE_SIZE));
vmm.Remap(AddressToMap, AddressToMap, Memory::RW | Memory::US);
}
if (bl.Interpreter)
{
debug("Keeping ElfFile at %p", ElfFile);
TCB *InterIPCThread = TaskManager->CreateThread(TaskManager->GetCurrentProcess(),
(IP)ELFInterpreterIPCThread,
nullptr,
nullptr,
std::vector<AuxiliaryVector>(),
TaskArchitecture::x64,
TaskCompatibility::Native,
true);
std::vector<const char *> *tmp_needed_libs =
new std::vector<const char *>(bl.NeededLibraries);
InterIPCThread->SYSV_ABI_Call((uintptr_t)Process,
(uintptr_t) new std::string(Path),
(uintptr_t)bl.VirtualMemoryImage,
(uintptr_t)tmp_needed_libs);
InterIPCThread->Rename("ELF Interpreter IPC Thread");
InterIPCThread->SetPriority(TaskPriority::Low);
InterIPCThread->Status = TaskStatus::Ready;
}
TCB *Thread = TaskManager->CreateThread(Process,
bl.InstructionPointer,
argv, envp, bl.auxv,
Arch,
Compatibility);
foreach (Memory::MemMgr::AllocatedPages p in bl.TmpMem->GetAllocatedPagesList())
{
Thread->Memory->Add(p.Address, p.PageCount);
bl.TmpMem->DetachAddress(p.Address);
}
delete bl.TmpMem, bl.TmpMem = nullptr;
bl.sd.Process = Process;
bl.sd.Thread = Thread;
bl.sd.Status = ExStatus::OK;
vfs->Close(ExFile);
return bl;
}
}

View File

@ -1,155 +0,0 @@
/*
This file is part of Fennix Kernel.
Fennix Kernel is free software: you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation, either version 3 of
the License, or (at your option) any later version.
Fennix Kernel is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
*/
#include <exec.hpp>
#include <debug.h>
#include "../../kernel.h"
using namespace Tasking;
namespace Execute
{
struct InterpreterIPCDataLibrary
{
char Name[64];
};
typedef struct
{
char Path[256];
void *MemoryImage;
struct InterpreterIPCDataLibrary Libraries[64];
} InterpreterIPCData;
void ELFInterpreterIPCThread(PCB *TargetProcess,
std::string *TargetPath,
void *MemoryImage,
std::vector<const char *> *_NeededLibraries)
{
std::vector<const char *> NeededLibraries = *_NeededLibraries;
delete _NeededLibraries;
debug("Interpreter thread started for %s", TargetPath->c_str());
// Interpreter will create an IPC with token "LOAD".
char UniqueToken[16] = {'L', 'O', 'A', 'D', '\0'};
InterProcessCommunication::IPCHandle *Handle = nullptr;
while (Handle == nullptr)
{
debug("Searching for IPC with token %s", UniqueToken);
Handle = TargetProcess->IPC->SearchByToken(UniqueToken);
if (Handle == nullptr)
debug("Failed");
TaskManager->Sleep(200);
if (Handle == nullptr)
debug("Retrying...");
}
debug("IPC found, sending data...");
InterpreterIPCData *TmpBuffer = new InterpreterIPCData;
strncpy(TmpBuffer->Path, TargetPath->c_str(), sizeof(TmpBuffer->Path) - 1);
TmpBuffer->MemoryImage = MemoryImage;
size_t NeededLibsSize = NeededLibraries.size();
for (size_t i = 0; i < NeededLibsSize; i++)
strncpy(TmpBuffer->Libraries[i].Name, NeededLibraries[i],
sizeof(TmpBuffer->Libraries[i].Name) - 1);
#ifdef DEBUG
debug("Input:");
debug("Path: %s", TargetPath->c_str());
debug("MemoryImage: %p", MemoryImage);
for (size_t i = 0; i < NeededLibsSize; i++)
debug("Library: %s", NeededLibraries[i]);
debug("Buffer:");
debug("Path: %s", TmpBuffer->Path);
debug("MemoryImage: %p", TmpBuffer->MemoryImage);
for (size_t i = 0; i < 64; i++)
{
if (TmpBuffer->Libraries[i].Name[0] != '\0')
break;
debug("Library: %s", TmpBuffer->Libraries[i].Name);
}
#endif
RetryIPCWrite:
InterProcessCommunication::IPCErrorCode ret =
TargetProcess->IPC->Write(Handle->ID, TmpBuffer, sizeof(InterpreterIPCData));
debug("Write returned %d", ret);
if (ret == InterProcessCommunication::IPCErrorCode::IPCNotListening)
{
debug("IPC not listening, retrying...");
TaskManager->Sleep(100);
goto RetryIPCWrite;
}
delete TmpBuffer;
while (!TargetProcess->IPC->SearchByToken(UniqueToken))
TaskManager->Schedule();
debug("Interpreter thread finished for %s", TargetPath->c_str());
for (size_t i = 0; i < NeededLibsSize; i++)
delete[] NeededLibraries[i];
delete TargetPath;
TEXIT(0);
}
uintptr_t LoadELFInterpreter(Memory::MemMgr *mem, Memory::Virtual &vmm, const char *Interpreter)
{
if (GetBinaryType((char *)Interpreter) != BinaryType::BinTypeELF)
{
error("Interpreter \"%s\" is not an ELF file.", Interpreter);
return 0;
}
/* No need to check if it's valid because
the function that calls this already checks it. */
VirtualFileSystem::File ElfFile = vfs->Open(Interpreter);
Elf64_Ehdr ELFHeader;
vfs->Read(ElfFile, (uint8_t *)&ELFHeader, sizeof(Elf64_Ehdr));
debug("Interpreter type: %#x", ELFHeader.e_type);
uintptr_t BaseAddress;
size_t ElfPHDRsSize;
GetBaseAndSize(ElfFile, BaseAddress, ElfPHDRsSize);
MmImage MemoryImage = ELFCreateMemoryImage(mem, vmm, ElfFile, ElfPHDRsSize);
CopyLOADSegments(ElfFile, BaseAddress, (uintptr_t)MemoryImage.Physical);
vfs->Close(ElfFile);
bool IsPIC = ELFHeader.e_type == ET_DYN;
debug("Elf %s PIC", IsPIC ? "is" : "is not");
if (IsPIC)
{
debug("Interpreter entry point: %#lx (%#lx + %#lx)",
(uintptr_t)MemoryImage.Physical + ELFHeader.e_entry,
(uintptr_t)MemoryImage.Physical, ELFHeader.e_entry);
return (uintptr_t)MemoryImage.Physical + ELFHeader.e_entry;
}
else
{
debug("Interpreter entry point: %#lx", ELFHeader.e_entry);
return ELFHeader.e_entry;
}
}
}

View File

@ -1,480 +0,0 @@
/*
This file is part of Fennix Kernel.
Fennix Kernel is free software: you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation, either version 3 of
the License, or (at your option) any later version.
Fennix Kernel is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
*/
#include <exec.hpp>
#include <memory.hpp>
#include <lock.hpp>
#include <msexec.h>
#include <cwalk.h>
#include <elf.h>
#include <abi.h>
#include "../../kernel.h"
#include "../../Fex.hpp"
using namespace Tasking;
using namespace VirtualFileSystem;
namespace Execute
{
ELFBaseLoad ELFObject::LoadExec_x86_32(File &ElfFile, PCB *TargetProcess)
{
stub;
return {};
}
ELFBaseLoad ELFObject::LoadExec_x86_64(File &ElfFile, PCB *TargetProcess)
{
ELFBaseLoad ELFBase{};
uintptr_t BaseAddress;
size_t ElfPHDRsSize;
GetBaseAndSize(ElfFile, BaseAddress, ElfPHDRsSize);
Elf64_Ehdr ELFHeader;
vfs->Read(ElfFile, (uint8_t *)&ELFHeader, sizeof(Elf64_Ehdr));
uintptr_t EntryPoint = ELFHeader.e_entry;
debug("%s's entry point is %#lx", ElfFile.Name, EntryPoint);
ELFBase.TmpMem = new Memory::MemMgr(TargetProcess->PageTable); /* This should be deleted inside BaseLoad.cpp */
Memory::Virtual vmm(TargetProcess->PageTable);
/* If required, MemoryImage will be at virtual address. (unless is PIC)
tl;dr this is where the code is stored. */
MmImage MemoryImage = ELFCreateMemoryImage(ELFBase.TmpMem, vmm, ElfFile, ElfPHDRsSize);
debug("Solving symbols for %s", ElfFile.Name);
std::vector<Elf64_Shdr> DynamicString = ELFGetSections_x86_64(ElfFile, ".dynstr");
std::vector<Elf64_Shdr> StringTable = ELFGetSections_x86_64(ElfFile, ".strtab");
if (DynamicString.size() < 1) /* TODO: check if this is required */
DynamicString = StringTable;
/* Calculate entry point */
Elf64_Phdr FirstPhdr;
vfs->Seek(ElfFile, ELFHeader.e_phoff, SEEK_SET);
vfs->Read(ElfFile, (uint8_t *)&FirstPhdr, sizeof(Elf64_Phdr));
/* FIXME: this is not the correct way to calculate entry point */
if (FirstPhdr.p_vaddr == 0)
{
debug("Entry point is null. Adding virtual address to entry point");
EntryPoint += (uintptr_t)MemoryImage.Virtual;
}
CopyLOADSegments(ElfFile, BaseAddress, (uintptr_t)MemoryImage.Physical);
foreach (auto Tag in ELFGetDynamicTag_x86_64(ElfFile, DT_NEEDED))
{
const char *ReqLib = new char[256];
vfs->Seek(ElfFile, DynamicString[0].sh_offset + Tag.d_un.d_val, SEEK_SET);
vfs->Read(ElfFile, (uint8_t *)ReqLib, 256);
debug("DT_NEEDED - %s", ReqLib);
ELFBase.NeededLibraries.push_back(ReqLib);
}
char InterpreterPath[256] = {'\0'};
std::vector<Elf64_Phdr> PhdrINTERP = ELFGetSymbolType_x86_64(ElfFile, PT_INTERP);
foreach (auto Interp in PhdrINTERP)
{
const char *InterpPath = new char[256];
vfs->Seek(ElfFile, Interp.p_offset, SEEK_SET);
vfs->Read(ElfFile, (uint8_t *)InterpPath, 256);
memcpy((void *)InterpreterPath, InterpPath,
(strlen(InterpPath) > 256) ? 256 : strlen(InterpPath));
debug("Interpreter: %s", InterpreterPath);
delete[] InterpPath;
VirtualFileSystem::File InterpreterFile = vfs->Open(InterpreterPath);
if (!InterpreterFile.IsOK())
{
warn("Failed to open interpreter file: %s", InterpreterPath);
vfs->Close(InterpreterFile);
continue;
}
else
{
if (GetBinaryType(InterpreterPath) != BinTypeELF)
{
warn("Interpreter %s is not an ELF file", InterpreterPath);
vfs->Close(InterpreterFile);
continue;
}
vfs->Close(InterpreterFile);
break;
}
}
if (strlen(InterpreterPath) > 1)
{
EntryPoint = LoadELFInterpreter(ELFBase.TmpMem, vmm, InterpreterPath);
ELFBase.Interpreter = true;
}
debug("Entry Point: %#lx", EntryPoint);
char *aux_platform = (char *)ELFBase.TmpMem->RequestPages(1, true); /* TODO: 4096 bytes is too much for this */
strcpy(aux_platform, "x86_64");
ELFBase.auxv.push_back({.archaux = {.a_type = AT_NULL, .a_un = {.a_val = 0}}});
ELFBase.auxv.push_back({.archaux = {.a_type = AT_EXECFN, .a_un = {.a_val = (uint64_t)0 /* FIXME */}}});
ELFBase.auxv.push_back({.archaux = {.a_type = AT_PLATFORM, .a_un = {.a_val = (uint64_t)aux_platform}}});
ELFBase.auxv.push_back({.archaux = {.a_type = AT_ENTRY, .a_un = {.a_val = (uint64_t)EntryPoint}}});
ELFBase.auxv.push_back({.archaux = {.a_type = AT_BASE, .a_un = {.a_val = (uint64_t)MemoryImage.Virtual}}});
ELFBase.auxv.push_back({.archaux = {.a_type = AT_PAGESZ, .a_un = {.a_val = (uint64_t)PAGE_SIZE}}});
ELFBase.auxv.push_back({.archaux = {.a_type = AT_PHNUM, .a_un = {.a_val = (uint64_t)ELFHeader.e_phnum}}});
ELFBase.auxv.push_back({.archaux = {.a_type = AT_PHENT, .a_un = {.a_val = (uint64_t)ELFHeader.e_phentsize}}});
ELFBase.auxv.push_back({.archaux = {.a_type = AT_PHDR, .a_un = {.a_val = (uint64_t)ELFHeader.e_phoff}}});
ELFBase.InstructionPointer = EntryPoint;
ELFBase.MemoryImage = MemoryImage.Physical;
ELFBase.VirtualMemoryImage = MemoryImage.Virtual;
ELFBase.Success = true;
return ELFBase;
}
ELFBaseLoad ELFObject::LoadDyn_x86_32(File &ElfFile, PCB *TargetProcess, bool IsLibrary)
{
stub;
return {};
}
ELFBaseLoad ELFObject::LoadDyn_x86_64(File &ElfFile, PCB *TargetProcess, bool IsLibrary)
{
ELFBaseLoad ELFBase{};
uintptr_t BaseAddress;
size_t ElfPHDRsSize;
GetBaseAndSize(ElfFile, BaseAddress, ElfPHDRsSize);
Elf64_Ehdr ELFHeader;
vfs->Read(ElfFile, (uint8_t *)&ELFHeader, sizeof(Elf64_Ehdr));
uintptr_t EntryPoint = ELFHeader.e_entry;
debug("%s's entry point is %#lx", ElfFile.Name, EntryPoint);
ELFBase.TmpMem = new Memory::MemMgr(TargetProcess->PageTable); /* This should be deleted inside BaseLoad.cpp */
Memory::Virtual vmm(TargetProcess->PageTable);
/* If required, MemoryImage will be at virtual address. (unless is PIC)
tl;dr this is where the code is stored. */
MmImage MemoryImage = ELFCreateMemoryImage(ELFBase.TmpMem, vmm, ElfFile, ElfPHDRsSize);
debug("Solving symbols for %s", ElfFile.Name);
std::vector<Elf64_Shdr> DynamicString = ELFGetSections_x86_64(ElfFile, ".dynstr");
std::vector<Elf64_Shdr> StringTable = ELFGetSections_x86_64(ElfFile, ".strtab");
if (DynamicString.size() < 1) /* TODO: check if this is required */
DynamicString = StringTable;
/* Calculate entry point */
Elf64_Phdr FirstPhdr;
vfs->Seek(ElfFile, ELFHeader.e_phoff, SEEK_SET);
vfs->Read(ElfFile, (uint8_t *)&FirstPhdr, sizeof(Elf64_Phdr));
/* FIXME: this is not the correct way to calculate entry point */
if (FirstPhdr.p_vaddr == 0)
{
debug("Entry point is null. Adding virtual address to entry point");
EntryPoint += (uintptr_t)MemoryImage.Virtual;
}
CopyLOADSegments(ElfFile, BaseAddress, (uintptr_t)MemoryImage.Physical);
foreach (auto Tag in ELFGetDynamicTag_x86_64(ElfFile, DT_NEEDED))
{
const char *ReqLib = new char[256];
vfs->Seek(ElfFile, DynamicString[0].sh_offset + Tag.d_un.d_val, SEEK_SET);
vfs->Read(ElfFile, (uint8_t *)ReqLib, 256);
debug("DT_NEEDED - %s", ReqLib);
ELFBase.NeededLibraries.push_back(ReqLib);
}
std::vector<Elf64_Dyn> JmpRel = ELFGetDynamicTag_x86_64(ElfFile, DT_JMPREL);
std::vector<Elf64_Dyn> SymTab = ELFGetDynamicTag_x86_64(ElfFile, DT_SYMTAB);
std::vector<Elf64_Dyn> StrTab = ELFGetDynamicTag_x86_64(ElfFile, DT_STRTAB);
if (JmpRel.size() < 1)
{
debug("No DT_JMPREL");
}
if (SymTab.size() < 1)
{
debug("No DT_SYMTAB");
}
if (StrTab.size() < 1)
{
debug("No DT_STRTAB");
}
if (JmpRel.size() > 1 &&
SymTab.size() > 1 &&
StrTab.size() > 1)
{
debug("JmpRel: %#lx, SymTab: %#lx, StrTab: %#lx", JmpRel[0].d_un.d_ptr, SymTab[0].d_un.d_ptr, StrTab[0].d_un.d_ptr);
Elf64_Rela *_JmpRel = (Elf64_Rela *)((uintptr_t)MemoryImage.Physical + (JmpRel[0].d_un.d_ptr - BaseAddress));
Elf64_Sym *_SymTab = (Elf64_Sym *)((uintptr_t)MemoryImage.Physical + (SymTab[0].d_un.d_ptr - BaseAddress));
char *_DynStr = (char *)((uintptr_t)MemoryImage.Physical + (StrTab[0].d_un.d_ptr - BaseAddress));
Elf64_Shdr *gotSection = nullptr;
Elf64_Shdr shdr;
for (Elf64_Half i = 0; i < ELFHeader.e_shnum; i++)
{
vfs->Seek(ElfFile, ELFHeader.e_shoff + i * sizeof(Elf64_Shdr), SEEK_SET);
vfs->Read(ElfFile, (uint8_t *)&shdr, sizeof(Elf64_Shdr));
if (shdr.sh_type == SHT_PROGBITS &&
(shdr.sh_flags & SHF_WRITE) &&
(shdr.sh_flags & SHF_ALLOC))
{
gotSection = new Elf64_Shdr;
*gotSection = shdr;
break;
}
}
if (gotSection)
{
Elf64_Xword numEntries = gotSection->sh_size / sizeof(Elf64_Addr);
for (Elf64_Xword i = 0; i < numEntries - 3; i++)
{
Elf64_Rela *Rel = _JmpRel + i;
Elf64_Addr *GOTEntry = (Elf64_Addr *)(Rel->r_offset + (uintptr_t)MemoryImage.Physical);
Elf64_Xword RelType = ELF64_R_TYPE(Rel->r_info);
debug("r_offset: %#lx RelType: %d", Rel->r_offset, RelType);
switch (RelType)
{
case R_X86_64_NONE:
break;
case R_X86_64_JUMP_SLOT:
{
Elf64_Xword SymIndex = ELF64_R_SYM(Rel->r_info);
Elf64_Sym *Sym = _SymTab + SymIndex;
if (Sym->st_name)
{
char *SymName = _DynStr + Sym->st_name;
debug("SymName: %s", SymName);
Elf64_Sym LibSym = ELFLookupSymbol(ElfFile, SymName);
if (LibSym.st_value)
{
*GOTEntry = (Elf64_Addr)((uintptr_t)MemoryImage.Physical + LibSym.st_value);
debug("GOT[%ld]: %#lx + %#lx = %#lx",
i, (uintptr_t)MemoryImage.Physical, LibSym.st_value, *GOTEntry);
}
}
break;
}
default:
{
fixme("RelType %d not supported", RelType);
break;
}
}
debug("GOT[%ld](%#lx): %#lx", i, GOTEntry, *GOTEntry);
}
delete gotSection;
}
else
{
debug("GOT section not found");
}
}
/* ------------------------------------------------------------------------ */
foreach (auto Tag in ELFGetDynamicTag_x86_64(ElfFile, DT_NEEDED))
{
const char *ReqLib = new char[256];
vfs->Seek(ElfFile, DynamicString[0].sh_offset + Tag.d_un.d_val, SEEK_SET);
vfs->Read(ElfFile, (uint8_t *)ReqLib, 256);
debug("DT_NEEDED - %s", ReqLib);
ELFBase.NeededLibraries.push_back(ReqLib);
}
char InterpreterPath[256] = {'\0'};
std::vector<Elf64_Phdr> PhdrINTERP = ELFGetSymbolType_x86_64(ElfFile, PT_INTERP);
foreach (auto Interp in PhdrINTERP)
{
const char *InterpPath = new char[256];
vfs->Seek(ElfFile, Interp.p_offset, SEEK_SET);
vfs->Read(ElfFile, (uint8_t *)InterpPath, 256);
memcpy((void *)InterpreterPath, InterpPath,
(strlen(InterpPath) > 256) ? 256 : strlen(InterpPath));
debug("Interpreter: %s", InterpreterPath);
delete[] InterpPath;
VirtualFileSystem::File InterpreterFile = vfs->Open(InterpreterPath);
if (!InterpreterFile.IsOK())
{
warn("Failed to open interpreter file: %s", InterpreterPath);
vfs->Close(InterpreterFile);
continue;
}
else
{
if (GetBinaryType(InterpreterPath) != BinTypeELF)
{
warn("Interpreter %s is not an ELF file", InterpreterPath);
vfs->Close(InterpreterFile);
continue;
}
vfs->Close(InterpreterFile);
break;
}
}
if (strlen(InterpreterPath) > 1)
{
EntryPoint = LoadELFInterpreter(ELFBase.TmpMem, vmm, InterpreterPath);
ELFBase.Interpreter = true;
}
else if (IsLibrary)
{
/* FIXME: Detect interpreter from current running process. */
EntryPoint = LoadELFInterpreter(ELFBase.TmpMem, vmm, "/lib/ld.so");
ELFBase.Interpreter = true;
}
debug("Entry Point: %#lx", EntryPoint);
char *aux_platform = (char *)ELFBase.TmpMem->RequestPages(1, true); /* TODO: 4096 bytes is too much for this */
strcpy(aux_platform, "x86_64");
ELFBase.auxv.push_back({.archaux = {.a_type = AT_NULL, .a_un = {.a_val = 0}}});
ELFBase.auxv.push_back({.archaux = {.a_type = AT_EXECFN, .a_un = {.a_val = (uint64_t)0 /* FIXME */}}});
ELFBase.auxv.push_back({.archaux = {.a_type = AT_PLATFORM, .a_un = {.a_val = (uint64_t)aux_platform}}});
ELFBase.auxv.push_back({.archaux = {.a_type = AT_ENTRY, .a_un = {.a_val = (uint64_t)EntryPoint}}});
ELFBase.auxv.push_back({.archaux = {.a_type = AT_BASE, .a_un = {.a_val = (uint64_t)MemoryImage.Virtual}}});
ELFBase.auxv.push_back({.archaux = {.a_type = AT_PAGESZ, .a_un = {.a_val = (uint64_t)PAGE_SIZE}}});
ELFBase.auxv.push_back({.archaux = {.a_type = AT_PHNUM, .a_un = {.a_val = (uint64_t)ELFHeader.e_phnum}}});
ELFBase.auxv.push_back({.archaux = {.a_type = AT_PHENT, .a_un = {.a_val = (uint64_t)ELFHeader.e_phentsize}}});
ELFBase.auxv.push_back({.archaux = {.a_type = AT_PHDR, .a_un = {.a_val = (uint64_t)ELFHeader.e_phoff}}});
ELFBase.InstructionPointer = EntryPoint;
ELFBase.MemoryImage = MemoryImage.Physical;
ELFBase.VirtualMemoryImage = MemoryImage.Virtual;
ELFBase.Success = true;
return ELFBase;
}
ELFObject::ELFObject(char *AbsolutePath,
PCB *TargetProcess,
bool IsLibrary)
{
if (GetBinaryType(AbsolutePath) != BinaryType::BinTypeELF)
{
error("%s is not an ELF file or is invalid.", AbsolutePath);
return;
}
VirtualFileSystem::File ExFile = vfs->Open(AbsolutePath);
Elf32_Ehdr ELFHeader;
vfs->Read(ExFile, (uint8_t *)&ELFHeader, sizeof(Elf32_Ehdr));
ELFBaseLoad bl;
switch (ELFHeader.e_type)
{
case ET_REL:
{
fixme("ET_REL not implemented");
break;
}
case ET_EXEC:
{
switch (ELFHeader.e_machine)
{
case EM_386:
this->BaseLoadInfo = this->LoadExec_x86_32(ExFile,
TargetProcess);
break;
case EM_X86_64:
this->BaseLoadInfo = this->LoadExec_x86_64(ExFile,
TargetProcess);
break;
case EM_ARM:
error("ARM is not supported yet!");
break;
case EM_AARCH64:
error("ARM64 is not supported yet!");
break;
default:
error("Unknown architecture: %d", ELFHeader.e_machine);
break;
}
break;
}
case ET_DYN:
{
switch (ELFHeader.e_machine)
{
case EM_386:
this->BaseLoadInfo = this->LoadDyn_x86_32(ExFile,
TargetProcess,
IsLibrary);
break;
case EM_X86_64:
this->BaseLoadInfo = this->LoadDyn_x86_64(ExFile,
TargetProcess,
IsLibrary);
break;
case EM_ARM:
error("ARM is not supported yet!");
break;
case EM_AARCH64:
error("ARM64 is not supported yet!");
break;
default:
error("Unknown architecture: %d", ELFHeader.e_machine);
break;
}
break;
}
case ET_CORE:
{
fixme("ET_CORE not implemented");
break;
}
case ET_NONE:
default:
{
error("Unknown ELF Type: %d", ELFHeader.e_type);
break;
}
}
vfs->Close(ExFile);
}
ELFObject::~ELFObject()
{
}
}

View File

@ -1,340 +0,0 @@
/*
This file is part of Fennix Kernel.
Fennix Kernel is free software: you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation, either version 3 of
the License, or (at your option) any later version.
Fennix Kernel is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
*/
#include <exec.hpp>
#include <msexec.h>
#include "../../kernel.h"
#include "../../Fex.hpp"
namespace Execute
{
bool ELFIs64(void *Header)
{
Elf32_Ehdr *ELFHeader = (Elf32_Ehdr *)Header;
if (ELFHeader->e_ident[EI_CLASS] == ELFCLASS64)
return true;
return false;
}
/* Originally from https://wiki.osdev.org/ELF_Tutorial */
Elf64_Shdr *GetELFSheader(Elf64_Ehdr *Header)
{
return (Elf64_Shdr *)((uintptr_t)Header + Header->e_shoff);
}
Elf64_Shdr *GetELFSection(Elf64_Ehdr *Header, uint64_t Index)
{
return &GetELFSheader(Header)[Index];
}
char *GetELFStringTable(Elf64_Ehdr *Header)
{
if (Header->e_shstrndx == SHN_UNDEF)
return nullptr;
return (char *)Header + GetELFSection(Header, Header->e_shstrndx)->sh_offset;
}
char *ELFLookupString(Elf64_Ehdr *Header, uintptr_t Offset)
{
char *StringTable = GetELFStringTable(Header);
if (StringTable == nullptr)
return nullptr;
return StringTable + Offset;
}
Elf64_Sym *ELFLookupSymbol(Elf64_Ehdr *Header, const char *Name)
{
Elf64_Shdr *SymbolTable = nullptr;
Elf64_Shdr *StringTable = nullptr;
for (Elf64_Half i = 0; i < Header->e_shnum; i++)
{
Elf64_Shdr *shdr = GetELFSection(Header, i);
switch (shdr->sh_type)
{
case SHT_SYMTAB:
SymbolTable = shdr;
StringTable = GetELFSection(Header, shdr->sh_link);
break;
default:
{
break;
}
}
}
if (SymbolTable == nullptr || StringTable == nullptr)
return nullptr;
for (size_t i = 0; i < (SymbolTable->sh_size / sizeof(Elf64_Sym)); i++)
{
Elf64_Sym *Symbol = (Elf64_Sym *)((uintptr_t)Header + SymbolTable->sh_offset + (i * sizeof(Elf64_Sym)));
char *String = (char *)((uintptr_t)Header + StringTable->sh_offset + Symbol->st_name);
if (strcmp(String, Name) == 0)
return Symbol;
}
return nullptr;
}
Elf64_Sym ELFLookupSymbol(VirtualFileSystem::File &ElfFile, const char *Name)
{
off_t OldOffset = vfs->Seek(ElfFile, 0, SEEK_CUR);
Elf64_Ehdr Header;
vfs->Seek(ElfFile, 0, SEEK_SET);
vfs->Read(ElfFile, (uint8_t *)&Header, sizeof(Elf64_Ehdr));
Elf64_Shdr SymbolTable;
Elf64_Shdr StringTable;
for (Elf64_Half i = 0; i < Header.e_shnum; i++)
{
Elf64_Shdr shdr;
vfs->Seek(ElfFile, Header.e_shoff + (i * sizeof(Elf64_Shdr)), SEEK_SET);
vfs->Read(ElfFile, (uint8_t *)&shdr, sizeof(Elf64_Shdr));
switch (shdr.sh_type)
{
case SHT_SYMTAB:
SymbolTable = shdr;
vfs->Seek(ElfFile, Header.e_shoff + (shdr.sh_link * sizeof(Elf64_Shdr)), SEEK_SET);
vfs->Read(ElfFile, (uint8_t *)&StringTable, sizeof(Elf64_Shdr));
break;
default:
{
break;
}
}
}
if (SymbolTable.sh_name == 0 ||
StringTable.sh_name == 0)
{
error("Symbol table not found.");
vfs->Seek(ElfFile, OldOffset, SEEK_SET);
return {};
}
for (size_t i = 0; i < (SymbolTable.sh_size / sizeof(Elf64_Sym)); i++)
{
// Elf64_Sym *Symbol = (Elf64_Sym *)((uintptr_t)Header + SymbolTable->sh_offset + (i * sizeof(Elf64_Sym)));
Elf64_Sym Symbol;
vfs->Seek(ElfFile, SymbolTable.sh_offset + (i * sizeof(Elf64_Sym)), SEEK_SET);
vfs->Read(ElfFile, (uint8_t *)&Symbol, sizeof(Elf64_Sym));
// char *String = (char *)((uintptr_t)Header + StringTable->sh_offset + Symbol->st_name);
char String[256];
vfs->Seek(ElfFile, StringTable.sh_offset + Symbol.st_name, SEEK_SET);
vfs->Read(ElfFile, (uint8_t *)&String, 256);
if (strcmp(String, Name) == 0)
{
vfs->Seek(ElfFile, OldOffset, SEEK_SET);
return Symbol;
}
}
error("Symbol not found.");
vfs->Seek(ElfFile, OldOffset, SEEK_SET);
return {};
}
uintptr_t ELFGetSymbolValue(Elf64_Ehdr *Header, uint64_t Table, uint64_t Index)
{
#if defined(a64)
if (Table == SHN_UNDEF || Index == SHN_UNDEF)
return 0;
Elf64_Shdr *SymbolTable = GetELFSection(Header, Table);
uint64_t STEntries = SymbolTable->sh_size / SymbolTable->sh_entsize;
if (Index >= STEntries)
{
error("Symbol index out of range %d-%u.", Table, Index);
return 0xdead;
}
uint64_t SymbolAddress = (uint64_t)Header + SymbolTable->sh_offset;
Elf64_Sym *Symbol = &((Elf64_Sym *)SymbolAddress)[Index];
if (Symbol->st_shndx == SHN_UNDEF)
{
Elf64_Shdr *StringTable = GetELFSection(Header, SymbolTable->sh_link);
const char *Name = (const char *)Header + StringTable->sh_offset + Symbol->st_name;
void *Target = (void *)ELFLookupSymbol(Header, Name)->st_value;
if (Target == nullptr)
{
if (ELF64_ST_BIND(Symbol->st_info) & STB_WEAK)
return 0;
else
{
error("Undefined external symbol \"%s\".", Name);
return 0xdead;
}
}
else
return (uintptr_t)Target;
}
else if (Symbol->st_shndx == SHN_ABS)
return Symbol->st_value;
else
{
Elf64_Shdr *Target = GetELFSection(Header, Symbol->st_shndx);
return (uintptr_t)Header + Symbol->st_value + Target->sh_offset;
}
#endif
}
void CopyLOADSegments(VirtualFileSystem::File &ElfFile, uintptr_t HdrsBase, uintptr_t PhysicalBase)
{
off_t OldOffset = vfs->Seek(ElfFile, 0, SEEK_CUR);
Elf64_Ehdr ELFHeader;
vfs->Seek(ElfFile, 0, SEEK_SET);
vfs->Read(ElfFile, (uint8_t *)&ELFHeader, sizeof(Elf64_Ehdr));
Elf64_Phdr ProgramHeaders;
for (Elf64_Half i = 0; i < ELFHeader.e_phnum; i++)
{
vfs->Seek(ElfFile, ELFHeader.e_phoff + (i * sizeof(Elf64_Phdr)), SEEK_SET);
vfs->Read(ElfFile, (uint8_t *)&ProgramHeaders, sizeof(Elf64_Phdr));
if (ProgramHeaders.p_type != PT_LOAD)
continue;
uintptr_t SegmentDestination = (ProgramHeaders.p_vaddr - HdrsBase) + PhysicalBase;
debug("Copying segment to %#lx (%ld file bytes, %ld mem bytes)",
SegmentDestination,
ProgramHeaders.p_filesz, ProgramHeaders.p_memsz);
if (ProgramHeaders.p_filesz > 0)
{
vfs->Seek(ElfFile, ProgramHeaders.p_offset, SEEK_SET);
vfs->Read(ElfFile, (uint8_t *)SegmentDestination, ProgramHeaders.p_filesz);
}
if (ProgramHeaders.p_memsz - ProgramHeaders.p_filesz > 0)
memset((void *)(SegmentDestination + ProgramHeaders.p_filesz),
0,
ProgramHeaders.p_memsz - ProgramHeaders.p_filesz);
}
vfs->Seek(ElfFile, OldOffset, SEEK_SET);
}
void GetBaseAndSize(VirtualFileSystem::File &ElfFile, uintptr_t &Base, size_t &Size)
{
Base = UINTPTR_MAX;
Size = 0;
off_t OldOffset = vfs->Seek(ElfFile, 0, SEEK_CUR);
Elf64_Ehdr ELFHeader;
vfs->Seek(ElfFile, 0, SEEK_SET);
vfs->Read(ElfFile, (uint8_t *)&ELFHeader, sizeof(Elf64_Ehdr));
Elf64_Phdr ProgramHeaders;
vfs->Seek(ElfFile, ELFHeader.e_phoff, SEEK_SET);
vfs->Read(ElfFile, (uint8_t *)&ProgramHeaders, sizeof(Elf64_Phdr));
for (Elf64_Half i = 0; i < ELFHeader.e_phnum; i++)
{
Base = MIN(Base, ProgramHeaders.p_vaddr);
uintptr_t SegmentEnd = ProgramHeaders.p_vaddr - Base + ProgramHeaders.p_memsz;
Size = MAX(Size, SegmentEnd);
vfs->Seek(ElfFile, sizeof(Elf64_Phdr), SEEK_CUR);
vfs->Read(ElfFile, (uint8_t *)&ProgramHeaders, sizeof(Elf64_Phdr));
}
debug("Base: %#lx, Size: %#lx (%ld, %ld KB)", Base, Size, Size, TO_KB(Size));
vfs->Seek(ElfFile, OldOffset, SEEK_SET);
}
MmImage ELFCreateMemoryImage(Memory::MemMgr *mem,
Memory::Virtual &vmm,
VirtualFileSystem::File &ElfFile,
size_t Length)
{
off_t OldOffset = vfs->Seek(ElfFile, 0, SEEK_CUR);
void *MemoryImage = nullptr;
Elf64_Ehdr ELFHeader;
vfs->Seek(ElfFile, 0, SEEK_SET);
vfs->Read(ElfFile, (uint8_t *)&ELFHeader, sizeof(Elf64_Ehdr));
bool IsPIC = ELFHeader.e_type == ET_DYN;
UNUSED(IsPIC);
debug("Elf %s PIC", IsPIC ? "is" : "is not");
bool FirstProgramHeader = false;
uintptr_t FirstProgramHeaderVirtualAddress = 0x0;
Elf64_Phdr ProgramHeaders;
for (Elf64_Half i = 0; i < ELFHeader.e_phnum; i++)
{
vfs->Seek(ElfFile, ELFHeader.e_phoff + i * sizeof(Elf64_Phdr), SEEK_SET);
vfs->Read(ElfFile, (uint8_t *)&ProgramHeaders, sizeof(Elf64_Phdr));
if (ProgramHeaders.p_type != PT_LOAD)
continue;
if (!FirstProgramHeader)
{
FirstProgramHeader = true;
FirstProgramHeaderVirtualAddress = ProgramHeaders.p_vaddr;
}
if (ProgramHeaders.p_vaddr == 0)
{
debug("p_vaddr is 0, allocating %ld pages for image (size: %#lx)", TO_PAGES(Length), Length);
MemoryImage = mem->RequestPages(TO_PAGES(Length), true);
debug("MemoryImage: %#lx-%#lx", MemoryImage, (uintptr_t)MemoryImage + Length);
memset(MemoryImage, 0, Length);
vfs->Seek(ElfFile, OldOffset, SEEK_SET);
return {MemoryImage, (void *)FirstProgramHeaderVirtualAddress};
}
}
debug("Allocating %ld pages for image (size: %#lx)", TO_PAGES(Length), Length);
MemoryImage = mem->RequestPages(TO_PAGES(Length));
debug("MemoryImage: %#lx-%#lx", MemoryImage, (uintptr_t)MemoryImage + Length);
memset(MemoryImage, 0, Length);
uintptr_t FirstProgramHeaderVirtualAddressAligned = 0;
if (FirstProgramHeaderVirtualAddress != 0)
{
FirstProgramHeaderVirtualAddressAligned = ALIGN_DOWN(FirstProgramHeaderVirtualAddress, PAGE_SIZE);
debug("Aligning address %#lx to %#lx",
FirstProgramHeaderVirtualAddress,
FirstProgramHeaderVirtualAddressAligned);
}
else
FirstProgramHeaderVirtualAddress = (uintptr_t)MemoryImage;
for (size_t i = 0; i < TO_PAGES(Length); i++)
{
vmm.Remap((void *)((uintptr_t)FirstProgramHeaderVirtualAddressAligned + (i * PAGE_SIZE)), (void *)((uintptr_t)MemoryImage + (i * PAGE_SIZE)), Memory::PTFlag::RW | Memory::PTFlag::US);
debug("Remapped: %#lx -> %#lx", (uintptr_t)FirstProgramHeaderVirtualAddressAligned + (i * PAGE_SIZE), (uintptr_t)MemoryImage + (i * PAGE_SIZE));
}
vfs->Seek(ElfFile, OldOffset, SEEK_SET);
return {MemoryImage, (void *)FirstProgramHeaderVirtualAddress};
}
}

View File

@ -1,159 +0,0 @@
/*
This file is part of Fennix Kernel.
Fennix Kernel is free software: you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation, either version 3 of
the License, or (at your option) any later version.
Fennix Kernel is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
*/
#include <exec.hpp>
#include <memory.hpp>
#include <lock.hpp>
#include <msexec.h>
#include <cwalk.h>
#include <elf.h>
#include <abi.h>
#ifdef DEBUG
#include <dumper.hpp>
#endif
#include "../../kernel.h"
#include "../../Fex.hpp"
using namespace Tasking;
NewLock(ExecuteServiceLock);
namespace Execute
{
Memory::MemMgr *mem = nullptr;
std::vector<SharedLibrary> Libs;
void LibraryManagerService()
{
mem = new Memory::MemMgr;
while (true)
{
{
SmartLock(ExecuteServiceLock);
foreach (auto &Lib in Libs)
{
if (Lib.RefCount > 0)
{
Lib.Timeout = TimeManager->CalculateTarget(10, Time::Units::Minutes);
debug("Reset timeout for %s", Lib.Identifier);
continue;
}
if (Lib.Timeout < TimeManager->GetCounter())
{
// TODO: Remove library from memory
fixme("Removed library %s because of timeout", Lib.Identifier);
}
else
{
debug("Timeout for %s is %ld", Lib.Identifier, Lib.Timeout);
}
}
debug("Waiting 10 seconds...");
}
TaskManager->Sleep(10000);
}
}
bool AddLibrary(char *Identifier,
VirtualFileSystem::File &ExFile,
const Memory::Virtual &vmm)
{
SmartLock(ExecuteServiceLock);
SharedLibrary sl;
foreach (auto lib in Libs)
{
if (strcmp(lib.Identifier, Identifier) == 0)
{
debug("Library %s already loaded", Identifier);
lib.RefCount++;
return true;
}
}
PCB *Process = TaskManager->GetCurrentProcess();
ELFObject *obj = new ELFObject(vfs->GetPathFromNode(ExFile.GetNode()).get(), Process, true);
if (!obj->IsValid())
{
error("Failed to load dynamic ELF");
return false;
}
ELFBaseLoad bl = obj->GetBaseLoadInfo();
strncpy(sl.Identifier, Identifier, sizeof(sl.Identifier) - 1);
char *AbsolutePath = vfs->GetPathFromNode(ExFile.GetNode()).get();
strncpy(sl.Path, AbsolutePath, sizeof(sl.Path) - 1);
sl.Timeout = TimeManager->CalculateTarget(10, Time::Units::Minutes);
sl.RefCount = 0;
sl.MemoryImage = (uintptr_t)bl.MemoryImage;
sl.Length = ExFile.GetLength();
Libs.push_back(sl);
debug("Library %s loaded at %#lx", Identifier, sl.MemoryImage);
if (bl.InstructionPointer)
{
TCB *Thread = TaskManager->CreateThread(Process,
bl.InstructionPointer,
nullptr,
nullptr,
bl.auxv,
Process->Info.Architecture,
Process->Info.Compatibility,
true);
Thread->Rename(Identifier);
Thread->Status = TaskStatus::Ready;
foreach (Memory::MemMgr::AllocatedPages p in bl.TmpMem->GetAllocatedPagesList())
{
Thread->Memory->Add(p.Address, p.PageCount);
bl.TmpMem->DetachAddress(p.Address);
}
}
else
{
foreach (Memory::MemMgr::AllocatedPages p in bl.TmpMem->GetAllocatedPagesList())
{
/* FIXME: MEMORY LEAK */
// Process->Memory->Add(p.Address, p.PageCount);
bl.TmpMem->DetachAddress(p.Address);
fixme("Potential memory leak. (%#lx - %ld)",
p.Address, p.PageCount);
}
}
return true;
}
SharedLibrary GetLibrary(char *Identifier)
{
SmartLock(ExecuteServiceLock);
foreach (auto Lib in Libs)
{
if (strcmp(Lib.Identifier, Identifier) == 0)
{
Lib.RefCount++;
debug("Library %s found at %#lx", Identifier, Lib.MemoryImage);
return Lib;
}
}
error("Library %s not found", Identifier);
return SharedLibrary();
}
}

View File

@ -1,99 +0,0 @@
/*
This file is part of Fennix Kernel.
Fennix Kernel is free software: you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation, either version 3 of
the License, or (at your option) any later version.
Fennix Kernel is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
*/
#include <exec.hpp>
#include <memory.hpp>
#include <lock.hpp>
#include <msexec.h>
#include <cwalk.h>
#include <elf.h>
#include <abi.h>
#include "../kernel.h"
#include "../Fex.hpp"
using namespace Tasking;
namespace Execute
{
SpawnData Spawn(char *Path, const char **argv, const char **envp)
{
SpawnData ret = {.Status = ExStatus::Unknown,
.Process = nullptr,
.Thread = nullptr};
VirtualFileSystem::File ExFile = vfs->Open(Path);
if (!ExFile.IsOK())
{
if (ExFile.Status == VirtualFileSystem::FileStatus::NotFound)
{
ret.Status = ExStatus::InvalidFilePath;
goto Exit;
}
else
{
ret.Status = ExStatus::InvalidFile;
goto Exit;
}
if (ExFile.GetFlags() != VirtualFileSystem::NodeFlags::FILE)
{
ret.Status = ExStatus::InvalidFilePath;
goto Exit;
}
}
switch (GetBinaryType(Path))
{
case BinaryType::BinTypeFex:
{
Fex FexHdr;
vfs->Read(ExFile, (uint8_t *)&FexHdr, sizeof(Fex));
if (FexHdr.Type == FexFormatType::FexFormatType_Executable)
{
stub;
assert(false);
}
ret.Status = ExStatus::InvalidFileHeader;
break;
}
case BinaryType::BinTypeELF:
{
ELFBaseLoad bl = ELFLoad(Path, argv, envp);
if (!bl.Success)
{
ret.Status = ExStatus::LoadingProcedureFailed;
break;
}
ret = bl.sd;
break;
}
default:
{
ret.Status = ExStatus::Unsupported;
break;
}
}
Exit:
vfs->Close(ExFile);
return ret;
}
}

View File

@ -0,0 +1,115 @@
/*
This file is part of Fennix Kernel.
Fennix Kernel is free software: you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation, either version 3 of
the License, or (at your option) any later version.
Fennix Kernel is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
*/
#include <exec.hpp>
#include <msexec.h>
#include "../kernel.h"
#include "../Fex.hpp"
namespace Execute
{
BinaryType GetBinaryType(const char *Path)
{
BinaryType Type;
int fd = fopen(Path, "r");
if (fd < 0)
return (BinaryType)fd;
debug("File opened: %s, descriptor %d", Path, fd);
Memory::SmartHeap sh = Memory::SmartHeap(1024);
fread(fd, sh, 128);
Fex *FexHdr = (Fex *)sh.GetObject();
Elf32_Ehdr *ELFHeader = (Elf32_Ehdr *)sh.GetObject();
IMAGE_DOS_HEADER *MZHeader = (IMAGE_DOS_HEADER *)sh.GetObject();
/* Check Fex header. */
if (FexHdr->Magic[0] == 'F' &&
FexHdr->Magic[1] == 'E' &&
FexHdr->Magic[2] == 'X' &&
FexHdr->Magic[3] == '\0')
{
/* If the fex type is driver, we shouldn't return as Fex. */
if (FexHdr->Type == FexFormatType_Executable)
{
debug("Image - Fex");
Type = BinaryType::BinTypeFex;
goto Success;
}
else if (FexHdr->Type == FexFormatType_Driver)
{
fixme("Fex Driver is not supposed to be executed.");
/* TODO: Driver installation pop-up. */
}
}
/* Check ELF header. */
else if (ELFHeader->e_ident[EI_MAG0] == ELFMAG0 &&
ELFHeader->e_ident[EI_MAG1] == ELFMAG1 &&
ELFHeader->e_ident[EI_MAG2] == ELFMAG2 &&
ELFHeader->e_ident[EI_MAG3] == ELFMAG3)
{
debug("Image - ELF");
Type = BinaryType::BinTypeELF;
goto Success;
}
/* Check MZ header. */
else if (MZHeader->e_magic == IMAGE_DOS_SIGNATURE)
{
lseek(fd, MZHeader->e_lfanew, SEEK_SET);
fread(fd, sh, 512);
IMAGE_NT_HEADERS *PEHeader =
(IMAGE_NT_HEADERS *)(((char *)sh.GetObject()) +
MZHeader->e_lfanew);
IMAGE_OS2_HEADER *NEHeader =
(IMAGE_OS2_HEADER *)(((char *)sh.GetObject()) +
MZHeader->e_lfanew);
/* TODO: LE, EDOS */
if (PEHeader->Signature == IMAGE_NT_SIGNATURE)
{
debug("Image - PE");
Type = BinaryType::BinTypePE;
goto Success;
}
else if (NEHeader->ne_magic == IMAGE_OS2_SIGNATURE)
{
debug("Image - NE");
Type = BinaryType::BinTypeNE;
goto Success;
}
else
{
debug("Image - MZ");
Type = BinaryType::BinTypeMZ;
goto Success;
}
}
/* ... */
Type = BinaryType::BinTypeUnknown;
Success:
fclose(fd);
return Type;
}
}

View File

@ -0,0 +1,791 @@
/*
This file is part of Fennix Kernel.
Fennix Kernel is free software: you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation, either version 3 of
the License, or (at your option) any later version.
Fennix Kernel is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
*/
#include <exec.hpp>
#include <memory.hpp>
#include <lock.hpp>
#include <msexec.h>
#include <cwalk.h>
#include <elf.h>
#include <abi.h>
#include "../../kernel.h"
#include "../../Fex.hpp"
using namespace Tasking;
using namespace VirtualFileSystem;
namespace Execute
{
void ELFObject::LoadExec_x86_32(int fd, PCB *TargetProcess)
{
stub;
UNUSED(fd);
UNUSED(TargetProcess);
}
void ELFObject::LoadExec_x86_64(int fd, PCB *TargetProcess)
{
std::string InterpreterPath;
std::vector<Elf64_Phdr> PhdrINTERP = ELFGetSymbolType_x86_64(fd, PT_INTERP);
foreach (auto Interp in PhdrINTERP)
{
Memory::SmartHeap sh = Memory::SmartHeap(256);
lseek(fd, Interp.p_offset, SEEK_SET);
fread(fd, sh, 256);
InterpreterPath = sh;
int ifd = fopen(InterpreterPath.c_str(), "r");
if (ifd < 0)
{
warn("Failed to open interpreter file: %s",
InterpreterPath.c_str());
continue;
}
else
{
if (GetBinaryType(InterpreterPath.c_str()) != BinTypeELF)
{
warn("Interpreter %s is not an ELF file",
InterpreterPath.c_str());
fclose(ifd);
continue;
}
if (LoadInterpreter(ifd, TargetProcess))
{
/* ba deci de aici trb sa fac
sa se incarce interperter-ul
argv[1] ar trb sa fie locatia pt intrep */
// modific argv-ul
// TODO FIXME TODO FIXME TODO FIXME TODO FIXME TODO FIXME TODO FIXME TODO FIXME TODO FIXME
// TODO FIXME TODO FIXME TODO FIXME TODO FIXME TODO FIXME TODO FIXME TODO FIXME TODO FIXME
// TODO FIXME TODO FIXME TODO FIXME TODO FIXME TODO FIXME TODO FIXME TODO FIXME TODO FIXME
// TODO FIXME TODO FIXME TODO FIXME TODO FIXME TODO FIXME TODO FIXME TODO FIXME TODO FIXME
// TODO FIXME TODO FIXME TODO FIXME TODO FIXME TODO FIXME TODO FIXME TODO FIXME TODO FIXME
// TODO FIXME TODO FIXME TODO FIXME TODO FIXME TODO FIXME TODO FIXME TODO FIXME TODO FIXME
// TODO FIXME TODO FIXME TODO FIXME TODO FIXME TODO FIXME TODO FIXME TODO FIXME TODO FIXME
debug("Interpreter loaded successfully");
fclose(ifd);
return;
}
}
}
Elf64_Ehdr ELFHeader;
fread(fd, (uint8_t *)&ELFHeader, sizeof(Elf64_Ehdr));
uintptr_t EntryPoint = ELFHeader.e_entry;
debug("Entry point is %#lx", EntryPoint);
debug("Solving symbols");
std::vector<Elf64_Shdr> DynamicString = ELFGetSections_x86_64(fd, ".dynstr");
std::vector<Elf64_Shdr> StringTable = ELFGetSections_x86_64(fd, ".strtab");
if (DynamicString.size() < 1) /* TODO: check if this is required */
DynamicString = StringTable;
Memory::Virtual vmm = Memory::Virtual(TargetProcess->PageTable);
Memory::MemMgr *mm = TargetProcess->Memory;
uint64_t BaseAddress = 0;
/* Copy segments into memory */
{
Elf64_Phdr ProgramHeader;
for (Elf64_Half i = 0; i < ELFHeader.e_phnum; i++)
{
lseek(fd, ELFHeader.e_phoff + (i * sizeof(Elf64_Phdr)), SEEK_SET);
fread(fd, (uint8_t *)&ProgramHeader, sizeof(Elf64_Phdr));
switch (ProgramHeader.p_type)
{
case PT_LOAD:
{
if (ProgramHeader.p_memsz == 0)
continue;
void *pAddr = mm->RequestPages(TO_PAGES(ProgramHeader.p_memsz), true);
void *SegmentDestination = (void *)ProgramHeader.p_vaddr;
vmm.Map(SegmentDestination, pAddr,
ProgramHeader.p_memsz,
Memory::P | Memory::RW | Memory::US);
debug("Mapped %#lx to %#lx", SegmentDestination, pAddr);
if (BaseAddress == 0)
BaseAddress = (uintptr_t)SegmentDestination;
debug("Copying segment to p: %#lx-%#lx; v: %#lx-%#lx (%ld file bytes, %ld mem bytes)",
pAddr, uintptr_t(pAddr) + ProgramHeader.p_memsz,
SegmentDestination, uintptr_t(SegmentDestination) + ProgramHeader.p_memsz,
ProgramHeader.p_filesz, ProgramHeader.p_memsz);
if (ProgramHeader.p_filesz > 0)
{
lseek(fd, ProgramHeader.p_offset, SEEK_SET);
fread(fd, (uint8_t *)pAddr, ProgramHeader.p_filesz);
}
if (ProgramHeader.p_memsz - ProgramHeader.p_filesz > 0)
{
void *zAddr = (void *)(uintptr_t(pAddr) + ProgramHeader.p_filesz);
memset(zAddr, 0, ProgramHeader.p_memsz - ProgramHeader.p_filesz);
}
break;
}
default:
{
fixme("Unhandled program header type: %#lx",
ProgramHeader.p_type);
break;
}
}
}
}
struct stat statbuf;
fstat(fd, &statbuf);
Memory::SmartHeap sh = Memory::SmartHeap(statbuf.st_size);
lseek(fd, 0, SEEK_SET);
fread(fd, sh, statbuf.st_size);
TargetProcess->ELFSymbolTable->AppendSymbols(uintptr_t(sh.GetObject()));
debug("Entry Point: %#lx", EntryPoint);
char *aux_platform = (char *)mm->RequestPages(1, true); /* TODO: 4KiB is too much for this */
strcpy(aux_platform, "x86_64");
std::string execfn = thisProcess->FileDescriptors->GetAbsolutePath(fd);
void *execfn_str = mm->RequestPages(TO_PAGES(execfn.size() + 1), true);
strcpy((char *)execfn_str, execfn.c_str());
// prep. for AT_PHDR
void *phdr_array = mm->RequestPages(TO_PAGES(ELFHeader.e_phnum * sizeof(Elf64_Phdr)), true);
lseek(fd, ELFHeader.e_phoff, SEEK_SET);
fread(fd, (uint8_t *)phdr_array, ELFHeader.e_phnum * sizeof(Elf64_Phdr));
Elfauxv.push_back({.archaux = {.a_type = AT_NULL, .a_un = {.a_val = 0}}});
Elfauxv.push_back({.archaux = {.a_type = AT_PLATFORM, .a_un = {.a_val = (uint64_t)aux_platform}}});
Elfauxv.push_back({.archaux = {.a_type = AT_EXECFN, .a_un = {.a_val = (uint64_t)execfn_str}}});
// AT_HWCAP2 26
// AT_RANDOM 25
// AT_SECURE 23
Elfauxv.push_back({.archaux = {.a_type = AT_EGID, .a_un = {.a_val = (uint64_t)0}}}); /* FIXME */
Elfauxv.push_back({.archaux = {.a_type = AT_GID, .a_un = {.a_val = (uint64_t)0}}}); /* FIXME */
Elfauxv.push_back({.archaux = {.a_type = AT_EUID, .a_un = {.a_val = (uint64_t)0}}}); /* FIXME */
Elfauxv.push_back({.archaux = {.a_type = AT_UID, .a_un = {.a_val = (uint64_t)0}}}); /* FIXME */
Elfauxv.push_back({.archaux = {.a_type = AT_ENTRY, .a_un = {.a_val = (uint64_t)EntryPoint}}});
// AT_FLAGS 8
Elfauxv.push_back({.archaux = {.a_type = AT_BASE, .a_un = {.a_val = (uint64_t)BaseAddress}}});
Elfauxv.push_back({.archaux = {.a_type = AT_PHNUM, .a_un = {.a_val = (uint64_t)ELFHeader.e_phnum}}});
Elfauxv.push_back({.archaux = {.a_type = AT_PHENT, .a_un = {.a_val = (uint64_t)ELFHeader.e_phentsize}}});
Elfauxv.push_back({.archaux = {.a_type = AT_PHDR, .a_un = {.a_val = (uint64_t)phdr_array}}});
// AT_CLKTCK 17
Elfauxv.push_back({.archaux = {.a_type = AT_PAGESZ, .a_un = {.a_val = (uint64_t)PAGE_SIZE}}});
// AT_HWCAP 16
// AT_MINSIGSTKSZ 51
// AT_SYSINFO_EHDR 33
this->ip = EntryPoint;
this->IsElfValid = true;
}
void ELFObject::LoadDyn_x86_32(int fd, PCB *TargetProcess)
{
stub;
UNUSED(fd);
UNUSED(TargetProcess);
}
void ELFObject::LoadDyn_x86_64(int fd, PCB *TargetProcess)
{
std::string InterpreterPath;
std::vector<Elf64_Phdr> PhdrINTERP = ELFGetSymbolType_x86_64(fd, PT_INTERP);
foreach (auto Interp in PhdrINTERP)
{
Memory::SmartHeap sh = Memory::SmartHeap(256);
lseek(fd, Interp.p_offset, SEEK_SET);
fread(fd, sh, 256);
InterpreterPath = sh;
int ifd = fopen(InterpreterPath.c_str(), "r");
if (ifd < 0)
{
warn("Failed to open interpreter file: %s",
InterpreterPath.c_str());
continue;
}
else
{
if (GetBinaryType(InterpreterPath.c_str()) != BinTypeELF)
{
warn("Interpreter %s is not an ELF file",
InterpreterPath.c_str());
fclose(ifd);
continue;
}
if (LoadInterpreter(ifd, TargetProcess))
{
/* ba deci de aici trb sa fac
sa se incarce interperter-ul
argv[1] ar trb sa fie locatia pt intrep */
// modific argv-ul
// TODO FIXME TODO FIXME TODO FIXME TODO FIXME TODO FIXME TODO FIXME TODO FIXME TODO FIXME
// TODO FIXME TODO FIXME TODO FIXME TODO FIXME TODO FIXME TODO FIXME TODO FIXME TODO FIXME
// TODO FIXME TODO FIXME TODO FIXME TODO FIXME TODO FIXME TODO FIXME TODO FIXME TODO FIXME
// TODO FIXME TODO FIXME TODO FIXME TODO FIXME TODO FIXME TODO FIXME TODO FIXME TODO FIXME
// TODO FIXME TODO FIXME TODO FIXME TODO FIXME TODO FIXME TODO FIXME TODO FIXME TODO FIXME
// TODO FIXME TODO FIXME TODO FIXME TODO FIXME TODO FIXME TODO FIXME TODO FIXME TODO FIXME
// TODO FIXME TODO FIXME TODO FIXME TODO FIXME TODO FIXME TODO FIXME TODO FIXME TODO FIXME
debug("Interpreter loaded successfully");
fclose(ifd);
return;
}
}
}
Elf64_Ehdr ELFHeader;
fread(fd, (uint8_t *)&ELFHeader, sizeof(Elf64_Ehdr));
uintptr_t EntryPoint = ELFHeader.e_entry;
debug("Entry point is %#lx", EntryPoint);
debug("Solving symbols");
std::vector<Elf64_Shdr> DynamicString = ELFGetSections_x86_64(fd, ".dynstr");
std::vector<Elf64_Shdr> StringTable = ELFGetSections_x86_64(fd, ".strtab");
if (DynamicString.size() < 1) /* TODO: check if this is required */
DynamicString = StringTable;
Memory::Virtual vmm = Memory::Virtual(TargetProcess->PageTable);
Memory::MemMgr *mm = TargetProcess->Memory;
uintptr_t BaseAddress = 0;
/* Copy segments into memory */
{
Elf64_Phdr ProgramHeader;
std::size_t SegmentsSize = 0;
for (Elf64_Half i = 0; i < ELFHeader.e_phnum; i++)
{
lseek(fd, ELFHeader.e_phoff + (i * sizeof(Elf64_Phdr)), SEEK_SET);
fread(fd, (uint8_t *)&ProgramHeader, sizeof(Elf64_Phdr));
if (ProgramHeader.p_type == PT_LOAD ||
ProgramHeader.p_type == PT_DYNAMIC)
SegmentsSize += ProgramHeader.p_memsz;
}
/* TODO: Check if this is correct and/or it needs more
complex calculations & allocations */
void *SegmentsAddress = mm->RequestPages(TO_PAGES(SegmentsSize) + 1, true);
BaseAddress = (uintptr_t)SegmentsAddress;
debug("BaseAddress: %#lx, End: %#lx", BaseAddress,
BaseAddress + FROM_PAGES(TO_PAGES(SegmentsSize)));
for (Elf64_Half i = 0; i < ELFHeader.e_phnum; i++)
{
lseek(fd, ELFHeader.e_phoff + (i * sizeof(Elf64_Phdr)), SEEK_SET);
fread(fd, (uint8_t *)&ProgramHeader, sizeof(Elf64_Phdr));
switch (ProgramHeader.p_type)
{
case PT_LOAD:
{
/* Because this is ET_DYN, we can load the segments
anywhere we want. */
uintptr_t SegmentDestination = BaseAddress + ProgramHeader.p_vaddr;
if (ProgramHeader.p_memsz == 0)
continue;
debug("PIC: %#lx + %#lx",
BaseAddress,
ProgramHeader.p_vaddr);
debug("Copying segment to %#lx-%#lx (%ld file bytes, %ld mem bytes)",
SegmentDestination, SegmentDestination + ProgramHeader.p_memsz,
ProgramHeader.p_filesz, ProgramHeader.p_memsz);
if (ProgramHeader.p_filesz > 0)
{
lseek(fd, ProgramHeader.p_offset, SEEK_SET);
fread(fd, (uint8_t *)SegmentDestination, ProgramHeader.p_filesz);
}
if (ProgramHeader.p_memsz - ProgramHeader.p_filesz > 0)
{
void *zAddr = (void *)(SegmentDestination + ProgramHeader.p_filesz);
memset(zAddr, 0, ProgramHeader.p_memsz - ProgramHeader.p_filesz);
}
break;
}
case PT_DYNAMIC:
{
/* PT_DYNAMIC contains the dynamic linking information for the
executable or shared library. */
uintptr_t DynamicSegmentDestination = BaseAddress + ProgramHeader.p_vaddr;
if (ProgramHeader.p_memsz == 0)
continue;
debug("Copying PT_DYNAMIC segment to %#lx-%#lx (%ld file bytes, %ld mem bytes)",
DynamicSegmentDestination, DynamicSegmentDestination + ProgramHeader.p_memsz,
ProgramHeader.p_filesz, ProgramHeader.p_memsz);
if (ProgramHeader.p_filesz > 0)
{
lseek(fd, ProgramHeader.p_offset, SEEK_SET);
fread(fd, (uint8_t *)DynamicSegmentDestination, ProgramHeader.p_filesz);
}
if (ProgramHeader.p_memsz - ProgramHeader.p_filesz > 0)
{
void *zAddr = (void *)(DynamicSegmentDestination + ProgramHeader.p_filesz);
memset(zAddr, 0, ProgramHeader.p_memsz - ProgramHeader.p_filesz);
}
break;
}
default:
{
fixme("Unhandled program header type: %#lx",
ProgramHeader.p_type);
break;
}
}
}
}
EntryPoint += BaseAddress;
debug("The new ep is %#lx", EntryPoint);
std::vector<Elf64_Dyn> JmpRel = ELFGetDynamicTag_x86_64(fd, DT_JMPREL);
std::vector<Elf64_Dyn> SymTab = ELFGetDynamicTag_x86_64(fd, DT_SYMTAB);
std::vector<Elf64_Dyn> StrTab = ELFGetDynamicTag_x86_64(fd, DT_STRTAB);
std::vector<Elf64_Dyn> RelaDyn = ELFGetDynamicTag_x86_64(fd, DT_RELA);
std::vector<Elf64_Dyn> RelaDynSize = ELFGetDynamicTag_x86_64(fd, DT_RELASZ);
std::vector<Elf64_Dyn> PltGot = ELFGetDynamicTag_x86_64(fd, DT_PLTGOT);
std::size_t JmpRelSize = JmpRel.size();
std::size_t SymTabSize = SymTab.size();
std::size_t StrTabSize = StrTab.size();
std::size_t RelaDynSize_v = RelaDyn.size();
std::size_t PltGotSize = PltGot.size();
if (JmpRelSize < 1)
debug("No DT_JMPREL");
if (SymTabSize < 1)
debug("No DT_SYMTAB");
if (StrTabSize < 1)
debug("No DT_STRTAB");
if (RelaDynSize_v < 1)
debug("No DT_RELA");
if (RelaDynSize[0].d_un.d_val < 1)
debug("DT_RELASZ is < 1");
if (PltGotSize < 1)
debug("No DT_PLTGOT");
if (JmpRelSize > 0 && SymTabSize > 0 && StrTabSize > 0)
{
debug("JmpRel: %#lx, SymTab: %#lx, StrTab: %#lx",
JmpRel[0].d_un.d_ptr, SymTab[0].d_un.d_ptr, StrTab[0].d_un.d_ptr);
Elf64_Rela *_JmpRel = (Elf64_Rela *)((uintptr_t)BaseAddress + JmpRel[0].d_un.d_ptr);
Elf64_Sym *_SymTab = (Elf64_Sym *)((uintptr_t)BaseAddress + SymTab[0].d_un.d_ptr);
char *_DynStr = (char *)((uintptr_t)BaseAddress + StrTab[0].d_un.d_ptr);
Elf64_Rela *_RelaDyn = (Elf64_Rela *)((uintptr_t)BaseAddress + RelaDyn[0].d_un.d_ptr);
Elf64_Shdr *gotSection = nullptr;
Elf64_Shdr shdr;
for (Elf64_Half i = 0; i < ELFHeader.e_shnum; i++)
{
lseek(fd, ELFHeader.e_shoff + i * sizeof(Elf64_Shdr), SEEK_SET);
fread(fd, (uint8_t *)&shdr, sizeof(Elf64_Shdr));
if (shdr.sh_type == SHT_PROGBITS &&
(shdr.sh_flags & SHF_WRITE) &&
(shdr.sh_flags & SHF_ALLOC))
{
gotSection = new Elf64_Shdr;
*gotSection = shdr;
debug("Found GOT section");
break;
}
}
if (gotSection)
{
// .rela.plt
// R_X86_64_JUMP_SLOT
Elf64_Xword numEntries = gotSection->sh_size / sizeof(Elf64_Addr);
for (Elf64_Xword i = 0; i < numEntries; i++)
{
Elf64_Addr *GOTEntry = (Elf64_Addr *)(gotSection->sh_addr + BaseAddress + i * sizeof(Elf64_Addr));
Elf64_Addr GOTEntryValue = *GOTEntry;
if (GOTEntryValue == 0)
continue;
Elf64_Rela *Rel = _JmpRel + i;
Elf64_Xword RelType = ELF64_R_TYPE(Rel->r_info);
switch (RelType)
{
case R_X86_64_JUMP_SLOT:
{
Elf64_Xword SymIndex = ELF64_R_SYM(Rel->r_info);
Elf64_Sym *Sym = _SymTab + SymIndex;
if (Sym->st_name)
{
char *SymName = _DynStr + Sym->st_name;
debug("SymName: %s", SymName);
Elf64_Sym LibSym = ELFLookupSymbol(fd, SymName);
if (LibSym.st_value)
{
*GOTEntry = (Elf64_Addr)(BaseAddress + LibSym.st_value);
debug("GOT[%ld](%#lx): %#lx",
i, uintptr_t(GOTEntry) - BaseAddress,
*GOTEntry);
}
}
continue;
}
default:
{
fixme("Unhandled relocation type: %#lx", RelType);
break;
}
}
}
// .rela.dyn
// R_X86_64_RELATIVE
// R_X86_64_GLOB_DAT
if (RelaDynSize_v > 0 && RelaDynSize[0].d_un.d_val > 0)
{
Elf64_Xword numRelaDynEntries = RelaDynSize[0].d_un.d_val / sizeof(Elf64_Rela);
for (Elf64_Xword i = 0; i < numRelaDynEntries; i++)
{
Elf64_Rela *Rel = _RelaDyn + i;
Elf64_Addr *GOTEntry = (Elf64_Addr *)(Rel->r_offset + BaseAddress);
Elf64_Xword RelType = ELF64_R_TYPE(Rel->r_info);
switch (RelType)
{
case R_X86_64_RELATIVE:
{
*GOTEntry = (Elf64_Addr)(BaseAddress + Rel->r_addend);
debug("GOT[%ld](%#lx): %#lx (R_X86_64_RELATIVE)",
i, uintptr_t(GOTEntry) - BaseAddress,
*GOTEntry);
break;
}
case R_X86_64_GLOB_DAT:
{
Elf64_Xword SymIndex = ELF64_R_SYM(Rel->r_info);
Elf64_Sym *Sym = _SymTab + SymIndex;
if (Sym->st_name)
{
char *SymName = _DynStr + Sym->st_name;
debug("SymName: %s", SymName);
Elf64_Sym LibSym = ELFLookupSymbol(fd, SymName);
if (LibSym.st_value)
{
*GOTEntry = (Elf64_Addr)(BaseAddress + LibSym.st_value);
debug("GOT[%ld](%#lx): %#lx (R_X86_64_GLOB_DAT)",
i, uintptr_t(GOTEntry) - BaseAddress,
*GOTEntry);
}
}
break;
}
default:
{
fixme("Unhandled relocation type: %#lx", RelType);
break;
}
}
}
}
// _GLOBAL_OFFSET_TABLE_
if (PltGotSize > 0)
{
Elf64_Dyn got = PltGot[0];
Elf64_Addr *GOTEntry = (Elf64_Addr *)(got.d_un.d_ptr + BaseAddress);
// *GOTEntry = (Elf64_Addr)(BaseAddress + PltGot[0].d_un.d_val);
std::vector<Elf64_Phdr> DYNAMICPhdrs = ELFGetSymbolType_x86_64(fd, PT_DYNAMIC);
if (DYNAMICPhdrs.size() > 0)
*GOTEntry = (Elf64_Addr)(BaseAddress + DYNAMICPhdrs[0].p_vaddr);
}
delete gotSection;
}
else
{
debug("GOT section not found");
}
}
/* ------------------------------------------------------------------------ */
struct stat statbuf;
fstat(fd, &statbuf);
Memory::SmartHeap sh = Memory::SmartHeap(statbuf.st_size);
lseek(fd, 0, SEEK_SET);
fread(fd, sh, statbuf.st_size);
TargetProcess->ELFSymbolTable->AppendSymbols(uintptr_t(sh.GetObject()), BaseAddress);
debug("Entry Point: %#lx", EntryPoint);
char *aux_platform = (char *)mm->RequestPages(1, true); /* TODO: 4KiB is too much for this */
strcpy(aux_platform, "x86_64");
std::string execfn = thisProcess->FileDescriptors->GetAbsolutePath(fd);
void *execfn_str = mm->RequestPages(TO_PAGES(execfn.size() + 1), true);
strcpy((char *)execfn_str, execfn.c_str());
// prep. for AT_PHDR
void *phdr_array = mm->RequestPages(TO_PAGES(ELFHeader.e_phnum * sizeof(Elf64_Phdr)), true);
lseek(fd, ELFHeader.e_phoff, SEEK_SET);
fread(fd, (uint8_t *)phdr_array, ELFHeader.e_phnum * sizeof(Elf64_Phdr));
Elfauxv.push_back({.archaux = {.a_type = AT_NULL, .a_un = {.a_val = 0}}});
Elfauxv.push_back({.archaux = {.a_type = AT_PLATFORM, .a_un = {.a_val = (uint64_t)aux_platform}}});
Elfauxv.push_back({.archaux = {.a_type = AT_EXECFN, .a_un = {.a_val = (uint64_t)execfn_str}}});
// AT_HWCAP2 26
// AT_RANDOM 25
// AT_SECURE 23
Elfauxv.push_back({.archaux = {.a_type = AT_EGID, .a_un = {.a_val = (uint64_t)0}}}); /* FIXME */
Elfauxv.push_back({.archaux = {.a_type = AT_GID, .a_un = {.a_val = (uint64_t)0}}}); /* FIXME */
Elfauxv.push_back({.archaux = {.a_type = AT_EUID, .a_un = {.a_val = (uint64_t)0}}}); /* FIXME */
Elfauxv.push_back({.archaux = {.a_type = AT_UID, .a_un = {.a_val = (uint64_t)0}}}); /* FIXME */
Elfauxv.push_back({.archaux = {.a_type = AT_ENTRY, .a_un = {.a_val = (uint64_t)EntryPoint}}});
// AT_FLAGS 8
Elfauxv.push_back({.archaux = {.a_type = AT_BASE, .a_un = {.a_val = (uint64_t)BaseAddress}}});
Elfauxv.push_back({.archaux = {.a_type = AT_PHNUM, .a_un = {.a_val = (uint64_t)ELFHeader.e_phnum}}});
Elfauxv.push_back({.archaux = {.a_type = AT_PHENT, .a_un = {.a_val = (uint64_t)ELFHeader.e_phentsize}}});
Elfauxv.push_back({.archaux = {.a_type = AT_PHDR, .a_un = {.a_val = (uint64_t)phdr_array}}});
// AT_CLKTCK 17
Elfauxv.push_back({.archaux = {.a_type = AT_PAGESZ, .a_un = {.a_val = (uint64_t)PAGE_SIZE}}});
// AT_HWCAP 16
// AT_MINSIGSTKSZ 51
// AT_SYSINFO_EHDR 33
this->ip = EntryPoint;
this->IsElfValid = true;
}
bool ELFObject::LoadInterpreter(int fd, PCB *TargetProcess)
{
Elf32_Ehdr ELFHeader;
fread(fd, &ELFHeader, sizeof(Elf32_Ehdr));
switch (ELFHeader.e_type)
{
case ET_REL:
{
fixme("ET_REL not implemented");
break;
}
case ET_EXEC:
{
switch (ELFHeader.e_machine)
{
case EM_386:
this->LoadExec_x86_32(fd, TargetProcess);
return true;
case EM_X86_64:
this->LoadExec_x86_64(fd, TargetProcess);
return true;
case EM_ARM:
error("ARM is not supported yet!");
break;
case EM_AARCH64:
error("ARM64 is not supported yet!");
break;
default:
error("Unknown architecture: %d", ELFHeader.e_machine);
break;
}
break;
}
case ET_DYN:
{
switch (ELFHeader.e_machine)
{
case EM_386:
this->LoadDyn_x86_32(fd, TargetProcess);
return true;
case EM_X86_64:
this->LoadDyn_x86_64(fd, TargetProcess);
return true;
case EM_ARM:
error("ARM is not supported yet!");
break;
case EM_AARCH64:
error("ARM64 is not supported yet!");
break;
default:
error("Unknown architecture: %d", ELFHeader.e_machine);
break;
}
break;
}
case ET_CORE:
{
fixme("ET_CORE not implemented");
break;
}
case ET_NONE:
default:
{
error("Unknown ELF Type: %d", ELFHeader.e_type);
break;
}
}
return false;
}
ELFObject::ELFObject(char *AbsolutePath,
PCB *TargetProcess,
const char **argv,
const char **envp)
{
if (GetBinaryType(AbsolutePath) != BinaryType::BinTypeELF)
{
error("%s is not an ELF file or is invalid.", AbsolutePath);
return;
}
int fd = fopen(AbsolutePath, "r");
if (fd < 0)
{
error("Failed to open %s, errno: %d", AbsolutePath, fd);
return;
}
int argc = 0;
int envc = 0;
while (argv[argc] != nullptr)
argc++;
while (envp[envc] != nullptr)
envc++;
// ELFargv = new const char *[argc + 2];
std::size_t argv_size = TO_PAGES(argc + 2 * sizeof(char *));
ELFargv = (const char **)TargetProcess->Memory->RequestPages(argv_size);
for (int i = 0; i < argc; i++)
ELFargv[i] = argv[i];
ELFargv[argc] = nullptr;
// ELFenvp = new const char *[envc + 1];
std::size_t envp_size = TO_PAGES(envc + 1 * sizeof(char *));
ELFenvp = (const char **)TargetProcess->Memory->RequestPages(envp_size);
for (int i = 0; i < envc; i++)
ELFenvp[i] = envp[i];
ELFenvp[envc] = nullptr;
Elf32_Ehdr ELFHeader;
fread(fd, &ELFHeader, sizeof(Elf32_Ehdr));
switch (ELFHeader.e_type)
{
case ET_REL:
{
fixme("ET_REL not implemented");
break;
}
case ET_EXEC:
{
switch (ELFHeader.e_machine)
{
case EM_386:
this->LoadExec_x86_32(fd, TargetProcess);
break;
case EM_X86_64:
this->LoadExec_x86_64(fd, TargetProcess);
break;
case EM_ARM:
error("ARM is not supported yet!");
break;
case EM_AARCH64:
error("ARM64 is not supported yet!");
break;
default:
error("Unknown architecture: %d", ELFHeader.e_machine);
break;
}
break;
}
case ET_DYN:
{
switch (ELFHeader.e_machine)
{
case EM_386:
this->LoadDyn_x86_32(fd, TargetProcess);
break;
case EM_X86_64:
this->LoadDyn_x86_64(fd, TargetProcess);
break;
case EM_ARM:
error("ARM is not supported yet!");
break;
case EM_AARCH64:
error("ARM64 is not supported yet!");
break;
default:
error("Unknown architecture: %d", ELFHeader.e_machine);
break;
}
break;
}
case ET_CORE:
{
fixme("ET_CORE not implemented");
break;
}
case ET_NONE:
default:
{
error("Unknown ELF Type: %d", ELFHeader.e_type);
break;
}
}
fclose(fd);
}
ELFObject::~ELFObject()
{
}
}

View File

@ -0,0 +1,203 @@
/*
This file is part of Fennix Kernel.
Fennix Kernel is free software: you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation, either version 3 of
the License, or (at your option) any later version.
Fennix Kernel is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
*/
#include <exec.hpp>
#include <msexec.h>
#include "../../kernel.h"
#include "../../Fex.hpp"
namespace Execute
{
bool ELFIs64(void *Header)
{
Elf32_Ehdr *ELFHeader = (Elf32_Ehdr *)Header;
if (ELFHeader->e_ident[EI_CLASS] == ELFCLASS64)
return true;
return false;
}
/* Originally from https://wiki.osdev.org/ELF_Tutorial */
Elf64_Shdr *GetELFSheader(Elf64_Ehdr *Header)
{
return (Elf64_Shdr *)((uintptr_t)Header + Header->e_shoff);
}
Elf64_Shdr *GetELFSection(Elf64_Ehdr *Header, uint64_t Index)
{
return &GetELFSheader(Header)[Index];
}
char *GetELFStringTable(Elf64_Ehdr *Header)
{
if (Header->e_shstrndx == SHN_UNDEF)
return nullptr;
return (char *)Header + GetELFSection(Header, Header->e_shstrndx)->sh_offset;
}
char *ELFLookupString(Elf64_Ehdr *Header, uintptr_t Offset)
{
char *StringTable = GetELFStringTable(Header);
if (StringTable == nullptr)
return nullptr;
return StringTable + Offset;
}
Elf64_Sym *ELFLookupSymbol(Elf64_Ehdr *Header, const char *Name)
{
Elf64_Shdr *SymbolTable = nullptr;
Elf64_Shdr *StringTable = nullptr;
for (Elf64_Half i = 0; i < Header->e_shnum; i++)
{
Elf64_Shdr *shdr = GetELFSection(Header, i);
switch (shdr->sh_type)
{
case SHT_SYMTAB:
SymbolTable = shdr;
StringTable = GetELFSection(Header, shdr->sh_link);
break;
default:
{
break;
}
}
}
if (SymbolTable == nullptr || StringTable == nullptr)
return nullptr;
for (size_t i = 0; i < (SymbolTable->sh_size / sizeof(Elf64_Sym)); i++)
{
Elf64_Sym *Symbol = (Elf64_Sym *)((uintptr_t)Header + SymbolTable->sh_offset + (i * sizeof(Elf64_Sym)));
char *String = (char *)((uintptr_t)Header + StringTable->sh_offset + Symbol->st_name);
if (strcmp(String, Name) == 0)
return Symbol;
}
return nullptr;
}
Elf64_Sym ELFLookupSymbol(int fd, const char *Name)
{
off_t OldOffset = lseek(fd, 0, SEEK_CUR);
Elf64_Ehdr Header;
lseek(fd, 0, SEEK_SET);
fread(fd, (uint8_t *)&Header, sizeof(Elf64_Ehdr));
Elf64_Shdr SymbolTable;
Elf64_Shdr StringTable;
for (Elf64_Half i = 0; i < Header.e_shnum; i++)
{
Elf64_Shdr shdr;
lseek(fd, Header.e_shoff + (i * sizeof(Elf64_Shdr)), SEEK_SET);
fread(fd, (uint8_t *)&shdr, sizeof(Elf64_Shdr));
switch (shdr.sh_type)
{
case SHT_SYMTAB:
SymbolTable = shdr;
lseek(fd, Header.e_shoff + (shdr.sh_link * sizeof(Elf64_Shdr)), SEEK_SET);
fread(fd, (uint8_t *)&StringTable, sizeof(Elf64_Shdr));
break;
default:
{
break;
}
}
}
if (SymbolTable.sh_name == 0 ||
StringTable.sh_name == 0)
{
error("Symbol table not found.");
lseek(fd, OldOffset, SEEK_SET);
return {};
}
for (size_t i = 0; i < (SymbolTable.sh_size / sizeof(Elf64_Sym)); i++)
{
// Elf64_Sym *Symbol = (Elf64_Sym *)((uintptr_t)Header + SymbolTable->sh_offset + (i * sizeof(Elf64_Sym)));
Elf64_Sym Symbol;
lseek(fd, SymbolTable.sh_offset + (i * sizeof(Elf64_Sym)), SEEK_SET);
fread(fd, (uint8_t *)&Symbol, sizeof(Elf64_Sym));
// char *String = (char *)((uintptr_t)Header + StringTable->sh_offset + Symbol->st_name);
char String[256];
lseek(fd, StringTable.sh_offset + Symbol.st_name, SEEK_SET);
fread(fd, (uint8_t *)&String, 256);
if (strcmp(String, Name) == 0)
{
lseek(fd, OldOffset, SEEK_SET);
return Symbol;
}
}
error("Symbol not found.");
lseek(fd, OldOffset, SEEK_SET);
return {};
}
uintptr_t ELFGetSymbolValue(Elf64_Ehdr *Header, uint64_t Table, uint64_t Index)
{
#if defined(a64)
if (Table == SHN_UNDEF || Index == SHN_UNDEF)
return 0;
Elf64_Shdr *SymbolTable = GetELFSection(Header, Table);
uint64_t STEntries = SymbolTable->sh_size / SymbolTable->sh_entsize;
if (Index >= STEntries)
{
error("Symbol index out of range %d-%u.", Table, Index);
return 0xdead;
}
uint64_t SymbolAddress = (uint64_t)Header + SymbolTable->sh_offset;
Elf64_Sym *Symbol = &((Elf64_Sym *)SymbolAddress)[Index];
if (Symbol->st_shndx == SHN_UNDEF)
{
Elf64_Shdr *StringTable = GetELFSection(Header, SymbolTable->sh_link);
const char *Name = (const char *)Header + StringTable->sh_offset + Symbol->st_name;
void *Target = (void *)ELFLookupSymbol(Header, Name)->st_value;
if (Target == nullptr)
{
if (ELF64_ST_BIND(Symbol->st_info) & STB_WEAK)
return 0;
else
{
error("Undefined external symbol \"%s\".", Name);
return 0xdead;
}
}
else
return (uintptr_t)Target;
}
else if (Symbol->st_shndx == SHN_ABS)
return Symbol->st_value;
else
{
Elf64_Shdr *Target = GetELFSection(Header, Symbol->st_shndx);
return (uintptr_t)Header + Symbol->st_value + Target->sh_offset;
}
#endif
}
}

View File

@ -26,7 +26,7 @@ namespace Execute
{
/* Originally from https://wiki.osdev.org/ELF_Tutorial */
ELFBaseLoad ELFLoadRel(void *BaseImage,
void ELFLoadRel(void *BaseImage,
const char *Name,
Tasking::PCB *Process)
{
@ -35,11 +35,6 @@ namespace Execute
debug("Relocatable");
/* TODO: I have to fully implement this, but for now I will leave it as it is now. */
warn("Relocatable ELF is not fully supported yet");
/* This should be deleted after with kfree */
ELFBaseLoad ELFBase = {};
/* This should be deleted inside BaseLoad.cpp */
ELFBase.TmpMem = new Memory::MemMgr(Process->PageTable);
Elf64_Shdr *shdr = GetELFSheader(((Elf64_Ehdr *)BaseImage));
for (Elf64_Half i = 0; i < ((Elf64_Ehdr *)BaseImage)->e_shnum; i++)
{
@ -78,10 +73,7 @@ namespace Execute
{
SymbolValue = ELFGetSymbolValue(((Elf64_Ehdr *)BaseImage), Section->sh_link, ELF64_R_SYM(RelTable->r_info));
if (SymbolValue == 0xdead)
{
delete ELFBase.TmpMem, ELFBase.TmpMem = nullptr;
return {};
}
return;
}
switch (ELF64_R_TYPE(RelTable->r_info))
@ -97,17 +89,14 @@ namespace Execute
default:
{
error("Unsupported relocation type: %d", ELF64_R_TYPE(RelTable->r_info));
delete ELFBase.TmpMem, ELFBase.TmpMem = nullptr;
return {};
return;
}
}
debug("Symbol value: %#lx", SymbolValue);
}
}
}
return ELFBase;
#elif defined(a32)
return {};
#endif
}
}

View File

@ -21,17 +21,18 @@
namespace Execute
{
std::vector<Elf64_Dyn> ELFGetDynamicTag_x86_64(VirtualFileSystem::File &ElfFile,
std::vector<Elf64_Dyn> ELFGetDynamicTag_x86_64(int fd,
DynamicArrayTags Tag)
{
off_t OldOffset = vfs->Seek(ElfFile, 0, SEEK_CUR);
#if defined(a64) || defined(aa64)
off_t OldOffset = lseek(fd, 0, SEEK_CUR);
std::vector<Elf64_Dyn> Ret;
Elf64_Ehdr ELFHeader;
vfs->Seek(ElfFile, 0, SEEK_SET);
vfs->Read(ElfFile, (uint8_t *)&ELFHeader, sizeof(Elf64_Ehdr));
lseek(fd, 0, SEEK_SET);
fread(fd, (uint8_t *)&ELFHeader, sizeof(Elf64_Ehdr));
std::vector<Elf64_Phdr> DYNAMICPhdrs = ELFGetSymbolType_x86_64(ElfFile, PT_DYNAMIC);
std::vector<Elf64_Phdr> DYNAMICPhdrs = ELFGetSymbolType_x86_64(fd, PT_DYNAMIC);
if (DYNAMICPhdrs.size() < 1)
{
@ -44,19 +45,22 @@ namespace Execute
Elf64_Dyn Dynamic;
for (size_t i = 0; i < Phdr.p_filesz / sizeof(Elf64_Dyn); i++)
{
vfs->Seek(ElfFile, Phdr.p_offset + (i * sizeof(Elf64_Dyn)), SEEK_SET);
vfs->Read(ElfFile, (uint8_t *)&Dynamic, sizeof(Elf64_Dyn));
lseek(fd, Phdr.p_offset + (i * sizeof(Elf64_Dyn)), SEEK_SET);
fread(fd, (uint8_t *)&Dynamic, sizeof(Elf64_Dyn));
if (Dynamic.d_tag != Tag)
continue;
debug("Found dynamic tag %d at %#lx [d_val: %#lx].",
debug("Found dynamic tag %d at %#lx [d_val: %#lx]",
Tag, &Dynamic, Dynamic.d_un.d_val);
Ret.push_back(Dynamic);
}
}
vfs->Seek(ElfFile, OldOffset, SEEK_SET);
lseek(fd, OldOffset, SEEK_SET);
return Ret;
#elif defined(a32)
return {};
#endif
}
}

View File

@ -21,23 +21,24 @@
namespace Execute
{
std::vector<Elf64_Shdr> ELFGetSections_x86_64(VirtualFileSystem::File &ElfFile,
std::vector<Elf64_Shdr> ELFGetSections_x86_64(int fd,
const char *SectionName)
{
off_t OldOffset = vfs->Seek(ElfFile, 0, SEEK_CUR);
#if defined(a64) || defined(aa64)
off_t OldOffset = lseek(fd, 0, SEEK_CUR);
std::vector<Elf64_Shdr> Ret;
Elf64_Ehdr ELFHeader;
vfs->Seek(ElfFile, 0, SEEK_SET);
vfs->Read(ElfFile, (uint8_t *)&ELFHeader, sizeof(Elf64_Ehdr));
lseek(fd, 0, SEEK_SET);
fread(fd, (uint8_t *)&ELFHeader, sizeof(Elf64_Ehdr));
Elf64_Shdr *SectionHeaders = new Elf64_Shdr[ELFHeader.e_shnum];
vfs->Seek(ElfFile, ELFHeader.e_shoff, SEEK_SET);
vfs->Read(ElfFile, (uint8_t *)SectionHeaders, sizeof(Elf64_Shdr) * ELFHeader.e_shnum);
lseek(fd, ELFHeader.e_shoff, SEEK_SET);
fread(fd, (uint8_t *)SectionHeaders, sizeof(Elf64_Shdr) * ELFHeader.e_shnum);
char *SectionNames = new char[SectionHeaders[ELFHeader.e_shstrndx].sh_size];
vfs->Seek(ElfFile, SectionHeaders[ELFHeader.e_shstrndx].sh_offset, SEEK_SET);
vfs->Read(ElfFile, (uint8_t *)SectionNames, SectionHeaders[ELFHeader.e_shstrndx].sh_size);
lseek(fd, SectionHeaders[ELFHeader.e_shstrndx].sh_offset, SEEK_SET);
fread(fd, (uint8_t *)SectionNames, SectionHeaders[ELFHeader.e_shstrndx].sh_size);
for (Elf64_Half i = 0; i < ELFHeader.e_shnum; ++i)
{
@ -46,9 +47,12 @@ namespace Execute
Ret.push_back(SectionHeaders[i]);
}
vfs->Seek(ElfFile, OldOffset, SEEK_SET);
lseek(fd, OldOffset, SEEK_SET);
delete[] SectionHeaders;
delete[] SectionNames;
return Ret;
#elif defined(a32)
return {};
#endif
}
}

View File

@ -21,30 +21,34 @@
namespace Execute
{
std::vector<Elf64_Phdr> ELFGetSymbolType_x86_64(VirtualFileSystem::File &ElfFile,
std::vector<Elf64_Phdr> ELFGetSymbolType_x86_64(int fd,
SegmentTypes Tag)
{
off_t OldOffset = vfs->Seek(ElfFile, 0, SEEK_CUR);
#if defined(a64) || defined(aa64)
off_t OldOffset = lseek(fd, 0, SEEK_CUR);
std::vector<Elf64_Phdr> Ret;
Elf64_Ehdr ELFHeader;
vfs->Seek(ElfFile, 0, SEEK_SET);
vfs->Read(ElfFile, (uint8_t *)&ELFHeader, sizeof(Elf64_Ehdr));
lseek(fd, 0, SEEK_SET);
fread(fd, (uint8_t *)&ELFHeader, sizeof(Elf64_Ehdr));
Elf64_Phdr ProgramHeaders;
vfs->Seek(ElfFile, ELFHeader.e_phoff, SEEK_SET);
vfs->Read(ElfFile, (uint8_t *)&ProgramHeaders, sizeof(Elf64_Phdr));
lseek(fd, ELFHeader.e_phoff, SEEK_SET);
fread(fd, (uint8_t *)&ProgramHeaders, sizeof(Elf64_Phdr));
for (Elf64_Half i = 0; i < ELFHeader.e_phnum; i++)
{
if (ProgramHeaders.p_type == Tag)
Ret.push_back(ProgramHeaders);
vfs->Seek(ElfFile, sizeof(Elf64_Phdr), SEEK_CUR);
vfs->Read(ElfFile, (uint8_t *)&ProgramHeaders, sizeof(Elf64_Phdr));
lseek(fd, sizeof(Elf64_Phdr), SEEK_CUR);
fread(fd, (uint8_t *)&ProgramHeaders, sizeof(Elf64_Phdr));
}
vfs->Seek(ElfFile, OldOffset, SEEK_SET);
lseek(fd, OldOffset, SEEK_SET);
return Ret;
#elif defined(a32)
return {};
#endif
}
}

161
ExecutionLayer/Spawn.cpp Normal file
View File

@ -0,0 +1,161 @@
/*
This file is part of Fennix Kernel.
Fennix Kernel is free software: you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation, either version 3 of
the License, or (at your option) any later version.
Fennix Kernel is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
*/
#include <exec.hpp>
#include <memory.hpp>
#include <lock.hpp>
#include <msexec.h>
#include <cwalk.h>
#include <elf.h>
#include <abi.h>
#include "../kernel.h"
#include "../Fex.hpp"
using namespace Tasking;
namespace Execute
{
int Spawn(char *Path, const char **argv, const char **envp,
Tasking::PCB *Parent,
Tasking::TaskCompatibility Compatibility)
{
int fd = fopen(Path, "r");
if (fd < 0)
return fd;
struct stat statbuf;
fstat(fd, &statbuf);
if (!S_ISREG(statbuf.st_mode))
{
fclose(fd);
return -EISDIR;
}
switch (GetBinaryType(Path))
{
case BinaryType::BinTypeFex:
{
Fex FexHdr;
fread(fd, (uint8_t *)&FexHdr, sizeof(Fex));
if (FexHdr.Type == FexFormatType::FexFormatType_Executable)
{
stub;
assert(false);
}
fclose(fd);
return -ENOEXEC;
}
case BinaryType::BinTypeELF:
{
TaskArchitecture Arch = TaskArchitecture::UnknownArchitecture;
const char *BaseName;
cwk_path_get_basename(Path, &BaseName, nullptr);
Elf32_Ehdr ELFHeader;
fread(fd, (uint8_t *)&ELFHeader, sizeof(Elf32_Ehdr));
switch (ELFHeader.e_machine)
{
case EM_386:
Arch = TaskArchitecture::x32;
break;
case EM_X86_64:
Arch = TaskArchitecture::x64;
break;
case EM_ARM:
Arch = TaskArchitecture::ARM32;
break;
case EM_AARCH64:
Arch = TaskArchitecture::ARM64;
break;
default:
error("Unknown ELF architecture %d",
ELFHeader.e_machine);
break;
}
// TODO: This shouldn't be ignored
if (ELFHeader.e_ident[EI_CLASS] == ELFCLASS32)
fixme("32-bit ELF");
else if (ELFHeader.e_ident[EI_CLASS] == ELFCLASS64)
fixme("64-bit ELF");
else
fixme("Unknown class %d", ELFHeader.e_ident[EI_CLASS]);
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
if (ELFHeader.e_ident[EI_DATA] != ELFDATA2LSB)
{
fixme("ELF32 LSB expected, got %d", ELFHeader.e_ident[EI_DATA]);
}
#else
if (ELFHeader.e_ident[EI_DATA] != ELFDATA2MSB)
{
fixme("ELF32 MSB expected, got %d", ELFHeader.e_ident[EI_DATA]);
}
#endif
/* ------------------------------------------------------------------------------------------------------------------------------ */
void *ElfFile = KernelAllocator.RequestPages(TO_PAGES(statbuf.st_size + 1));
fread(fd, (uint8_t *)ElfFile, statbuf.st_size);
debug("Loaded elf %s at %#lx with the length of %ld",
Path, ElfFile, statbuf.st_size);
PCB *Process = TaskManager->CreateProcess(thisProcess,
BaseName,
TaskExecutionMode::User,
ElfFile, false,
0, 0);
KernelAllocator.FreePages(ElfFile, TO_PAGES(statbuf.st_size + 1));
Process->SetWorkingDirectory(vfs->GetNodeFromPath(Path)->Parent);
Process->Info.Compatibility = TaskCompatibility::Native;
Process->Info.Architecture = TaskArchitecture::x64;
ELFObject *obj = new ELFObject(Path, Process, argv, envp);
if (!obj->IsValid)
{
error("Failed to load ELF object");
fclose(fd);
delete Process;
return -ENOEXEC;
}
TCB *Thread = TaskManager->CreateThread(Process,
obj->InstructionPointer,
obj->argv, obj->envp, obj->auxv,
Arch,
Compatibility);
fclose(fd);
return Thread->ID;
}
default:
{
debug("Unknown binary type: %d",
GetBinaryType(Path));
fclose(fd);
return -ENOEXEC;
}
}
fclose(fd);
return -ENOEXEC;
}
}

View File

@ -29,13 +29,13 @@ namespace VirtualFileSystem
if (!Size)
Size = node->Length;
if ((size_t)node->Offset > node->Length)
if (RefOffset > node->Length)
return 0;
if (node->Offset + Size > node->Length)
Size = node->Length - node->Offset;
if (RefOffset + (off_t)Size > node->Length)
Size = node->Length - RefOffset;
memcpy(Buffer, (uint8_t *)(node->Address + node->Offset), Size);
memcpy(Buffer, (uint8_t *)(node->Address + RefOffset), Size);
return Size;
}
@ -113,7 +113,7 @@ namespace VirtualFileSystem
}
else
{
trace("%s %dKB Type:%c", header->name, TO_KB(size), header->typeflag[0]);
debug("%s %d KiB, Type:%c", header->name, TO_KiB(size), header->typeflag[0]);
node->Mode = string2int(header->mode);
node->Address = (Address + 512);
node->Length = size;
@ -128,6 +128,8 @@ namespace VirtualFileSystem
break;
case SYMLINK:
node->Flags = NodeFlags::SYMLINK;
node->Symlink = new char[strlen(header->link) + 1];
strncpy((char *)node->Symlink, header->link, strlen(header->link));
break;
case DIRECTORY:
node->Flags = NodeFlags::DIRECTORY;

View File

@ -0,0 +1,434 @@
/*
This file is part of Fennix Kernel.
Fennix Kernel is free software: you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation, either version 3 of
the License, or (at your option) any later version.
Fennix Kernel is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
*/
#include <filesystem.hpp>
#include <smart_ptr.hpp>
#include <convert.h>
#include <task.hpp>
#include <printf.h>
#include <lock.hpp>
#include <cwalk.h>
#include "../kernel.h"
namespace VirtualFileSystem
{
ReadFSFunction(fd_Read)
{
if (!Size)
Size = node->Length;
if (RefOffset > node->Length)
return 0;
if (RefOffset + (off_t)Size > node->Length)
Size = node->Length - RefOffset;
memcpy(Buffer, (uint8_t *)(node->Address + RefOffset), Size);
return Size;
}
WriteFSFunction(fd_Write)
{
if (!Size)
Size = node->Length;
if (RefOffset > node->Length)
return 0;
if (RefOffset + (off_t)Size > node->Length)
Size = node->Length - RefOffset;
memcpy((uint8_t *)(node->Address + RefOffset), Buffer, Size);
return Size;
}
VirtualFileSystem::FileSystemOperations fd_op = {
.Name = "fd",
// .Read = fd_Read,
// .Write = fd_Write,
};
FileDescriptorTable::FileDescriptor
FileDescriptorTable::GetFileDescriptor(int FileDescriptor)
{
foreach (auto fd in FileDescriptors)
{
if (fd.Descriptor == FileDescriptor)
return fd;
}
return {.Descriptor = -1};
}
int FileDescriptorTable::ProbeMode(mode_t Mode, int Flags)
{
if (Flags & O_RDONLY)
{
if (!(Mode & S_IRUSR))
return -EACCES;
}
if (Flags & O_WRONLY)
{
if (!(Mode & S_IWUSR))
return -EACCES;
}
if (Flags & O_RDWR)
{
if (!(Mode & S_IRUSR) ||
!(Mode & S_IWUSR))
return -EACCES;
}
return 0;
}
int FileDescriptorTable::AddFileDescriptor(const char *AbsolutePath,
mode_t Mode, int Flags)
{
Tasking::PCB *pcb = thisProcess;
if (ProbeMode(Mode, Flags) < 0)
{
errno = EACCES;
return -1;
}
if (Flags & O_CREAT)
{
Node *n = vfs->Create(AbsolutePath,
NodeFlags::FILE,
pcb->CurrentWorkingDirectory);
if (!n)
{
error("Failed to create file %s: %d",
AbsolutePath, errno);
return -1;
}
}
if (Flags & O_EXCL)
{
RefNode *File = vfs->Open(AbsolutePath,
pcb->CurrentWorkingDirectory);
if (!File)
{
errno = EEXIST;
return -1;
}
}
if (Flags & O_TRUNC)
{
fixme("Implement O_TRUNC");
}
if (Flags & O_APPEND)
{
fixme("Implement O_APPEND");
}
if (Flags & O_CLOEXEC)
{
fixme("Implement O_CLOEXEC");
}
RefNode *File = vfs->Open(AbsolutePath,
pcb->CurrentWorkingDirectory);
if (!File)
{
error("Failed to open file %s: %d",
AbsolutePath, errno);
return -1;
}
FileDescriptorTable::FileDescriptor fd;
fd.Descriptor = GetFreeFileDescriptor();
if (fd.Descriptor < 0)
{
errno = EMFILE;
return -1;
}
fd.Mode = Mode;
fd.Flags = Flags;
fd.Handle = File;
FileDescriptors.push_back(fd);
char FileName[64];
sprintf(FileName, "%d", fd.Descriptor);
VirtualFileSystem::Node *n = vfs->Create(FileName, VirtualFileSystem::NodeFlags::FILE, this->fdDir);
if (n)
{
/* FIXME: Implement proper file descriptors */
n->Address = (uintptr_t)0xdeadbeef;
n->Length = File->FileSize;
n->Operator = &fd_op;
}
return fd.Descriptor;
}
int FileDescriptorTable::RemoveFileDescriptor(int FileDescriptor)
{
forItr(itr, FileDescriptors)
{
if (itr->Descriptor == FileDescriptor)
{
FileDescriptors.erase(itr);
char FileName[64];
sprintf(FileName, "%d", FileDescriptor);
vfs->Delete(FileName, false, this->fdDir);
return 0;
}
}
errno = EBADF;
return -1;
}
int FileDescriptorTable::GetFreeFileDescriptor()
{
int i = 0;
while (true)
{
bool Found = false;
foreach (auto fd in FileDescriptors)
{
if (fd.Descriptor == i)
{
Found = true;
break;
}
}
if (!Found)
return i;
i++;
}
errno = EMFILE;
return -1;
}
std::string FileDescriptorTable::GetAbsolutePath(int FileDescriptor)
{
FileDescriptorTable::FileDescriptor fd =
this->GetFileDescriptor(FileDescriptor);
if (fd.Descriptor == -1)
return "";
Node *node = fd.Handle->node;
std::string absolutePath = vfs->GetPathFromNode(node);
std::string path = absolutePath.c_str();
return path;
}
int FileDescriptorTable::_open(const char *pathname, int flags,
mode_t mode)
{
if (pathname == nullptr)
{
errno = EFAULT;
return -1;
}
return AddFileDescriptor(pathname, mode, flags);
}
int FileDescriptorTable::_creat(const char *pathname, mode_t mode)
{
return _open(pathname, O_WRONLY | O_CREAT | O_TRUNC, mode);
}
ssize_t FileDescriptorTable::_read(int fd, void *buf, size_t count)
{
FileDescriptor fdesc;
fdesc = this->GetFileDescriptor(fd);
if (fdesc.Descriptor < 0)
{
errno = EBADF;
return -1;
}
return fdesc.Handle->Read((uint8_t *)buf, count);
}
ssize_t FileDescriptorTable::_write(int fd, const void *buf,
size_t count)
{
FileDescriptor fdesc;
fdesc = this->GetFileDescriptor(fd);
if (fdesc.Descriptor < 0)
return -1;
return fdesc.Handle->Write((uint8_t *)buf, count);
}
int FileDescriptorTable::_close(int fd)
{
FileDescriptor fdesc;
fdesc = this->GetFileDescriptor(fd);
if (fdesc.Descriptor < 0)
{
errno = EBADF;
return -1;
}
if (RemoveFileDescriptor(fd) < 0)
{
errno = EBADF;
return -1;
}
delete fdesc.Handle;
return 0;
}
off_t FileDescriptorTable::_lseek(int fd, off_t offset, int whence)
{
FileDescriptor fdesc;
fdesc = this->GetFileDescriptor(fd);
if (fdesc.Descriptor < 0)
{
errno = EBADF;
return -1;
}
return fdesc.Handle->Seek(offset, whence);
}
int FileDescriptorTable::_stat(const char *pathname,
struct stat *statbuf)
{
if (pathname == nullptr)
{
errno = EINVAL;
return -1;
}
RefNode *file = vfs->Open(pathname,
thisProcess->CurrentWorkingDirectory);
if (!file)
{
error("Failed to open file %s: %d",
pathname, errno);
return -1;
}
Node *node = file->node;
statbuf->st_dev = 0; /* FIXME: stub */
statbuf->st_ino = node->IndexNode;
statbuf->st_mode = node->Flags | node->Mode;
statbuf->st_nlink = 0; /* FIXME: stub */
statbuf->st_uid = node->UserIdentifier;
statbuf->st_gid = node->GroupIdentifier;
statbuf->st_rdev = 0; /* FIXME: stub */
statbuf->st_size = node->Length;
statbuf->st_blksize = 0; /* FIXME: stub */
statbuf->st_blocks = 0; /* FIXME: stub */
statbuf->st_attr = 0; /* FIXME: stub */
return 0;
}
int FileDescriptorTable::_fstat(int fd, struct stat *statbuf)
{
FileDescriptor fdesc;
fdesc = this->GetFileDescriptor(fd);
if (fdesc.Descriptor < 0)
{
errno = EBADF;
return -1;
}
Node *node = fdesc.Handle->node;
statbuf->st_dev = 0; /* FIXME: stub */
statbuf->st_ino = node->IndexNode;
statbuf->st_mode = node->Flags | node->Mode;
statbuf->st_nlink = 0; /* FIXME: stub */
statbuf->st_uid = node->UserIdentifier;
statbuf->st_gid = node->GroupIdentifier;
statbuf->st_rdev = 0; /* FIXME: stub */
statbuf->st_size = node->Length;
statbuf->st_blksize = 0; /* FIXME: stub */
statbuf->st_blocks = 0; /* FIXME: stub */
statbuf->st_attr = 0; /* FIXME: stub */
return 0;
}
int FileDescriptorTable::_lstat(const char *pathname,
struct stat *statbuf)
{
if (pathname == nullptr)
{
errno = EINVAL;
return -1;
}
RefNode *file = vfs->Open(pathname,
thisProcess->CurrentWorkingDirectory);
if (!file)
{
error("Failed to open file %s: %d",
pathname, errno);
return -1;
}
Node *node = file->node;
statbuf->st_dev = 0; /* FIXME: stub */
statbuf->st_ino = node->IndexNode;
statbuf->st_mode = node->Flags | node->Mode;
statbuf->st_nlink = 0; /* FIXME: stub */
statbuf->st_uid = node->UserIdentifier;
statbuf->st_gid = node->GroupIdentifier;
statbuf->st_rdev = 0; /* FIXME: stub */
statbuf->st_size = node->Length;
statbuf->st_blksize = 0; /* FIXME: stub */
statbuf->st_blocks = 0; /* FIXME: stub */
statbuf->st_attr = 0; /* FIXME: stub */
return 0;
}
FileDescriptorTable::FileDescriptorTable(void *Owner)
{
this->fdDir = vfs->Create("fd", VirtualFileSystem::NodeFlags::DIRECTORY,
((Tasking::PCB *)Owner)->ProcessDirectory);
}
FileDescriptorTable::~FileDescriptorTable()
{
foreach (auto var in FileDescriptors)
{
this->RemoveFileDescriptor(var.Descriptor);
delete var.Handle;
}
}
}

197
FileSystem/FileNode.cpp Normal file
View File

@ -0,0 +1,197 @@
/*
This file is part of Fennix Kernel.
Fennix Kernel is free software: you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation, either version 3 of
the License, or (at your option) any later version.
Fennix Kernel is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
*/
#include <filesystem.hpp>
namespace VirtualFileSystem
{
ReferenceNode *Node::CreateReference()
{
SmartLock(NodeLock);
ReferenceNode *rn = new ReferenceNode(this);
References.push_back(rn);
debug("Created reference %p for node %p", rn, this);
return rn;
}
void Node::RemoveReference(ReferenceNode *Reference)
{
SmartLock(NodeLock);
debug("Removing reference %p for node %p", Reference, this);
References.erase(std::find(References.begin(), References.end(), Reference));
}
/**************************************************************/
size_t ReferenceNode::Read(uint8_t *Buffer, size_t Size)
{
if (this->SymlinkTo)
return this->SymlinkTo->Read(Buffer, Size);
if (!this->node->Operator)
{
errno = EFAULT;
return -1;
}
SmartLock(RefNodeLock);
if (this->node->Operator->Read)
{
off_t RefOffset = off_t(this->Offset.load());
return this->node->Operator->Read(this->node, Size, Buffer, RefOffset);
}
errno = ENOSYS;
return -1;
}
size_t ReferenceNode::Write(uint8_t *Buffer, size_t Size)
{
if (this->SymlinkTo)
return this->SymlinkTo->Write(Buffer, Size);
if (!this->node->Operator)
{
errno = EFAULT;
return -1;
}
SmartLock(RefNodeLock);
if (this->node->Operator->Write)
{
off_t RefOffset = off_t(this->Offset.load());
return this->node->Operator->Write(this->node, Size, Buffer, RefOffset);
}
errno = ENOSYS;
return -1;
}
off_t ReferenceNode::Seek(off_t Offset, int Whence)
{
if (this->SymlinkTo)
return this->SymlinkTo->Seek(Offset, Whence);
if (!this->node->Operator)
{
errno = EFAULT;
return -1;
}
SmartLock(RefNodeLock);
if (this->node->Operator->Seek)
{
off_t RefOffset = off_t(this->Offset.load());
return this->node->Operator->Seek(this->node, Offset, Whence, RefOffset);
}
switch (Whence)
{
case SEEK_SET:
{
if (Offset > this->node->Length)
{
errno = EINVAL;
return -1;
}
this->Offset.store(Offset);
break;
}
case SEEK_CUR:
{
off_t NewOffset = off_t(this->Offset.load()) + Offset;
if (NewOffset > this->node->Length ||
NewOffset < 0)
{
errno = EINVAL;
return -1;
}
this->Offset.store(NewOffset);
break;
}
case SEEK_END:
{
off_t NewOffset = this->node->Length + Offset;
if (NewOffset > this->node->Length ||
NewOffset < 0)
{
errno = EINVAL;
return -1;
}
this->Offset.store(NewOffset);
break;
}
default:
{
error("Invalid whence!");
errno = EINVAL;
return -1;
}
}
return (off_t)this->Offset.load();
}
ReferenceNode::ReferenceNode(Node *node)
{
SmartLock(RefNodeLock);
this->node = node;
this->FileSize = node->Length;
this->AbsolutePath += node->FileSystem->GetPathFromNode(node);
if (this->node->Flags == SYMLINK)
{
if (!this->node->SymlinkTarget)
{
this->node->SymlinkTarget =
node->FileSystem->GetNodeFromPath(this->node->Symlink);
/* not standard but useful in kernel-space */
this->node->Length = this->node->SymlinkTarget->Length;
}
if (!this->node->SymlinkTarget)
{
error("Symlink target %s not found!",
this->node->Symlink);
errno = ENOENT;
return;
}
this->SymlinkTo = this->node->SymlinkTarget->CreateReference();
}
debug("Created reference node for %s [%#lx]",
this->AbsolutePath.c_str(), (uintptr_t)this);
}
ReferenceNode::~ReferenceNode()
{
SmartLock(RefNodeLock);
if (this->SymlinkTo)
this->node->SymlinkTarget->RemoveReference(this);
this->node->RemoveReference(this);
debug("Destroyed reference node for %s [%#lx]",
this->AbsolutePath.c_str(), (uintptr_t)this);
}
}

View File

@ -20,7 +20,6 @@
#include <smart_ptr.hpp>
#include <convert.h>
#include <printf.h>
#include <lock.hpp>
#include <cwalk.h>
#include "../kernel.h"
@ -34,20 +33,26 @@
#define vfsdbg(m, ...)
#endif
NewLock(VFSLock);
namespace VirtualFileSystem
{
std::shared_ptr<char> Virtual::GetPathFromNode(Node *node)
std::string Virtual::GetPathFromNode(Node *File)
{
vfsdbg("GetPathFromNode( Node: \"%s\" )", node->Name);
Node *Parent = node;
vfsdbg("GetPathFromNode( Node: \"%s\" )", File->Name);
SmartLock(VirtualLock);
Node *Parent = File;
char **Path = nullptr;
size_t Size = 1;
size_t PathSize = 0;
std::string FinalPath;
while (Parent != FileSystemRoot && Parent != nullptr)
{
if (File == FileSystemRoot->Children[0])
{
FinalPath = "/";
break;
}
bool Found = false;
foreach (const auto &Children in FileSystemRoot->Children)
if (Children == Parent)
@ -70,7 +75,7 @@ namespace VirtualFileSystem
}
Path = new_path;
Path[PathSize] = Parent->Name;
Path[PathSize] = (char *)Parent->Name;
PathSize++;
new_path = new char *[PathSize + 1];
memcpy(new_path, Path, sizeof(char *) * PathSize);
@ -81,33 +86,42 @@ namespace VirtualFileSystem
Parent = Parent->Parent;
}
for (size_t i = 0; i < PathSize; i++)
Size += strlen(Path[i]);
std::shared_ptr<char> FinalPath;
FinalPath.reset(new char[Size]);
size_t Offset = 0;
for (size_t i = PathSize - 1; i < PathSize; i--)
{
if (Path[i] == nullptr)
continue;
size_t ElementSize = strlen(Path[i]);
memcpy(FinalPath.get() + Offset, Path[i], ElementSize);
Offset += ElementSize;
FinalPath += Path[i];
}
FinalPath.get()[Size - 1] = '\0';
FinalPath += "\0";
delete[] Path, Path = nullptr;
vfsdbg("GetPathFromNode()->\"%s\"", FinalPath.get());
vfsdbg("GetPathFromNode()->\"%s\"", FinalPath.c_str());
return FinalPath;
}
Node *Virtual::GetNodeFromPath(const char *Path, Node *Parent)
Node *Virtual::GetNodeFromPath_Unsafe(const char *Path, Node *Parent)
{
vfsdbg("GetNodeFromPath( Path: \"%s\" Parent: \"%s\" )", Path, Parent ? Parent->Name : "(null)");
vfsdbg("GetNodeFromPath( Path: \"%s\" Parent: \"%s\" )",
Path, Parent ? Parent->Name : "(null)");
if (strcmp(Path, "/") == 0)
return FileSystemRoot->Children[0]; // 0 - filesystem root
if (strcmp(Path, ".") == 0)
return Parent;
if (strcmp(Path, "..") == 0)
{
if (Parent)
{
if (Parent->Parent)
return Parent->Parent;
else
return Parent;
}
else
return nullptr;
}
Node *ReturnNode = Parent;
bool IsAbsolutePath = cwk_path_is_absolute(Path);
@ -122,6 +136,7 @@ namespace VirtualFileSystem
if (unlikely(!cwk_path_get_first_segment(Path, &segment)))
{
error("Path doesn't have any segments.");
errno = ENOENT;
return nullptr;
}
@ -133,7 +148,8 @@ namespace VirtualFileSystem
GetNodeFromPathNextParent:
foreach (auto Child in ReturnNode->Children)
{
vfsdbg("comparing \"%s\" with \"%s\"", Child->Name, SegmentName);
vfsdbg("comparing \"%s\" with \"%s\"",
Child->Name, SegmentName);
if (strcmp(Child->Name, SegmentName) == 0)
{
ReturnNode = Child;
@ -145,7 +161,8 @@ namespace VirtualFileSystem
const char *basename;
cwk_path_get_basename(Path, &basename, nullptr);
vfsdbg("BaseName: \"%s\" NodeName: \"%s\"", basename, ReturnNode->Name);
vfsdbg("BaseName: \"%s\" NodeName: \"%s\"",
basename, ReturnNode->Name);
if (strcmp(basename, ReturnNode->Name) == 0)
{
@ -154,15 +171,14 @@ namespace VirtualFileSystem
}
vfsdbg("GetNodeFromPath()->\"(null)\"");
errno = ENOENT;
return nullptr;
}
File Virtual::ConvertNodeToFILE(Node *node)
Node *Virtual::GetNodeFromPath(const char *Path, Node *Parent)
{
File file{};
file.Status = FileStatus::OK;
file.node = node;
return file;
SmartLock(VirtualLock);
return GetNodeFromPath_Unsafe(Path, Parent);
}
bool Virtual::PathIsRelative(const char *Path)
@ -175,7 +191,9 @@ namespace VirtualFileSystem
Node *Virtual::GetParent(const char *Path, Node *Parent)
{
vfsdbg("GetParent( Path: \"%s\" Parent: \"%s\" )", Path, Parent->Name);
vfsdbg("GetParent( Path: \"%s\" Parent: \"%s\" )",
Path, Parent->Name);
if (Parent)
{
vfsdbg("GetParent()->\"%s\"", Parent->Name);
@ -218,13 +236,16 @@ namespace VirtualFileSystem
error("Parent is null!");
return nullptr;
}
vfsdbg("AddNewChild( Name: \"%s\" Parent: \"%s\" )", Name, Parent->Name);
vfsdbg("AddNewChild( Name: \"%s\" Parent: \"%s\" )",
Name, Parent->Name);
Node *newNode = new Node;
newNode->Parent = Parent;
strcpy(newNode->Name, Name);
newNode->Name = new char[strlen(Name) + 1];
strncpy((char *)newNode->Name, Name, strlen(Name));
newNode->Operator = Parent->Operator;
newNode->FileSystem = this;
Parent->Children.push_back(newNode);
vfsdbg("AddNewChild()->\"%s\"", newNode->Name);
@ -233,7 +254,9 @@ namespace VirtualFileSystem
Node *Virtual::GetChild(const char *Name, Node *Parent)
{
vfsdbg("GetChild( Name: \"%s\" Parent: \"%s\" )", Name, Parent->Name);
vfsdbg("GetChild( Name: \"%s\" Parent: \"%s\" )",
Name, Parent->Name);
if (!Parent)
{
vfsdbg("GetChild()->nullptr");
@ -250,42 +273,53 @@ namespace VirtualFileSystem
return nullptr;
}
FileStatus Virtual::RemoveChild(const char *Name, Node *Parent)
int Virtual::RemoveChild(const char *Name, Node *Parent)
{
vfsdbg("RemoveChild( Name: \"%s\" Parent: \"%s\" )", Name, Parent->Name);
for (size_t i = 0; i < Parent->Children.size(); i++)
vfsdbg("RemoveChild( Name: \"%s\" Parent: \"%s\" )",
Name, Parent->Name);
forItr(itr, Parent->Children)
{
if (strcmp(Parent->Children[i]->Name, Name) == 0)
if (strcmp((*itr)->Name, Name) == 0)
{
delete Parent->Children[i], Parent->Children[i] = nullptr;
Parent->Children.remove(i);
delete *itr, *itr = nullptr;
Parent->Children.erase(itr);
vfsdbg("RemoveChild()->OK");
return FileStatus::OK;
return 0;
}
}
vfsdbg("RemoveChild()->NotFound");
return FileStatus::NotFound;
}
std::shared_ptr<char> Virtual::NormalizePath(const char *Path, Node *Parent)
vfsdbg("RemoveChild()->NotFound");
return -1;
}
std::string Virtual::NormalizePath(const char *Path, Node *Parent)
{
vfsdbg("NormalizePath( Path: \"%s\" Parent: \"%s\" )", Path, Parent->Name);
vfsdbg("NormalizePath( Path: \"%s\" Parent: \"%s\" )",
Path, Parent->Name);
char *NormalizedPath = new char[strlen((char *)Path) + 1];
std::shared_ptr<char> RelativePath;
std::string RelativePath;
cwk_path_normalize(Path, NormalizedPath, strlen((char *)Path) + 1);
if (cwk_path_is_relative(NormalizedPath))
{
std::shared_ptr<char> ParentPath = GetPathFromNode(Parent);
size_t PathSize = cwk_path_get_absolute(ParentPath.get(), NormalizedPath, nullptr, 0);
RelativePath.reset(new char[PathSize + 1]);
cwk_path_get_absolute(ParentPath.get(), NormalizedPath, RelativePath.get(), PathSize + 1);
std::string ParentPath = GetPathFromNode(Parent);
size_t PathSize = cwk_path_join(ParentPath.c_str(),
NormalizedPath,
nullptr, 0);
RelativePath.resize(PathSize + 1);
cwk_path_join(ParentPath.c_str(), NormalizedPath,
(char *)RelativePath.c_str(),
PathSize + 1);
}
else
{
RelativePath.reset(new char[strlen(NormalizedPath) + 1]);
strcpy(RelativePath.get(), NormalizedPath);
RelativePath = NormalizedPath;
}
delete[] NormalizedPath;
vfsdbg("NormalizePath()->\"%s\"", RelativePath.get());
@ -303,9 +337,10 @@ namespace VirtualFileSystem
if (Parent == nullptr)
Parent = FileSystemRoot;
vfsdbg("PathExists( Path: \"%s\" Parent: \"%s\" )", Path, Parent->Name);
vfsdbg("PathExists( Path: \"%s\" Parent: \"%s\" )",
Path, Parent->Name);
if (GetNodeFromPath(NormalizePath(Path, Parent).get(), Parent))
if (GetNodeFromPath(NormalizePath(Path, Parent).c_str(), Parent))
{
vfsdbg("PathExists()->OK");
return true;
@ -315,15 +350,20 @@ namespace VirtualFileSystem
return false;
}
Node *Virtual::CreateRoot(const char *RootName, FileSystemOperations *Operator)
Node *Virtual::CreateRoot(const char *RootName,
FileSystemOperations *Operator)
{
if (Operator == nullptr)
return nullptr;
vfsdbg("Creating root %s", RootName);
debug("Creating root %s", RootName);
SmartLock(VirtualLock);
Node *newNode = new Node;
strncpy(newNode->Name, RootName, FILENAME_LENGTH);
newNode->Name = RootName;
newNode->Flags = NodeFlags::DIRECTORY;
newNode->Operator = Operator;
newNode->FileSystem = this;
FileSystemRoot->Children.push_back(newNode);
return newNode;
}
@ -331,26 +371,30 @@ namespace VirtualFileSystem
/* TODO: Further testing needed */
Node *Virtual::Create(const char *Path, NodeFlags Flag, Node *Parent)
{
SmartLock(VFSLock);
if (isempty((char *)Path))
return nullptr;
SmartLock(VirtualLock);
Node *RootNode = FileSystemRoot->Children[0];
Node *CurrentParent = this->GetParent(Path, Parent);
vfsdbg("Virtual::Create( Path: \"%s\" Parent: \"%s\" )", Path, Parent ? Parent->Name : CurrentParent->Name);
vfsdbg("Virtual::Create( Path: \"%s\" Parent: \"%s\" )",
Path, Parent ? Parent->Name : CurrentParent->Name);
std::shared_ptr<char> CleanPath = this->NormalizePath(Path, CurrentParent);
VirtualLock.Unlock();
std::string CleanPath = this->NormalizePath(Path, CurrentParent);
VirtualLock.Lock(__FUNCTION__);
vfsdbg("CleanPath: \"%s\"", CleanPath.get());
if (PathExists(CleanPath.get(), CurrentParent))
VirtualLock.Unlock();
if (PathExists(CleanPath.c_str(), CurrentParent))
{
error("Path %s already exists.", CleanPath.get());
error("Path %s already exists.", CleanPath.c_str());
goto CreatePathError;
}
VirtualLock.Lock(__FUNCTION__);
cwk_segment segment;
if (!cwk_path_get_first_segment(CleanPath.get(), &segment))
if (!cwk_path_get_first_segment(CleanPath.c_str(), &segment))
{
error("Path doesn't have any segments.");
goto CreatePathError;
@ -363,12 +407,14 @@ namespace VirtualFileSystem
vfsdbg("SegmentName: \"%s\"", SegmentName);
if (Parent)
{
if (GetChild(SegmentName, RootNode) != nullptr)
{
RootNode = GetChild(SegmentName, RootNode);
delete[] SegmentName;
continue;
}
}
if (GetChild(SegmentName, CurrentParent) == nullptr)
{
@ -384,7 +430,12 @@ namespace VirtualFileSystem
} while (cwk_path_get_next_segment(&segment));
vfsdbg("Virtual::Create()->\"%s\"", CurrentParent->Name);
vfsdbg("Path created: \"%s\"", GetPathFromNode(CurrentParent).get());
#ifdef DEBUG
VirtualLock.Unlock();
debug("Path created: \"%s\"",
GetPathFromNode(CurrentParent).c_str());
VirtualLock.Lock(__FUNCTION__);
#endif
return CurrentParent;
CreatePathError:
@ -392,321 +443,192 @@ namespace VirtualFileSystem
return nullptr;
}
FileStatus Virtual::Delete(const char *Path, bool Recursive, Node *Parent)
int Virtual::Delete(const char *Path, bool Recursive, Node *Parent)
{
SmartLock(VFSLock);
vfsdbg("Virtual::Delete( Path: \"%s\" Parent: \"%s\" )", Path, Parent ? Parent->Name : "(null)");
vfsdbg("Virtual::Delete( Path: \"%s\" Parent: \"%s\" )",
Path, Parent ? Parent->Name : "(null)");
if (isempty((char *)Path))
return InvalidParameter;
{
errno = EINVAL;
return -1;
}
if (Parent == nullptr)
Parent = FileSystemRoot;
std::shared_ptr<char> CleanPath = this->NormalizePath(Path, Parent);
vfsdbg("CleanPath: \"%s\"", CleanPath.get());
std::string CleanPath = this->NormalizePath(Path, Parent);
vfsdbg("CleanPath: \"%s\"", CleanPath.c_str());
if (!PathExists(CleanPath.get(), Parent))
if (!PathExists(CleanPath.c_str(), Parent))
{
vfsdbg("Path %s doesn't exist.", CleanPath.get());
return InvalidPath;
vfsdbg("Path %s doesn't exist.", CleanPath.c_str());
errno = ENOENT;
return -1;
}
Node *NodeToDelete = GetNodeFromPath(CleanPath.get(), Parent);
Node *ParentNode = GetParent(CleanPath.get(), Parent);
Node *NodeToDelete = GetNodeFromPath(CleanPath.c_str(), Parent);
if (NodeToDelete->Flags == NodeFlags::DIRECTORY)
{
SmartLock(VirtualLock);
if (Recursive)
{
foreach (auto Child in NodeToDelete->Children)
{
VFSLock.Unlock();
FileStatus Status = Delete(GetPathFromNode(Child).get(), true);
VFSLock.Lock(__FUNCTION__);
if (Status != FileStatus::OK)
VirtualLock.Unlock();
int Status = Delete(GetPathFromNode(Child).c_str(), true);
VirtualLock.Lock(__FUNCTION__);
if (Status != 0)
{
vfsdbg("Failed to delete child %s with status %d. (%s)", Child->Name, Status, Path);
return PartiallyCompleted;
error("Failed to delete child %s with status %d. (%s)",
Child->Name, Status, Path);
errno = EIO;
return -1;
}
}
}
else if (NodeToDelete->Children.size() > 0)
{
vfsdbg("Directory %s is not empty.", CleanPath.get());
return DirectoryNotEmpty;
error("Directory %s is not empty.", CleanPath.c_str());
errno = ENOTEMPTY;
return -1;
}
}
if (RemoveChild(NodeToDelete->Name, ParentNode) != FileStatus::OK)
SmartLock(VirtualLock);
Node *ParentNode = GetParent(CleanPath.c_str(), Parent);
if (RemoveChild(NodeToDelete->Name, ParentNode) != 0)
{
vfsdbg("Failed to remove child %s from parent %s. (%s)", NodeToDelete->Name, ParentNode->Name, Path);
return NotFound;
error("Failed to remove child %s from parent %s. (%s)", NodeToDelete->Name, ParentNode->Name, Path);
errno = EIO;
return -1;
}
debug("Deleted %s", CleanPath.c_str());
vfsdbg("Virtual::Delete()->OK");
return OK;
return 0;
}
FileStatus Virtual::Delete(Node *Path, bool Recursive, Node *Parent) { return Delete(GetPathFromNode(Path).get(), Recursive, Parent); }
int Virtual::Delete(Node *Path, bool Recursive, Node *Parent)
{
std::string PathString = GetPathFromNode(Path);
return Delete(PathString.c_str(), Recursive, Parent);
}
/* TODO: REWORK */
File Virtual::Mount(const char *Path, FileSystemOperations *Operator)
Node *Virtual::Mount(const char *Path, FileSystemOperations *Operator)
{
SmartLock(VFSLock);
File file{};
if (unlikely(!Operator))
{
file.Status = FileStatus::InvalidOperator;
return file;
errno = EFAULT;
return nullptr;
}
if (unlikely(isempty((char *)Path)))
{
file.Status = FileStatus::InvalidParameter;
return file;
errno = EINVAL;
return nullptr;
}
vfsdbg("Mounting %s", Path);
const char *PathCopy;
cwk_path_get_basename(Path, &PathCopy, 0);
strcpy(file.Name, PathCopy);
file.Status = FileStatus::OK;
file.node = Create(Path, NodeFlags::MOUNTPOINT);
file.node->Operator = Operator;
return file;
Node *MountPoint = Create(Path, NodeFlags::MOUNTPOINT);
MountPoint->Operator = Operator;
return MountPoint;
}
FileStatus Virtual::Unmount(File &File)
int Virtual::Unmount(Node *File)
{
SmartLock(VFSLock);
if (unlikely(!File.node))
return FileStatus::InvalidParameter;
fixme("Unmounting %s", File.Name);
return FileStatus::OK;
}
size_t Virtual::Read(File &File, uint8_t *Buffer, size_t Size)
if (unlikely(!File))
{
SmartLock(VFSLock);
if (unlikely(!File.node))
{
File.Status = FileStatus::InvalidNode;
return 0;
}
if (unlikely(!File.node->Operator))
{
File.Status = FileStatus::InvalidOperator;
return 0;
}
File.Status = FileStatus::OK;
vfsdbg("Reading %s out->%016x", File.Name, Buffer);
return File.node->Operator->Read(File.node, Size, Buffer);
}
size_t Virtual::Write(File &File, uint8_t *Buffer, size_t Size)
{
SmartLock(VFSLock);
if (unlikely(!File.node))
{
File.Status = FileStatus::InvalidNode;
return 0;
}
if (unlikely(!File.node->Operator))
{
File.Status = FileStatus::InvalidOperator;
return 0;
}
File.Status = FileStatus::OK;
vfsdbg("Writing %s out->%016x", File.Name, Buffer);
return File.node->Operator->Write(File.node, Size, Buffer);
}
off_t Virtual::Seek(File &File, off_t Offset, uint8_t Whence)
{
SmartLock(VFSLock);
Node *node = File.node;
File.Status = FileStatus::OK;
if (unlikely(!node))
{
File.Status = FileStatus::InvalidNode;
errno = EINVAL;
return -1;
}
if (unlikely(!node->Operator))
if (unlikely(File->Flags != NodeFlags::MOUNTPOINT))
{
File.Status = FileStatus::InvalidOperator;
errno = ENOTDIR;
return -1;
}
if (unlikely(node->Operator->Seek))
{
node->Offset = File.ContextOffset;
File.ContextOffset = node->Operator->Seek(node, Offset, Whence);
return File.ContextOffset;
}
switch (Whence)
{
case SEEK_SET:
{
if ((size_t)Offset > node->Length)
return -1;
File.ContextOffset = node->Offset = Offset;
break;
}
case SEEK_CUR:
{
off_t NewOffset = File.ContextOffset + Offset;
if ((size_t)NewOffset > node->Length ||
NewOffset < 0)
return -1;
File.ContextOffset = node->Offset = NewOffset;
break;
}
case SEEK_END:
{
off_t NewOffset = node->Length + Offset;
if ((size_t)NewOffset > node->Length ||
NewOffset < 0)
return -1;
File.ContextOffset = node->Offset = NewOffset;
break;
}
default:
{
error("Invalid whence!");
fixme("Unmounting %s",
File->Name);
errno = ENOSYS;
return -1;
}
}
return File.ContextOffset;
}
/* TODO: CHECK Open */
File Virtual::Open(const char *Path, Node *Parent)
RefNode *Virtual::Open(const char *Path, Node *Parent)
{
SmartLock(VFSLock);
vfsdbg("Opening %s with parent %s", Path, Parent ? Parent->Name : "(null)");
const char *basename;
if (strcmp(Path, "/") == 0)
{
File file{};
file.node = FileSystemRoot;
return FileSystemRoot->CreateReference();
strcpy(file.Name, "/");
return file;
}
if (!Parent)
Parent = FileSystemRoot->Children[0];
if (strcmp(Path, ".") == 0)
{
File file{};
file.node = Parent;
if (unlikely(!file.node))
file.Status = FileStatus::NotFound;
cwk_path_get_basename(GetPathFromNode(Parent).get(), &basename, nullptr);
strcpy(file.Name, basename);
return file;
}
return Parent->CreateReference();
if (strcmp(Path, "..") == 0)
{
File file{};
if (Parent->Parent != nullptr)
file.node = Parent->Parent;
if (!file.node)
file.Status = FileStatus::NotFound;
cwk_path_get_basename(GetPathFromNode(Parent).get(), &basename, nullptr);
strcpy(file.Name, basename);
return file;
if (Parent->Parent)
return Parent->Parent->CreateReference();
else
return Parent->CreateReference();
}
Node *CurrentParent = this->GetParent(Path, Parent);
std::shared_ptr<char> CleanPath = NormalizePath(Path, CurrentParent);
std::string CleanPath = NormalizePath(Path, CurrentParent);
File file{};
/* TODO: Check for other errors */
if (!PathExists(CleanPath.get(), CurrentParent))
if (!PathExists(CleanPath.c_str(), CurrentParent))
{
{
SmartLock(VirtualLock);
foreach (auto Child in FileSystemRoot->Children)
{
if (strcmp(Child->Name, CleanPath.get()) == 0)
{
file.node = Child;
if (file.node == nullptr)
{
file.Status = FileStatus::UnknownFileStatusError;
file.node = nullptr;
return file;
}
cwk_path_get_basename(GetPathFromNode(Child).get(), &basename, nullptr);
strcpy(file.Name, basename);
return file;
if (strcmp(Child->Name, CleanPath.c_str()) != 0)
continue;
return Child->CreateReference();
}
}
file.node = GetNodeFromPath(CleanPath.get(), FileSystemRoot->Children[0]);
if (file.node)
{
cwk_path_get_basename(GetPathFromNode(file.node).get(), &basename, nullptr);
strcpy(file.Name, basename);
return file;
}
Node *node = GetNodeFromPath(CleanPath.c_str(), FileSystemRoot->Children[0]);
if (node)
return node->CreateReference();
}
else
{
file.node = GetNodeFromPath(CleanPath.get(), CurrentParent);
cwk_path_get_basename(CleanPath.get(), &basename, nullptr);
strcpy(file.Name, basename);
return file;
Node *node = GetNodeFromPath(CleanPath.c_str(), CurrentParent);
if (node)
return node->CreateReference();
}
file.Status = FileStatus::NotFound;
return file;
}
FileStatus Virtual::Close(File &File)
{
SmartLock(VFSLock);
if (unlikely(!File.node))
return FileStatus::InvalidHandle;
vfsdbg("Closing %s", File.Name);
File.node->Offset = 0;
return FileStatus::OK;
errno = ENOENT;
return nullptr;
}
Virtual::Virtual()
{
SmartLock(VirtualLock);
trace("Initializing virtual file system...");
FileSystemRoot = new Node;
FileSystemRoot->Flags = NodeFlags::MOUNTPOINT;
FileSystemRoot->Operator = nullptr;
FileSystemRoot->Parent = nullptr;
strncpy(FileSystemRoot->Name, "root", 4);
FileSystemRoot->Name = "root";
FileSystemRoot->FileSystem = this;
cwk_path_set_style(CWK_STYLE_UNIX);
}
Virtual::~Virtual()
{
debug("Destructor called");
SmartLock(VirtualLock);
stub;
/* TODO: sync, cache */
}
}

157
FileSystem/Kernel_IO.cpp Normal file
View File

@ -0,0 +1,157 @@
/*
This file is part of Fennix Kernel.
Fennix Kernel is free software: you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation, either version 3 of
the License, or (at your option) any later version.
Fennix Kernel is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
*/
#include <filesystem.hpp>
#include <errno.h>
#include "../kernel.h"
using Tasking::PCB;
using VirtualFileSystem::FileDescriptorTable;
static bool CheckForScheduler()
{
if (TaskManager == nullptr)
return false;
return true;
}
int fopen(const char *pathname, const char *mode)
{
if (!CheckForScheduler())
{
errno = ENOSYS;
return -1;
}
PCB *pcb = thisProcess;
FileDescriptorTable *fdt = pcb->FileDescriptors;
int fd = fdt->_open(pathname, ConvertFileFlags(mode), 0666);
return fd;
}
int creat(const char *pathname, mode_t mode)
{
if (!CheckForScheduler())
{
errno = ENOSYS;
return -1;
}
PCB *pcb = thisProcess;
FileDescriptorTable *fdt = pcb->FileDescriptors;
int fd = fdt->_creat(pathname, mode);
return fd;
}
ssize_t fread(int fd, void *buf, size_t count)
{
if (!CheckForScheduler())
{
errno = ENOSYS;
return -1;
}
PCB *pcb = thisProcess;
FileDescriptorTable *fdt = pcb->FileDescriptors;
ssize_t r = fdt->_read(fd, buf, count);
return r;
}
ssize_t fwrite(int fd, const void *buf, size_t count)
{
if (!CheckForScheduler())
{
errno = ENOSYS;
return -1;
}
PCB *pcb = thisProcess;
FileDescriptorTable *fdt = pcb->FileDescriptors;
ssize_t r = fdt->_write(fd, buf, count);
return r;
}
int fclose(int fd)
{
if (!CheckForScheduler())
{
errno = ENOSYS;
return -1;
}
PCB *pcb = thisProcess;
FileDescriptorTable *fdt = pcb->FileDescriptors;
int r = fdt->_close(fd);
return r;
}
off_t lseek(int fd, off_t offset, int whence)
{
if (!CheckForScheduler())
{
errno = ENOSYS;
return -1;
}
PCB *pcb = thisProcess;
FileDescriptorTable *fdt = pcb->FileDescriptors;
off_t r = fdt->_lseek(fd, offset, whence);
return r;
}
int stat(const char *pathname, struct stat *statbuf)
{
if (!CheckForScheduler())
{
errno = ENOSYS;
return -1;
}
PCB *pcb = thisProcess;
FileDescriptorTable *fdt = pcb->FileDescriptors;
int r = fdt->_stat(pathname, statbuf);
return r;
}
int fstat(int fd, struct stat *statbuf)
{
if (!CheckForScheduler())
{
errno = ENOSYS;
return -1;
}
PCB *pcb = thisProcess;
FileDescriptorTable *fdt = pcb->FileDescriptors;
int r = fdt->_fstat(fd, statbuf);
return r;
}
int lstat(const char *pathname, struct stat *statbuf)
{
if (!CheckForScheduler())
{
errno = ENOSYS;
return -1;
}
PCB *pcb = thisProcess;
FileDescriptorTable *fdt = pcb->FileDescriptors;
int r = fdt->_lstat(pathname, statbuf);
return r;
}

View File

@ -1,218 +0,0 @@
/*
This file is part of Fennix Kernel.
Fennix Kernel is free software: you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation, either version 3 of
the License, or (at your option) any later version.
Fennix Kernel is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
*/
#include <gui.hpp>
#include "../kernel.h"
namespace GraphicalUserInterface
{
Ofast inline void InlineSetPixel(ScreenBitmap *Bitmap, int64_t X, int64_t Y, uint32_t Color)
{
if (unlikely(X < 0 || Y < 0 || X >= (int64_t)Bitmap->Width || Y >= (int64_t)Bitmap->Height))
return;
uint32_t *Pixel = (uint32_t *)((uintptr_t)Bitmap->Data + (Y * Bitmap->Width + X) * (Bitmap->BitsPerPixel / 8));
*Pixel = Color;
// Bitmap->Data[Y * Bitmap->Width + X] = Color;
}
void SetPixel(ScreenBitmap *Bitmap, size_t X, size_t Y, uint32_t Color)
{
if (unlikely(!Bitmap))
return;
if (unlikely(!Bitmap->Data))
return;
InlineSetPixel(Bitmap, X, Y, Color);
}
uint32_t GetPixel(ScreenBitmap *Bitmap, int64_t X, int64_t Y)
{
if (unlikely(!Bitmap))
return 0;
if (unlikely(!Bitmap->Data))
return 0;
if (unlikely(X < 0 || Y < 0 || X >= (int64_t)Bitmap->Width || Y >= (int64_t)Bitmap->Height))
return 0;
uint32_t *Pixel = (uint32_t *)((uintptr_t)Bitmap->Data + (Y * Bitmap->Width + X) * (Bitmap->BitsPerPixel / 8));
return *Pixel;
}
Ofast void DrawOverBitmap(ScreenBitmap *DestinationBitmap,
ScreenBitmap *SourceBitmap,
int64_t Top,
int64_t Left, bool IgnoreZero)
{
if (unlikely(!SourceBitmap) || unlikely(!SourceBitmap->Data) ||
unlikely(!DestinationBitmap) || unlikely(!DestinationBitmap->Data))
return;
// for (uint32_t i = 0; i < SourceBitmap->Width; i++)
// for (uint32_t j = 0; j < SourceBitmap->Height; j++)
// {
// uint32_t *Pixel = (uint32_t *)((uintptr_t)SourceBitmap->Data + (j * SourceBitmap->Width + i) * (SourceBitmap->BitsPerPixel / 8));
// if (IgnoreZero && (*Pixel != 0x000000))
// InlineSetPixel(DestinationBitmap, Left + i, Top + j, *Pixel);
// }
for (uint32_t j = 0; j < SourceBitmap->Height; j++)
{
uint32_t *Pixel = (uint32_t *)((uintptr_t)SourceBitmap->Data + j * SourceBitmap->Width * (SourceBitmap->BitsPerPixel / 8));
if (IgnoreZero)
{
for (uint32_t i = 0; i < SourceBitmap->Width; i++)
{
if (Pixel[i] != 0x000000)
InlineSetPixel(DestinationBitmap, Left + i, Top + j, Pixel[i]);
}
}
else
{
memcpy((void *)((uintptr_t)DestinationBitmap->Data + (Top + j) * DestinationBitmap->Width * (DestinationBitmap->BitsPerPixel / 8) + Left * (DestinationBitmap->BitsPerPixel / 8)),
(void *)((uintptr_t)SourceBitmap->Data + j * SourceBitmap->Width * (SourceBitmap->BitsPerPixel / 8)),
(size_t)(SourceBitmap->Width * (SourceBitmap->BitsPerPixel / 8)));
}
}
}
Ofast void PutRect(ScreenBitmap *Bitmap, Rect rect, uint32_t Color)
{
if (unlikely(!Bitmap))
return;
if (unlikely(!Bitmap->Data))
return;
for (uint32_t i = 0; i < rect.Width; i++)
for (uint32_t j = 0; j < rect.Height; j++)
InlineSetPixel(Bitmap, rect.Left + i, rect.Top + j, Color);
}
void PutBorder(ScreenBitmap *Bitmap, Rect rect, uint32_t Color)
{
if (unlikely(!Bitmap))
return;
if (unlikely(!Bitmap->Data))
return;
for (uint32_t i = 0; i < rect.Width; i++)
{
InlineSetPixel(Bitmap, rect.Left + i, rect.Top, Color);
InlineSetPixel(Bitmap, rect.Left + i, rect.Top + rect.Height - 1, Color);
}
for (uint32_t i = 0; i < rect.Height; i++)
{
InlineSetPixel(Bitmap, rect.Left, rect.Top + i, Color);
InlineSetPixel(Bitmap, rect.Left + rect.Width - 1, rect.Top + i, Color);
}
}
uint32_t BlendColors(uint32_t c1, uint32_t c2, float t)
{
uint8_t r1 = (c1 >> 16) & 0xFF;
uint8_t g1 = (c1 >> 8) & 0xFF;
uint8_t b1 = c1 & 0xFF;
uint8_t r2 = (c2 >> 16) & 0xFF;
uint8_t g2 = (c2 >> 8) & 0xFF;
uint8_t b2 = c2 & 0xFF;
uint8_t r = (uint8_t)(r1 + t * (r2 - r1));
uint8_t g = (uint8_t)(g1 + t * (g2 - g1));
uint8_t b = (uint8_t)(b1 + t * (b2 - b1));
return (r << 16) | (g << 8) | b;
}
void PutBorderWithShadow(ScreenBitmap *Bitmap, Rect rect, uint32_t Color)
{
UNUSED(Bitmap);
UNUSED(rect);
UNUSED(Color);
}
#define SHADOW_SIZE 12
void DrawShadow(ScreenBitmap *Bitmap, Rect rect)
{
UNUSED(Bitmap);
UNUSED(rect);
}
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wstrict-overflow"
void PaintChar(Video::Font *font, ScreenBitmap *Bitmap, char c, uint32_t Color, int64_t *CharCursorX, int64_t *CharCursorY)
{
switch (font->GetInfo().Type)
{
case Video::FontType::PCScreenFont1:
{
// uint32_t *PixelPtr = (uint32_t *)Bitmap->Data;
char *FontPtr = (char *)font->GetInfo().PSF1Font->GlyphBuffer + (c * font->GetInfo().PSF1Font->Header->charsize);
for (int64_t Y = *CharCursorY; Y < *CharCursorY + 16; Y++)
{
for (int64_t X = *CharCursorX; X < *CharCursorX + 8; X++)
if ((*FontPtr & (0b10000000 >> (X - *CharCursorX))) > 0)
InlineSetPixel(Bitmap, X, Y, Color);
FontPtr++;
}
*CharCursorX += 8;
break;
}
case Video::FontType::PCScreenFont2:
{
// if (font->PSF2Font->GlyphBuffer == (uint16_t *)0x01) // HAS UNICODE TABLE
// Char = font->PSF2Font->GlyphBuffer[Char];
int BytesPerLine = (font->GetInfo().PSF2Font->Header->width + 7) / 8;
char *FontPtr = (char *)font->GetInfo().StartAddress +
font->GetInfo().PSF2Font->Header->headersize +
(c > 0 && (unsigned char)c < font->GetInfo().PSF2Font->Header->length ? c : 0) *
font->GetInfo().PSF2Font->Header->charsize;
uint32_t fonthdrWidth = font->GetInfo().PSF2Font->Header->width;
uint32_t fonthdrHeight = font->GetInfo().PSF2Font->Header->height;
for (int64_t Y = *CharCursorY; Y < *CharCursorY + fonthdrHeight; Y++)
{
for (int64_t X = *CharCursorX; X < *CharCursorX + fonthdrWidth; X++)
if ((*FontPtr & (0b10000000 >> (X - *CharCursorX))) > 0)
InlineSetPixel(Bitmap, X, Y, Color);
FontPtr += BytesPerLine;
}
*CharCursorX += fonthdrWidth;
break;
}
default:
warn("Unsupported font type");
break;
}
}
#pragma GCC diagnostic pop
void DrawString(ScreenBitmap *Bitmap, Rect rect, const char *Text, uint32_t Color)
{
UNUSED(Bitmap);
UNUSED(rect);
UNUSED(Text);
UNUSED(Color);
}
}

View File

@ -1,667 +0,0 @@
/*
This file is part of Fennix Kernel.
Fennix Kernel is free software: you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation, either version 3 of
the License, or (at your option) any later version.
Fennix Kernel is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
*/
#include <gui.hpp>
#include <driver.hpp>
#include <task.hpp>
#include <debug.h>
#include "icons.hpp"
#include "../kernel.h"
#include "../DAPI.hpp"
#include "../Fex.hpp"
extern uintptr_t _binary_Files_tamsyn_font_1_11_Tamsyn7x14r_psf_start;
extern uintptr_t _binary_Files_tamsyn_font_1_11_Tamsyn7x14r_psf_end;
extern uintptr_t _binary_Files_tamsyn_font_1_11_Tamsyn7x14r_psf_size;
#ifdef DEBUG
size_t FIi = 0, PDi = 0, PWi = 0, PWWi = 0, PCi = 0, mmi = 0;
#endif
namespace GraphicalUserInterface
{
void GUI::FetchInputs()
{
MouseData Mouse;
bool FoundMouseDriver = false;
if (likely(DriverManager->GetDrivers().size() > 0))
{
foreach (auto Driver in DriverManager->GetDrivers())
{
if (((FexExtended *)Driver.ExtendedHeaderAddress)->Driver.Type == FexDriverType::FexDriverType_Input &&
((FexExtended *)Driver.ExtendedHeaderAddress)->Driver.TypeFlags & FexDriverInputTypes::FexDriverInputTypes_Mouse)
{
#ifdef DEBUG
static int once = 0;
if (!once++)
debug("Found mouse driver %ld", Driver.DriverUID);
#endif
KernelCallback callback{};
callback.Reason = FetchReason;
DriverManager->IOCB(Driver.DriverUID, &callback);
Mouse.X = callback.InputCallback.Mouse.X;
Mouse.Y = callback.InputCallback.Mouse.Y;
Mouse.Z = callback.InputCallback.Mouse.Z;
Mouse.Left = callback.InputCallback.Mouse.Buttons.Left;
Mouse.Right = callback.InputCallback.Mouse.Buttons.Right;
Mouse.Middle = callback.InputCallback.Mouse.Buttons.Middle;
FoundMouseDriver = true;
break;
}
}
}
if (unlikely(!FoundMouseDriver))
{
static int once = 0;
if (!once++)
debug("No mouse driver found.");
Mouse.X = Display->GetBuffer(200)->Width / 2;
Mouse.Y = Display->GetBuffer(200)->Height / 2;
Mouse.Z = 0;
Mouse.Left = false;
Mouse.Right = false;
Mouse.Middle = false;
}
Event eTemplate;
memset(&eTemplate, 0, sizeof(Event));
foreach (auto wnd in this->Windows)
{
/* On mouse down event */
if (unlikely((!MouseArray[1].Left || !MouseArray[1].Right || !MouseArray[1].Middle) &&
(Mouse.Left || Mouse.Right || Mouse.Middle)))
{
eTemplate.MouseDown.X = Mouse.X;
eTemplate.MouseDown.Y = Mouse.Y;
eTemplate.MouseDown.Left = Mouse.Left;
eTemplate.MouseDown.Right = Mouse.Right;
eTemplate.MouseDown.Middle = Mouse.Middle;
wnd->OnMouseDown(&eTemplate);
}
/* On mouse up event */
if (unlikely((MouseArray[1].Left || MouseArray[1].Right || MouseArray[1].Middle) &&
(!Mouse.Left || !Mouse.Right || !Mouse.Middle)))
{
eTemplate.MouseUp.X = Mouse.X;
eTemplate.MouseUp.Y = Mouse.Y;
eTemplate.MouseUp.Left = Mouse.Left;
eTemplate.MouseUp.Right = Mouse.Right;
eTemplate.MouseUp.Middle = Mouse.Middle;
wnd->OnMouseUp(&eTemplate);
}
static int Idle = 0;
if (likely(Mouse.X != MouseArray[1].X || Mouse.Y != MouseArray[1].Y))
{
Idle = 0;
Rect TopBarPos = wnd->GetPosition();
TopBarPos.Top -= 20;
TopBarPos.Height = 20;
TopBarPos.Width -= 60; /* buttons */
if (unlikely((int64_t)TopBarPos.Top < 0))
{
TopBarPos.Top = 0;
wnd->GetPositionPtr()->Top = 20;
}
Rect ResizeHintPos = wnd->GetPosition();
ResizeHintPos.Left += ResizeHintPos.Width - 20;
ResizeHintPos.Top += ResizeHintPos.Height - 20;
ResizeHintPos.Width = 20;
ResizeHintPos.Height = 20;
if (unlikely(TopBarPos.Contains(Mouse.X, Mouse.Y) ||
TopBarPos.Contains(MouseArray[0].X, MouseArray[0].Y) ||
TopBarPos.Contains(MouseArray[1].X, MouseArray[1].Y)))
{
if (likely(Mouse.Left))
{
if (likely(MouseArray[1].Left))
{
wnd->GetPositionPtr()->Left += Mouse.X - MouseArray[0].X;
wnd->GetPositionPtr()->Top += Mouse.Y - MouseArray[0].Y;
OverlayBufferRepaint = true;
OverlayFullRepaint = true;
}
}
}
if (ResizeHintPos.Contains(Mouse.X, Mouse.Y) ||
ResizeHintPos.Contains(MouseArray[0].X, MouseArray[0].Y) ||
ResizeHintPos.Contains(MouseArray[1].X, MouseArray[1].Y))
{
if (Mouse.Left)
{
if (MouseArray[1].Left)
{
wnd->GetPositionPtr()->Width += (size_t)(Mouse.X - MouseArray[0].X);
wnd->GetPositionPtr()->Height += (size_t)(Mouse.Y - MouseArray[0].Y);
if (wnd->GetPositionPtr()->Width < 200)
{
wnd->GetPositionPtr()->Width = 200;
Mouse.X = MouseArray[0].X;
}
if (wnd->GetPositionPtr()->Height < 100)
{
wnd->GetPositionPtr()->Height = 100;
Mouse.Y = MouseArray[0].Y;
}
OverlayBufferRepaint = true;
OverlayFullRepaint = true;
eTemplate.Resize.Width = wnd->GetPosition().Width;
eTemplate.Resize.Height = wnd->GetPosition().Height;
wnd->OnResize(&eTemplate);
}
}
if (unlikely(Cursor != CursorType::ResizeAll))
{
Cursor = CursorType::ResizeAll;
CursorBufferRepaint = true;
}
}
else
{
if (unlikely(Cursor != CursorType::Arrow))
{
Cursor = CursorType::Arrow;
CursorBufferRepaint = true;
}
}
eTemplate.MouseMove.X = Mouse.X;
eTemplate.MouseMove.Y = Mouse.Y;
eTemplate.MouseMove.Left = Mouse.Left;
eTemplate.MouseMove.Right = Mouse.Right;
eTemplate.MouseMove.Middle = Mouse.Middle;
wnd->OnMouseMove(&eTemplate);
}
else
{
if (unlikely(Idle > 1000))
CPU::Pause();
else
Idle++;
}
}
foreach (auto wdg in this->Widgets)
{
// TODO: Implement mouse events for widgets
UNUSED(wdg);
}
memmove(MouseArray + 1, MouseArray, sizeof(MouseArray) - sizeof(MouseArray[1]));
MouseArray[0] = Mouse;
LastCursor = Cursor;
}
void GUI::PaintDesktop()
{
if (DesktopBufferRepaint)
{
// PutRect(this->DesktopBuffer, this->Desktop, 0x404040);
memset(this->DesktopBuffer->Data, 0x404040, this->DesktopBuffer->Size);
DesktopBufferRepaint = false;
}
// Well... I have to do some code optimization on DrawOverBitmap. It's too slow and it's not even using SIMD
memcpy(this->BackBuffer->Data, this->DesktopBuffer->Data, this->DesktopBuffer->Size);
}
void GUI::PaintWidgets()
{
Event eTemplate;
memset(&eTemplate, 0, sizeof(Event));
foreach (auto wdg in this->Widgets)
wdg->OnPaint(nullptr);
}
void GUI::PaintWindows()
{
foreach (auto wnd in this->Windows)
{
ScreenBitmap *wndBuffer = wnd->GetBuffer();
if (unlikely(wndBuffer == nullptr)) // I think "unlikely" is not needed here
continue;
Rect WndPos = wnd->GetPosition();
// Draw window content
DrawOverBitmap(this->BackBuffer,
wndBuffer,
WndPos.Top,
WndPos.Left);
/* We can't use memcpy because the window buffer
is not the same size as the screen buffer
https://i.imgur.com/OHfaYnS.png */
// memcpy(this->BackBuffer->Data + wnd->GetPositionPtr()->Top * this->BackBuffer->Width + wnd->GetPositionPtr()->Left, wndBuffer->Data, wndBuffer->Size);
Rect TopBarPos = WndPos;
TopBarPos.Top -= 20;
TopBarPos.Height = 20;
if ((int64_t)TopBarPos.Top < 0)
{
TopBarPos.Top = 0;
wnd->GetPositionPtr()->Top = 20;
}
Rect CloseButtonPos;
Rect MinimizeButtonPos;
CloseButtonPos.Left = TopBarPos.Left + TopBarPos.Width - 20;
CloseButtonPos.Top = TopBarPos.Top;
CloseButtonPos.Width = 20;
CloseButtonPos.Height = 20;
MinimizeButtonPos.Left = TopBarPos.Left + TopBarPos.Width - 60;
if (unlikely(MouseArray[0].X >= (size_t)MinimizeButtonPos.Left &&
MouseArray[0].X <= (size_t)CloseButtonPos.Left + CloseButtonPos.Width &&
MouseArray[0].Y >= (size_t)CloseButtonPos.Top &&
MouseArray[0].Y <= (size_t)CloseButtonPos.Top + CloseButtonPos.Height))
{
OverlayBufferRepaint = true;
}
// Title bar
if (unlikely(OverlayBufferRepaint))
{
if (OverlayFullRepaint)
{
memset(this->OverlayBuffer->Data, 0, this->OverlayBuffer->Size);
OverlayFullRepaint = false;
}
static bool RepaintNeeded = false;
DrawShadow(this->OverlayBuffer, wnd->GetPosition());
Rect MaximizeButtonPos;
MaximizeButtonPos.Left = TopBarPos.Left + TopBarPos.Width - 40;
MaximizeButtonPos.Top = TopBarPos.Top;
MaximizeButtonPos.Width = 20;
MaximizeButtonPos.Height = 20;
MinimizeButtonPos.Top = TopBarPos.Top;
MinimizeButtonPos.Width = 20;
MinimizeButtonPos.Height = 20;
PutRect(this->OverlayBuffer, TopBarPos, 0x282828);
// Title bar buttons (close, minimize, maximize) on the right
if (MouseArray[0].X >= (size_t)CloseButtonPos.Left &&
MouseArray[0].X <= (size_t)CloseButtonPos.Left + CloseButtonPos.Width &&
MouseArray[0].Y >= (size_t)CloseButtonPos.Top &&
MouseArray[0].Y <= (size_t)CloseButtonPos.Top + CloseButtonPos.Height)
{
PutRect(this->OverlayBuffer, CloseButtonPos, MouseArray[0].Left ? 0xFF5500 : 0xFF0000);
RepaintNeeded = true;
}
else
{
PutRect(this->OverlayBuffer, MaximizeButtonPos, 0x282828);
}
if (MouseArray[0].X >= (size_t)MaximizeButtonPos.Left &&
MouseArray[0].X <= (size_t)MaximizeButtonPos.Left + MaximizeButtonPos.Width &&
MouseArray[0].Y >= (size_t)MaximizeButtonPos.Top &&
MouseArray[0].Y <= (size_t)MaximizeButtonPos.Top + MaximizeButtonPos.Height)
{
PutRect(this->OverlayBuffer, MaximizeButtonPos, MouseArray[0].Left ? 0x454545 : 0x404040);
RepaintNeeded = true;
}
else
{
PutRect(this->OverlayBuffer, MaximizeButtonPos, 0x282828);
}
if (MouseArray[0].X >= (size_t)MinimizeButtonPos.Left &&
MouseArray[0].X <= (size_t)MinimizeButtonPos.Left + MinimizeButtonPos.Width &&
MouseArray[0].Y >= (size_t)MinimizeButtonPos.Top &&
MouseArray[0].Y <= (size_t)MinimizeButtonPos.Top + MinimizeButtonPos.Height)
{
PutRect(this->OverlayBuffer, MinimizeButtonPos, MouseArray[0].Left ? 0x454545 : 0x404040);
RepaintNeeded = true;
}
else
{
PutRect(this->OverlayBuffer, MinimizeButtonPos, 0x282828);
}
// Title bar icons (close, minimize, maximize) on the right
for (short i = 0; i < 20; i++)
{
for (short j = 0; j < 20; j++)
{
if (CloseButton[i * 20 + j] == 1)
SetPixel(this->OverlayBuffer,
CloseButtonPos.Left + j,
CloseButtonPos.Top + i,
0xFFFFFF);
if ((MaximizeButtonMaximized[i * 20 + j] == 1) && !wnd->IsMaximized())
SetPixel(this->OverlayBuffer,
MaximizeButtonPos.Left + j,
MaximizeButtonPos.Top + i,
0xFFFFFF);
else if ((MaximizeButtonNormal[i * 20 + j] == 1) && wnd->IsMaximized())
SetPixel(this->OverlayBuffer,
MaximizeButtonPos.Left + j,
MaximizeButtonPos.Top + i,
0xFFFFFF);
if (MinimizeButton[i * 20 + j] == 1)
SetPixel(this->OverlayBuffer,
MinimizeButtonPos.Left + j,
MinimizeButtonPos.Top + i,
0xFFFFFF);
}
}
Rect wndPos = wnd->GetPosition();
// Resize hint
for (short i = 0; i < 20; i++)
for (short j = 0; j < 20; j++)
if (ResizeHint[i * 20 + j] == 1)
SetPixel(this->OverlayBuffer, wndPos.Left + wndPos.Width - 20 + j, wndPos.Top + wndPos.Height - 20 + i, 0xFFFFFF);
// Title bar border
PutBorder(this->OverlayBuffer, TopBarPos, 0xFF000000);
// Window border
PutBorder(this->OverlayBuffer, wndPos, 0xFF000000);
Rect TopBarTextPos = TopBarPos;
TopBarTextPos.Left += 4;
TopBarTextPos.Top += 4;
// Title bar text
int64_t CharCursorX = TopBarTextPos.Left;
int64_t CharCursorY = TopBarTextPos.Top;
for (uint64_t i = 0; i < strlen(wnd->GetTitle()); i++)
PaintChar(this->CurrentFont, this->OverlayBuffer, wnd->GetTitle()[i], 0xFFFFFF, &CharCursorX, &CharCursorY);
if (!RepaintNeeded)
{
OverlayBufferRepaint = false;
RepaintNeeded = false;
}
}
wnd->OnPaint(nullptr);
}
DrawOverBitmap(this->BackBuffer, this->OverlayBuffer, 0, 0);
}
/*
"* 2" to increase the size of the cursor
"/ 2" to decrease the size of the cursor
*/
#define ICON_SIZE
void GUI::PaintCursor()
{
uint32_t CursorColorInner = 0xFFFFFFFF;
uint32_t CursorColorOuter = 0xFF000000;
if (MouseArray[0].X != MouseArray[1].X ||
MouseArray[0].Y != MouseArray[1].Y ||
MouseArray[0].Z != MouseArray[1].Z ||
Cursor != LastCursor)
CursorBufferRepaint = true;
if (CursorBufferRepaint)
{
memset(this->CursorBuffer->Data, 0, this->CursorBuffer->Size);
switch (this->Cursor)
{
case CursorType::Visible:
{
CursorVisible = true;
break;
}
case CursorType::Hidden:
{
CursorVisible = false;
break;
}
default:
fixme("Unknown cursor type %d", this->Cursor);
[[fallthrough]];
case CursorType::Arrow:
{
if (CursorVisible)
for (int i = 0; i < 19; i++)
{
for (int j = 0; j < 12; j++)
{
if (CursorArrow[i * 12 + j] == 1)
{
SetPixel(this->CursorBuffer, j ICON_SIZE, i ICON_SIZE, CursorColorOuter);
}
else if (CursorArrow[i * 12 + j] == 2)
{
SetPixel(this->CursorBuffer, j ICON_SIZE, i ICON_SIZE, CursorColorInner);
}
}
}
break;
}
case CursorType::Hand:
{
if (CursorVisible)
for (int i = 0; i < 24; i++)
{
for (int j = 0; j < 17; j++)
{
if (CursorHand[i * 17 + j] == 1)
{
SetPixel(this->CursorBuffer, j ICON_SIZE, i ICON_SIZE, CursorColorOuter);
}
else if (CursorHand[i * 17 + j] == 2)
{
SetPixel(this->CursorBuffer, j ICON_SIZE, i ICON_SIZE, CursorColorInner);
}
}
}
break;
}
case CursorType::Wait:
{
if (CursorVisible)
for (int i = 0; i < 22; i++)
{
for (int j = 0; j < 13; j++)
{
if (CursorWait[i * 13 + j] == 1)
{
SetPixel(this->CursorBuffer, j ICON_SIZE, i ICON_SIZE, CursorColorOuter);
}
else if (CursorWait[i * 13 + j] == 2)
{
SetPixel(this->CursorBuffer, j ICON_SIZE, i ICON_SIZE, CursorColorInner);
}
}
}
break;
}
case CursorType::IBeam:
{
if (CursorVisible)
for (int i = 0; i < 22; i++)
{
for (int j = 0; j < 13; j++)
{
if (CursorIBeam[i * 13 + j] == 1)
{
SetPixel(this->CursorBuffer, j ICON_SIZE, i ICON_SIZE, CursorColorOuter);
}
else if (CursorIBeam[i * 13 + j] == 2)
{
SetPixel(this->CursorBuffer, j ICON_SIZE, i ICON_SIZE, CursorColorInner);
}
}
}
break;
}
case CursorType::ResizeAll:
{
if (CursorVisible)
for (int i = 0; i < 23; i++)
{
for (int j = 0; j < 23; j++)
{
if (CursorResizeAll[i * 23 + j] == 1)
{
SetPixel(this->CursorBuffer, j ICON_SIZE, i ICON_SIZE, CursorColorOuter);
}
else if (CursorResizeAll[i * 23 + j] == 2)
{
SetPixel(this->CursorBuffer, j ICON_SIZE, i ICON_SIZE, CursorColorInner);
}
}
}
break;
}
}
CursorBufferRepaint = false;
}
DrawOverBitmap(this->BackBuffer, this->CursorBuffer, MouseArray[0].Y, MouseArray[0].X);
}
void GUI::Loop()
{
/*
Because we do not use a gpu to do the rendering, we need to do it manually.
This is why the mouse is slow when we have to draw a bunch of things.
*/
while (IsRunning)
{
#ifdef DEBUG
FIi = CPU::Counter();
#endif
FetchInputs();
#ifdef DEBUG
FIi = CPU::Counter() - FIi;
PDi = CPU::Counter();
#endif
PaintDesktop();
#ifdef DEBUG
PDi = CPU::Counter() - PDi;
PWi = CPU::Counter();
#endif
PaintWidgets();
#ifdef DEBUG
PWi = CPU::Counter() - PWi;
PWWi = CPU::Counter();
#endif
PaintWindows();
#ifdef DEBUG
PWWi = CPU::Counter() - PWWi;
PCi = CPU::Counter();
#endif
PaintCursor();
#ifdef DEBUG
PCi = CPU::Counter() - PCi;
mmi = CPU::Counter();
#endif
memcpy(Display->GetBuffer(200)->Buffer, this->BackBuffer->Data, this->BackBuffer->Size);
Display->SetBuffer(200);
#ifdef DEBUG
mmi = CPU::Counter() - mmi;
#endif
}
}
void GUI::AddWindow(Window *window)
{
this->Windows.push_back(window);
}
void GUI::AddWidget(WidgetCollection *widget)
{
this->Widgets.push_back(widget);
}
GUI::GUI()
{
Display->CreateBuffer(0, 0, 200);
this->CurrentFont = new Video::Font(&_binary_Files_tamsyn_font_1_11_Tamsyn7x14r_psf_start, &_binary_Files_tamsyn_font_1_11_Tamsyn7x14r_psf_end, Video::FontType::PCScreenFont2);
this->mem = new Memory::MemMgr;
this->Desktop.Top = 0;
this->Desktop.Left = 0;
this->Desktop.Width = Display->GetBuffer(200)->Width;
this->Desktop.Height = Display->GetBuffer(200)->Height;
this->BackBuffer = new ScreenBitmap;
this->BackBuffer->Width = this->Desktop.Width;
this->BackBuffer->Height = this->Desktop.Height;
this->BackBuffer->BitsPerPixel = Display->GetBitsPerPixel();
this->BackBuffer->Pitch = Display->GetPitch();
this->BackBuffer->Size = Display->GetBuffer(200)->Size;
this->BackBuffer->Data = (uint8_t *)this->mem->RequestPages(TO_PAGES(this->BackBuffer->Size + 1));
memset(this->BackBuffer->Data, 0, this->BackBuffer->Size);
this->DesktopBuffer = new ScreenBitmap;
this->DesktopBuffer->Width = this->Desktop.Width;
this->DesktopBuffer->Height = this->Desktop.Height;
this->DesktopBuffer->BitsPerPixel = Display->GetBitsPerPixel();
this->DesktopBuffer->Pitch = Display->GetPitch();
this->DesktopBuffer->Size = Display->GetBuffer(200)->Size;
this->DesktopBuffer->Data = (uint8_t *)this->mem->RequestPages(TO_PAGES(this->DesktopBuffer->Size + 1));
memset(this->DesktopBuffer->Data, 0, this->DesktopBuffer->Size);
this->OverlayBuffer = new ScreenBitmap;
this->OverlayBuffer->Width = this->Desktop.Width;
this->OverlayBuffer->Height = this->Desktop.Height;
this->OverlayBuffer->BitsPerPixel = Display->GetBitsPerPixel();
this->OverlayBuffer->Pitch = Display->GetPitch();
this->OverlayBuffer->Size = Display->GetBuffer(200)->Size;
this->OverlayBuffer->Data = (uint8_t *)this->mem->RequestPages(TO_PAGES(this->OverlayBuffer->Size + 1));
memset(this->OverlayBuffer->Data, 0, this->OverlayBuffer->Size);
this->CursorBuffer = new ScreenBitmap;
this->CursorBuffer->Width = 25;
this->CursorBuffer->Height = 25;
this->CursorBuffer->BitsPerPixel = Display->GetBitsPerPixel();
this->CursorBuffer->Pitch = Display->GetPitch();
this->CursorBuffer->Size = (size_t)(this->CursorBuffer->Width * this->CursorBuffer->Height * (this->CursorBuffer->BitsPerPixel / 8));
this->CursorBuffer->Data = (uint8_t *)this->mem->RequestPages(TO_PAGES(this->CursorBuffer->Size + 1));
memset(this->CursorBuffer->Data, 0, this->CursorBuffer->Size);
this->IsRunning = true;
}
GUI::~GUI()
{
debug("Destructor called");
delete this->mem, this->mem = nullptr;
delete this->BackBuffer, this->BackBuffer = nullptr;
delete this->DesktopBuffer, this->DesktopBuffer = nullptr;
delete this->OverlayBuffer, this->OverlayBuffer = nullptr;
delete this->CursorBuffer, this->CursorBuffer = nullptr;
Display->DeleteBuffer(200);
this->Windows.clear();
}
}

View File

@ -1,253 +0,0 @@
/*
This file is part of Fennix Kernel.
Fennix Kernel is free software: you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation, either version 3 of
the License, or (at your option) any later version.
Fennix Kernel is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
*/
#include "icons.hpp"
char CursorArrow[] = {
1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 12x19
1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //
1, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, //
1, 2, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, //
1, 2, 2, 2, 1, 0, 0, 0, 0, 0, 0, 0, //
1, 2, 2, 2, 2, 1, 0, 0, 0, 0, 0, 0, //
1, 2, 2, 2, 2, 2, 1, 0, 0, 0, 0, 0, //
1, 2, 2, 2, 2, 2, 2, 1, 0, 0, 0, 0, //
1, 2, 2, 2, 2, 2, 2, 2, 1, 0, 0, 0, //
1, 2, 2, 2, 2, 2, 2, 2, 2, 1, 0, 0, //
1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 0, //
1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, //
1, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, //
1, 2, 2, 2, 1, 2, 2, 1, 0, 0, 0, 0, //
1, 2, 2, 1, 0, 1, 2, 2, 1, 0, 0, 0, //
1, 2, 1, 0, 0, 1, 2, 2, 1, 0, 0, 0, //
1, 1, 0, 0, 0, 0, 1, 2, 2, 1, 0, 0, //
1, 0, 0, 0, 0, 0, 1, 2, 2, 1, 0, 0, //
0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, //
};
char CursorHand[] = {
0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 17x24
0, 0, 0, 0, 1, 2, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, //
0, 0, 0, 0, 1, 2, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, //
0, 0, 0, 0, 1, 2, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, //
0, 0, 0, 0, 1, 2, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, //
0, 0, 0, 0, 1, 2, 2, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, //
0, 0, 0, 0, 1, 2, 2, 1, 2, 2, 1, 1, 1, 0, 0, 0, 0, //
0, 0, 0, 0, 1, 2, 2, 1, 2, 2, 1, 2, 2, 1, 1, 0, 0, //
0, 0, 0, 0, 1, 2, 2, 1, 2, 2, 1, 2, 2, 1, 2, 1, 0, //
0, 0, 0, 0, 1, 2, 2, 1, 2, 2, 1, 2, 2, 1, 2, 2, 1, //
1, 1, 1, 0, 1, 2, 2, 1, 2, 2, 1, 2, 2, 1, 2, 2, 1, //
1, 2, 2, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 1, 2, 2, 1, //
1, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, //
0, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, //
0, 0, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, //
0, 0, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, //
0, 0, 0, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, //
0, 0, 0, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 0, //
0, 0, 0, 0, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 0, //
0, 0, 0, 0, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 0, //
0, 0, 0, 0, 0, 1, 2, 2, 2, 2, 2, 2, 2, 2, 1, 0, 0, //
0, 0, 0, 0, 0, 1, 2, 2, 2, 2, 2, 2, 2, 2, 1, 0, 0, //
0, 0, 0, 0, 0, 1, 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, //
};
char CursorWait[] = {
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 13x22
1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, //
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, //
0, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 0, //
0, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 0, //
0, 1, 2, 2, 1, 2, 1, 2, 1, 2, 2, 1, 0, //
0, 1, 2, 2, 2, 1, 2, 1, 2, 2, 2, 1, 0, //
0, 1, 1, 2, 2, 2, 1, 2, 2, 2, 1, 1, 0, //
0, 0, 1, 1, 2, 2, 2, 2, 2, 1, 1, 0, 0, //
0, 0, 0, 1, 1, 2, 1, 2, 1, 1, 0, 0, 0, //
0, 0, 0, 0, 1, 1, 2, 1, 1, 0, 0, 0, 0, //
0, 0, 0, 0, 1, 1, 2, 1, 1, 0, 0, 0, 0, //
0, 0, 0, 1, 1, 2, 2, 2, 1, 1, 0, 0, 0, //
0, 0, 1, 1, 2, 2, 1, 2, 2, 1, 1, 0, 0, //
0, 1, 1, 2, 2, 2, 2, 2, 2, 2, 1, 1, 0, //
0, 1, 2, 2, 2, 2, 1, 2, 2, 2, 2, 1, 0, //
0, 1, 2, 2, 2, 1, 2, 1, 2, 2, 2, 1, 0, //
0, 1, 2, 2, 1, 2, 1, 2, 1, 2, 2, 1, 0, //
0, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 0, //
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, //
1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, //
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, //
};
char CursorIBeam[] = {
1, 1, 1, 0, 1, 1, 1, // 7x17
0, 0, 0, 1, 0, 0, 0, //
0, 0, 0, 1, 0, 0, 0, //
0, 0, 0, 1, 0, 0, 0, //
0, 0, 0, 1, 0, 0, 0, //
0, 0, 0, 1, 0, 0, 0, //
0, 0, 0, 1, 0, 0, 0, //
0, 0, 0, 1, 0, 0, 0, //
0, 0, 0, 1, 0, 0, 0, //
0, 0, 0, 1, 0, 0, 0, //
0, 0, 0, 1, 0, 0, 0, //
0, 0, 0, 1, 0, 0, 0, //
0, 0, 0, 1, 0, 0, 0, //
0, 0, 0, 1, 0, 0, 0, //
0, 0, 0, 1, 0, 0, 0, //
0, 0, 0, 1, 0, 0, 0, //
1, 1, 1, 0, 1, 1, 1, //
};
char CursorResizeAll[] = {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 23x23
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //
0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 2, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, //
0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 2, 2, 2, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, //
0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, //
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //
0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 2, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, //
0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 2, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, //
0, 0, 1, 2, 1, 0, 0, 0, 0, 0, 1, 2, 1, 0, 0, 0, 0, 0, 1, 2, 1, 0, 0, //
0, 1, 2, 2, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 2, 2, 1, 0, //
1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, //
0, 1, 2, 2, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 2, 2, 1, 0, //
0, 0, 1, 2, 1, 0, 0, 0, 0, 0, 1, 2, 1, 0, 0, 0, 0, 0, 1, 2, 1, 0, 0, //
0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 2, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, //
0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 2, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, //
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 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, 1, 2, 2, 2, 2, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, //
0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 2, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, //
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 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, 0, 0, //
};
char CloseButton[] = {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //
0, 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, 0, 0, 0, 0, 0, //
0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, //
0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 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, 0, 0, //
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, 1, 1, 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, 0, 0, //
0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, //
0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, //
0, 0, 0, 0, 0, 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, 0, 0, 0, 0, 0, 0, 0, 0, //
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 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 MinimizeButton[] = {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //
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, 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, 0, 0, //
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 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 MaximizeButtonNormal[] = {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //
0, 0, 0, 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, //
0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, //
0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 0, 0, 0, 0, //
0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, //
0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, //
0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, //
0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, //
0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, //
0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 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, 0, 0, //
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 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 MaximizeButtonMaximized[] = {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //
0, 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, 1, 0, 0, 0, 0, 0, //
0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, //
0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, //
0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, //
0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, //
0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, //
0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, //
0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, //
0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, //
0, 0, 0, 0, 0, 1, 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 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 ResizeHint[] = {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 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, 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, 1, 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, 0, 0, 0, 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, 1, 0, 0, 1, 0, 0, 0, 0, //
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, //
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, //
0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, //
0, 0, 0, 0, 0, 0, 0, 0, 1, 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, 0, 0, //
};

View File

@ -1,159 +0,0 @@
/*
This file is part of Fennix Kernel.
Fennix Kernel is free software: you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation, either version 3 of
the License, or (at your option) any later version.
Fennix Kernel is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
*/
#include <gui.hpp>
#include <driver.hpp>
#include <task.hpp>
#include <printf.h>
#include <debug.h>
#include "../kernel.h"
#include "../DAPI.hpp"
#include "../Fex.hpp"
namespace GraphicalUserInterface
{
void WidgetCollection::OnPaintBackground(Event *e)
{
UNUSED(e);
}
void WidgetCollection::OnPaintForeground(Event *e)
{
UNUSED(e);
foreach (auto Panel in this->Panels)
{
PutRect(this->Buffer, Panel->rect, Panel->Color);
}
foreach (auto Label in this->Labels)
{
Label->CharCursorX = Label->rect.Left;
Label->CharCursorY = Label->rect.Top;
for (uint64_t i = 0; i < strlen(Label->Text); i++)
PaintChar(this->CurrentFont, this->Buffer, Label->Text[i], 0xFFFFFF, &Label->CharCursorX, &Label->CharCursorY);
}
foreach (auto Button in this->Buttons)
{
if (Button->Pressed)
PutRect(this->Buffer, Button->rect, Button->PressedColor);
else if (Button->Hover)
PutRect(this->Buffer, Button->rect, Button->HoverColor);
else
PutRect(this->Buffer, Button->rect, Button->Color);
Button->CharCursorX = Button->rect.Left + (((Button->rect.Width / 2) - (this->CurrentFont->GetInfo().Width * strlen(Button->Text) / 2)));
Button->CharCursorY = Button->rect.Top + (((Button->rect.Height / 2) - (this->CurrentFont->GetInfo().Height / 2)));
for (uint64_t i = 0; i < strlen(Button->Text); i++)
PaintChar(this->CurrentFont, this->Buffer, Button->Text[i], 0xFFFFFF, &Button->CharCursorX, &Button->CharCursorY);
}
}
void WidgetCollection::OnPaint(Event *e)
{
static size_t LastWidth = 0;
static size_t LastHeight = 0;
if (LastWidth != ((Window *)this->ParentWindow)->GetPosition().Width ||
LastHeight != ((Window *)this->ParentWindow)->GetPosition().Height)
{
LastWidth = ((Window *)this->ParentWindow)->GetPosition().Width;
LastHeight = ((Window *)this->ParentWindow)->GetPosition().Height;
this->mem->FreePages(this->Buffer->Data, TO_PAGES(this->Buffer->Size + 1));
this->Buffer->Data = nullptr;
delete this->Buffer, this->Buffer = nullptr;
this->Buffer = new ScreenBitmap;
this->Buffer->Width = LastWidth;
this->Buffer->Height = LastHeight;
this->Buffer->BitsPerPixel = Display->GetBitsPerPixel();
this->Buffer->Pitch = Display->GetPitch();
this->Buffer->Size = this->Buffer->Pitch * (size_t)LastHeight;
this->Buffer->Data = (uint8_t *)this->mem->RequestPages(TO_PAGES(this->Buffer->Size + 1));
memset(this->Buffer->Data, 0, this->Buffer->Size);
this->NeedRedraw = true;
}
if (this->NeedRedraw)
{
memset(this->Buffer->Data, 0, this->Buffer->Size);
this->OnPaintBackground(e);
this->OnPaintForeground(e);
this->NeedRedraw = false;
}
DrawOverBitmap(((Window *)this->ParentWindow)->GetBuffer(), this->Buffer, 0, 0);
}
void WidgetCollection::OnMouseDown(Event *e)
{
foreach (auto Button in this->Buttons)
{
if (Button->rect.Contains(e->MouseDown.X, e->MouseDown.Y))
{
if (e->MouseDown.Left)
{
debug("Button Hold");
Button->Pressed = true;
this->NeedRedraw = true;
}
}
}
}
void WidgetCollection::OnMouseUp(Event *e)
{
foreach (auto Button in this->Buttons)
{
if (Button->rect.Contains(e->MouseUp.X, e->MouseUp.Y))
{
if (e->MouseUp.Left)
{
debug("Button Release");
if (Button->Pressed)
{
debug("Button Clicked");
if (Button->OnClick != (uintptr_t) nullptr)
((void (*)(void))Button->OnClick)();
Button->Pressed = false;
this->NeedRedraw = true;
}
}
}
}
}
void WidgetCollection::OnMouseMove(Event *e)
{
foreach (auto Button in this->Buttons)
{
if (Button->rect.Contains(e->MouseMove.X, e->MouseMove.Y))
{
Button->Hover = true;
this->NeedRedraw = true;
}
else
{
Button->Hover = false;
this->NeedRedraw = true;
}
}
}
}

View File

@ -1,141 +0,0 @@
/*
This file is part of Fennix Kernel.
Fennix Kernel is free software: you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation, either version 3 of
the License, or (at your option) any later version.
Fennix Kernel is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
*/
#include <gui.hpp>
#include <driver.hpp>
#include <task.hpp>
#include <printf.h>
#include <debug.h>
#include "../kernel.h"
#include "../DAPI.hpp"
#include "../Fex.hpp"
extern uintptr_t _binary_Files_tamsyn_font_1_11_Tamsyn10x20r_psf_start;
extern uintptr_t _binary_Files_tamsyn_font_1_11_Tamsyn10x20r_psf_end;
extern uintptr_t _binary_Files_tamsyn_font_1_11_Tamsyn10x20r_psf_size;
namespace GraphicalUserInterface
{
Handle WidgetCollection::CreatePanel(Rect rect, uint32_t Color)
{
PanelObject *panel = (PanelObject *)this->mem->RequestPages(TO_PAGES(sizeof(PanelObject) + 1));
panel->Handle.Type[0] = 'P';
panel->Handle.Type[1] = 'N';
panel->Handle.Type[2] = 'L';
panel->Handle.Type[3] = '\0';
panel->rect = rect;
panel->Color = Color;
panel->BorderColor = 0xFF000000;
panel->ShadowColor = 0xFF000000;
panel->Shadow = false;
Panels.push_back(panel);
this->NeedRedraw = true;
return (Handle)panel;
}
Handle WidgetCollection::CreateLabel(Rect rect, const char *Text)
{
LabelObject *label = (LabelObject *)this->mem->RequestPages(TO_PAGES(sizeof(LabelObject) + 1));
label->Handle.Type[0] = 'L';
label->Handle.Type[1] = 'B';
label->Handle.Type[2] = 'L';
label->Handle.Type[3] = '\0';
label->rect = rect;
strcpy(label->Text, Text);
label->Color = 0xFFFFFF;
label->CharCursorX = rect.Left;
label->CharCursorY = rect.Top;
Labels.push_back(label);
NeedRedraw = true;
return (Handle)label;
}
Handle WidgetCollection::CreateButton(Rect rect, const char *Text, uintptr_t OnClick)
{
ButtonObject *button = (ButtonObject *)this->mem->RequestPages(TO_PAGES(sizeof(ButtonObject) + 1));
button->Handle.Type[0] = 'B';
button->Handle.Type[1] = 'T';
button->Handle.Type[2] = 'N';
button->Handle.Type[3] = '\0';
button->rect = rect;
strcpy(button->Text, Text);
button->Color = 0x252525;
button->HoverColor = 0x353535;
button->PressedColor = 0x555555;
button->BorderColor = 0xFF000000;
button->ShadowColor = 0xFF000000;
button->Shadow = false;
button->Hover = false;
button->Pressed = false;
button->OnClick = OnClick;
Buttons.push_back(button);
this->NeedRedraw = true;
return (Handle)button;
}
void WidgetCollection::SetText(Handle handle, const char *Text)
{
HandleMeta *meta = (HandleMeta *)handle;
if (meta->Type[0] == 'L' && meta->Type[1] == 'B' && meta->Type[2] == 'L')
{
LabelObject *label = (LabelObject *)handle;
strcpy(label->Text, Text);
this->NeedRedraw = true;
}
}
WidgetCollection::WidgetCollection(void *ParentWindow)
{
if (!ParentWindow)
{
error("ParentWindow is null");
return;
}
this->ParentWindow = ParentWindow;
this->mem = new Memory::MemMgr;
this->Buffer = new ScreenBitmap;
this->Buffer->Width = ((Window *)this->ParentWindow)->GetPosition().Width;
this->Buffer->Height = ((Window *)this->ParentWindow)->GetPosition().Height;
this->Buffer->BitsPerPixel = Display->GetBitsPerPixel();
this->Buffer->Pitch = Display->GetPitch();
this->Buffer->Size = (size_t)(this->Buffer->Pitch * ((Window *)this->ParentWindow)->GetPosition().Height);
this->Buffer->Data = (uint8_t *)this->mem->RequestPages(TO_PAGES(this->Buffer->Size + 1));
memset(this->Buffer->Data, 0, this->Buffer->Size);
this->CurrentFont = new Video::Font(&_binary_Files_tamsyn_font_1_11_Tamsyn10x20r_psf_start, &_binary_Files_tamsyn_font_1_11_Tamsyn10x20r_psf_end, Video::FontType::PCScreenFont2);
}
WidgetCollection::~WidgetCollection()
{
delete this->mem, this->mem = nullptr;
delete this->Buffer, this->Buffer = nullptr;
delete this->CurrentFont, this->CurrentFont = nullptr;
}
}

View File

@ -1,82 +0,0 @@
/*
This file is part of Fennix Kernel.
Fennix Kernel is free software: you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation, either version 3 of
the License, or (at your option) any later version.
Fennix Kernel is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
*/
#include <gui.hpp>
#include <driver.hpp>
#include <task.hpp>
#include <printf.h>
#include <debug.h>
#include "../kernel.h"
#include "../DAPI.hpp"
#include "../Fex.hpp"
namespace GraphicalUserInterface
{
#define TASKBAR_HEIGHT 25
// if (!Maximized)
// {
// this->LastPosition.Left = this->Position.Left;
// this->LastPosition.Top = this->Position.Top;
// this->LastPosition.Width = this->Position.Width;
// this->LastPosition.Height = this->Position.Height;
// this->Position.Left = 0;
// this->Position.Top = 0;
// this->Position.Width = Display->GetBuffer(200)->Width;
// this->Position.Height = Display->GetBuffer(200)->Height - 20 - TASKBAR_HEIGHT;
// Maximized = true;
// }
// else
// {
// this->Position.Left = this->LastPosition.Left;
// this->Position.Top = this->LastPosition.Top;
// this->Position.Width = this->LastPosition.Width;
// this->Position.Height = this->LastPosition.Height;
// Maximized = false;
// }
void Window::AddWidget(WidgetCollection *widget)
{
this->Widgets.push_back(widget);
}
Window::Window(void *ParentGUI, Rect rect, const char *Title)
{
this->mem = new Memory::MemMgr;
this->Buffer = new ScreenBitmap;
this->Buffer->Width = rect.Width;
this->Buffer->Height = rect.Height;
this->Buffer->BitsPerPixel = Display->GetBitsPerPixel();
this->Buffer->Pitch = Display->GetPitch();
this->Buffer->Size = this->Buffer->Pitch * rect.Height;
this->Buffer->Data = (uint8_t *)this->mem->RequestPages(TO_PAGES(this->Buffer->Size + 1));
memset(this->Buffer->Data, 0, this->Buffer->Size);
this->ParentGUI = ParentGUI;
this->Position = rect;
strcpy(this->Title, Title);
this->Maximized = false;
this->Minimized = false;
}
Window::~Window()
{
delete this->mem, this->mem = nullptr;
}
}

View File

@ -1,137 +0,0 @@
/*
This file is part of Fennix Kernel.
Fennix Kernel is free software: you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation, either version 3 of
the License, or (at your option) any later version.
Fennix Kernel is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
*/
#include <gui.hpp>
#include <driver.hpp>
#include <task.hpp>
#include <printf.h>
#include <debug.h>
#include "../kernel.h"
#include "../DAPI.hpp"
#include "../Fex.hpp"
namespace GraphicalUserInterface
{
void Window::OnResize(Event *e)
{
// TODO: Optimize this
this->mem->FreePages(this->Buffer->Data, TO_PAGES(this->Buffer->Size + 1));
this->Buffer->Data = nullptr;
delete this->Buffer, this->Buffer = nullptr;
this->Buffer = new ScreenBitmap;
this->Buffer->Width = e->Resize.Width;
this->Buffer->Height = e->Resize.Height;
this->Buffer->BitsPerPixel = Display->GetBitsPerPixel();
this->Buffer->Pitch = Display->GetPitch();
this->Buffer->Size = this->Buffer->Pitch * e->Resize.Height;
this->Buffer->Data = (uint8_t *)this->mem->RequestPages(TO_PAGES(this->Buffer->Size + 1));
memset(this->Buffer->Data, 0, this->Buffer->Size);
this->OnPaint(e);
}
void Window::OnMinimize(Event *e)
{
UNUSED(e);
fixme("Window::OnMinimize() not implemented");
}
void Window::OnMaximize(Event *e)
{
UNUSED(e);
fixme("Window::OnMaximize() not implemented");
}
void Window::OnClose(Event *e)
{
UNUSED(e);
fixme("Window::OnClose() not implemented");
}
void Window::OnPaintBackground(Event *e)
{
UNUSED(e);
Rect PaintPosition = this->Position;
PaintPosition.Left = 0;
PaintPosition.Top = 0;
PutRect(this->Buffer, PaintPosition, 0x121212);
}
void Window::OnPaintForeground(Event *e)
{
// Window content
if (!this->Maximized)
{
char buf[256];
sprintf(buf, "Left:\eAA11FF%ld\eFFFFFF Top:\eAA11FF%ld\eFFFFFF W:\eAA11FF%ld\eFFFFFF H:\eAA11FF%ld\eFFFFFF", this->Position.Left, this->Position.Top, this->Position.Width, this->Position.Height);
// Display->DrawString(buf, this->Position.Left + 20, this->Position.Top + 25, 200);
}
foreach (auto var in this->Widgets)
{
var->OnPaint(e);
}
}
void Window::OnPaint(Event *e)
{
memset(this->Buffer->Data, 0, this->Buffer->Size);
this->OnPaintBackground(e);
this->OnPaintForeground(e);
}
void Window::OnMouseDown(Event *e)
{
Event WindowPos = *e;
WindowPos.MouseDown.X -= this->Position.Left;
WindowPos.MouseDown.Y -= this->Position.Top;
foreach (auto var in this->Widgets)
{
var->OnMouseDown(&WindowPos);
}
}
void Window::OnMouseUp(Event *e)
{
Event WindowPos = *e;
WindowPos.MouseUp.X -= this->Position.Left;
WindowPos.MouseUp.Y -= this->Position.Top;
foreach (auto var in this->Widgets)
{
var->OnMouseUp(&WindowPos);
}
}
void Window::OnMouseMove(Event *e)
{
Event WindowPos = *e;
WindowPos.MouseMove.X -= this->Position.Left;
WindowPos.MouseMove.Y -= this->Position.Top;
foreach (auto var in this->Widgets)
{
var->OnMouseMove(&WindowPos);
}
}
}

View File

@ -67,12 +67,11 @@ LockClass mExtTrkLock;
* - [x] The cleanup should be done by a thread (tasking). This is done to avoid a deadlock.
* - [ ] Implement a better Display::SetBrightness() function.
* - [ ] Fix memcpy, memset and memcmp functions (they are not working properly with SIMD).
* - [ ] Support Aarch64.
* - [ ] Fully support i386.
* - [ ] Support Aarch64.
* - [ ] SMP trampoline shouldn't be hardcoded at 0x2000.
* - [ ] Rework the stack guard.
* - [ ] Mutex implementation.
* - [ ] Vector should have a mutex.
* - [x] Mutex implementation.
* - [ ] Update SMBIOS functions to support newer versions and actually use it.
* - [ ] COW (Copy On Write) for the virtual memory. (https://en.wikipedia.org/wiki/Copy-on-write)
* - [ ] Bootstrap should have a separate bss section + PHDR.
@ -183,6 +182,10 @@ LockClass mExtTrkLock;
* https://github.com/gcc-mirror/gcc/tree/master/libstdc%2B%2B-v3
* https://itanium-cxx-abi.github.io/cxx-abi/abi.html
*
* - Keyboard:
* https://www.win.tue.nl/~aeb/linux/kbd/scancodes-11.html
* https://wiki.osdev.org/PS/2_Keyboard
*
*/
#ifdef a64
@ -207,8 +210,6 @@ NewLock(KernelLock);
#include <intrin.hpp>
using VirtualFileSystem::File;
using VirtualFileSystem::FileStatus;
using VirtualFileSystem::Node;
using VirtualFileSystem::NodeFlags;
@ -223,9 +224,10 @@ VirtualFileSystem::Virtual *vfs = nullptr;
KernelConfig Config = {
.AllocatorType = Memory::MemoryAllocatorType::XallocV1,
.SchedulerType = 1,
.DriverDirectory = {'/', 's', 'y', 's', 't', 'e', 'm', '/', 'd', 'r', 'i', 'v', 'e', 'r', 's', '\0'},
.InitPath = {'/', 's', 'y', 's', 't', 'e', 'm', '/', 'i', 'n', 'i', 't', '\0'},
.SchedulerType = Multi,
.DriverDirectory = {'/', 'm', 'o', 'd', 'u', 'l', 'e', 's', '\0'},
.InitPath = {'/', 'b', 'i', 'n', '/', 'i', 'n', 'i', 't', '\0'},
.UseLinuxSyscalls = false,
.InterruptsOnCrash = true,
.Cores = 0,
.IOAPICInterruptCore = 0,
@ -280,6 +282,9 @@ EXTERNC NIF void Main()
KPrint("CPU: \e058C19%s \e8822AA%s \e8888FF%s",
CPU::Hypervisor(), CPU::Vendor(), CPU::Name());
debug("CPU: %s %s %s",
CPU::Hypervisor(), CPU::Vendor(), CPU::Name());
if (DebuggerIsAttached)
KPrint("\eFFA500Kernel debugger detected.");
@ -291,11 +296,8 @@ EXTERNC NIF void Main()
KPrint("Loading Kernel Symbols");
KernelSymbolTable = new SymbolResolver::Symbols((uintptr_t)bInfo.Kernel.FileBase);
if (KernelSymbolTable->GetTotalEntries() == 0 &&
bInfo.Kernel.Symbols.Num &&
bInfo.Kernel.Symbols.EntSize &&
bInfo.Kernel.Symbols.Shndx)
KernelSymbolTable->AddBySymbolInfo(bInfo.Kernel.Symbols.Num,
if (!KernelSymbolTable->SymTableExists)
KernelSymbolTable->AddSymbolInfoFromGRUB(bInfo.Kernel.Symbols.Num,
bInfo.Kernel.Symbols.EntSize,
bInfo.Kernel.Symbols.Shndx,
bInfo.Kernel.Symbols.Sections);
@ -453,74 +455,74 @@ EXTERNC NIF void Main()
DevFS = vfs->Create("/dev", NodeFlags::DIRECTORY);
else
{
File dev = vfs->Open("/dev");
if (dev.GetFlags() != NodeFlags::DIRECTORY)
RefNode *dev = vfs->Open("/dev");
if (dev->GetNode()->Flags != NodeFlags::DIRECTORY)
{
KPrint("\eE85230/dev is not a directory! Halting...");
CPU::Stop();
}
vfs->Close(dev);
DevFS = dev.GetNode();
DevFS = dev->GetNode();
delete dev;
}
if (!vfs->PathExists("/mnt"))
MntFS = vfs->Create("/mnt", NodeFlags::DIRECTORY);
else
{
File mnt = vfs->Open("/mnt");
if (mnt.GetFlags() != NodeFlags::DIRECTORY)
RefNode *mnt = vfs->Open("/mnt");
if (mnt->GetNode()->Flags != NodeFlags::DIRECTORY)
{
KPrint("\eE85230/mnt is not a directory! Halting...");
CPU::Stop();
}
vfs->Close(mnt);
MntFS = mnt.GetNode();
MntFS = mnt->GetNode();
delete mnt;
}
if (!vfs->PathExists("/proc"))
ProcFS = vfs->Create("/proc", NodeFlags::DIRECTORY);
else
{
File proc = vfs->Open("/proc", nullptr);
if (proc.GetFlags() != NodeFlags::DIRECTORY)
RefNode *proc = vfs->Open("/proc", nullptr);
if (proc->GetNode()->Flags != NodeFlags::DIRECTORY)
{
KPrint("\eE85230/proc is not a directory! Halting...");
CPU::Stop();
}
vfs->Close(proc);
ProcFS = proc.GetNode();
ProcFS = proc->GetNode();
delete proc;
}
if (!vfs->PathExists("/var"))
VarLogFS = vfs->Create("/var", NodeFlags::DIRECTORY);
else
{
File var = vfs->Open("/var", nullptr);
if (var.GetFlags() != NodeFlags::DIRECTORY)
RefNode *var = vfs->Open("/var", nullptr);
if (var->GetNode()->Flags != NodeFlags::DIRECTORY)
{
KPrint("\eE85230/var is not a directory! Halting...");
CPU::Stop();
}
vfs->Close(var);
VarLogFS = var.GetNode();
VarLogFS = var->GetNode();
delete var;
if (!vfs->PathExists("/var/log"))
VarLogFS = vfs->Create("/var/log", NodeFlags::DIRECTORY);
else
{
File var_log = vfs->Open("/var/log", nullptr);
if (var_log.GetFlags() != NodeFlags::DIRECTORY)
RefNode *var_log = vfs->Open("/var/log", nullptr);
if (var_log->GetNode()->Flags != NodeFlags::DIRECTORY)
{
KPrint("\eE85230/var/log is not a directory! Halting...");
CPU::Stop();
}
vfs->Close(var_log);
VarLogFS = var_log.GetNode();
VarLogFS = var_log->GetNode();
delete var_log;
}
}
KPrint("\e058C19################################");
TaskManager = new Tasking::Task((Tasking::IP)KernelMainThread);
TaskManager = new Tasking::Task(Tasking::IP(KernelMainThread));
CPU::Halt(true);
}
@ -573,14 +575,16 @@ EXTERNC __no_stack_protector NIF void Entry(BootInfo *Info)
* memory management to be initialized first.
*/
TestString();
Test_std();
TestMemoryAllocation();
#endif
EnableProfiler = true;
Main();
}
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wdelete-non-virtual-dtor"
extern "C" void __cxa_finalize(void *);
EXTERNC __no_stack_protector void BeforeShutdown(bool Reboot)
{
UNUSED(Reboot);
@ -588,9 +592,6 @@ EXTERNC __no_stack_protector void BeforeShutdown(bool Reboot)
trace("\n\n\n#################### SYSTEM SHUTTING DOWN ####################\n\n");
if (RecoveryScreen)
delete RecoveryScreen, RecoveryScreen = nullptr;
if (NIManager)
delete NIManager, NIManager = nullptr;
@ -620,8 +621,10 @@ EXTERNC __no_stack_protector void BeforeShutdown(bool Reboot)
debug("Calling destructors...");
for (CallPtr *func = __fini_array_start; func != __fini_array_end; func++)
(*func)();
__cxa_finalize(nullptr);
debug("Done.");
}
#pragma GCC diagnostic pop
EXTERNC void TaskingPanic()
{

View File

@ -78,6 +78,12 @@ static struct cag_option ConfigOptions[] = {
.value_name = "PATH",
.description = "Path to init program"},
{.identifier = 'y',
.access_letters = "yY",
.access_name = "linux",
.value_name = "BOOL",
.description = "Use Linux syscalls by default"},
{.identifier = 'l',
.access_letters = NULL,
.access_name = "udl",
@ -110,12 +116,8 @@ static struct cag_option ConfigOptions[] = {
void ParseConfig(char *ConfigString, KernelConfig *ModConfig)
{
if (ConfigString == NULL)
{
KPrint("Empty kernel parameters!");
return;
}
else if (strlen(ConfigString) == 0)
if (ConfigString == NULL ||
strlen(ConfigString) == 0)
{
KPrint("Empty kernel parameters!");
return;
@ -170,11 +172,6 @@ void ParseConfig(char *ConfigString, KernelConfig *ModConfig)
KPrint("\eAAFFAAUsing Pages as memory allocator");
ModConfig->AllocatorType = Memory::MemoryAllocatorType::Pages;
}
else
{
KPrint("\eAAFFAAUnknown memory allocator: %s", value);
ModConfig->AllocatorType = Memory::MemoryAllocatorType::None;
}
break;
}
case 'c':
@ -197,17 +194,17 @@ void ParseConfig(char *ConfigString, KernelConfig *ModConfig)
if (strcmp(value, "multi") == 0)
{
KPrint("\eAAFFAAUsing Multi-Tasking Scheduler");
ModConfig->SchedulerType = 1;
ModConfig->SchedulerType = Multi;
}
else if (strcmp(value, "single") == 0)
{
KPrint("\eAAFFAAUsing Single-Tasking Scheduler");
ModConfig->SchedulerType = 0;
ModConfig->SchedulerType = Mono;
}
else
{
KPrint("\eAAFFAAUnknown scheduler: %s", value);
ModConfig->SchedulerType = 1;
ModConfig->SchedulerType = Multi;
}
break;
}
@ -225,6 +222,13 @@ void ParseConfig(char *ConfigString, KernelConfig *ModConfig)
KPrint("\eAAFFAAUsing %s as init program", value);
break;
}
case 'y':
{
value = cag_option_get_value(&context);
strcmp(value, "true") == 0 ? ModConfig->UseLinuxSyscalls = true : ModConfig->UseLinuxSyscalls = false;
KPrint("\eAAFFAAUse Linux syscalls by default: %s", value);
break;
}
case 'o':
{
value = cag_option_get_value(&context);

View File

@ -0,0 +1,55 @@
/*
This file is part of Fennix Kernel.
Fennix Kernel is free software: you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation, either version 3 of
the License, or (at your option) any later version.
Fennix Kernel is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
*/
#include "../cmds.hpp"
#include <filesystem.hpp>
#include "../../kernel.h"
using namespace VirtualFileSystem;
void cmd_cat(const char *args)
{
if (args[0] == '\0')
return;
Node *thisNode = vfs->GetNodeFromPath(args, thisProcess->CurrentWorkingDirectory);
if (thisNode == nullptr)
{
printf("cat: %s: No such file or directory\n", args);
return;
}
if (thisNode->Flags != NodeFlags::FILE &&
thisNode->Flags != NodeFlags::CHARDEVICE)
{
printf("cat: %s: Not a file\n", args);
return;
}
std::string path = vfs->GetPathFromNode(thisNode);
int fd = fopen(path.c_str(), "r");
struct stat st;
fstat(fd, &st);
char *buffer = new char[st.st_size + 1];
fread(fd, buffer, st.st_size);
printf("%s\n", buffer);
delete[] buffer;
fclose(fd);
}

View File

@ -0,0 +1,46 @@
/*
This file is part of Fennix Kernel.
Fennix Kernel is free software: you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation, either version 3 of
the License, or (at your option) any later version.
Fennix Kernel is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
*/
#include "../cmds.hpp"
#include <filesystem.hpp>
#include "../../kernel.h"
using namespace VirtualFileSystem;
void cmd_cd(const char *args)
{
if (args[0] == '\0')
return;
Node *thisNode = vfs->GetNodeFromPath(args, thisProcess->CurrentWorkingDirectory);
if (thisNode == nullptr)
{
printf("cd: %s: No such file or directory\n", args);
return;
}
if (thisNode->Flags != NodeFlags::DIRECTORY)
{
printf("cd: %s: Not a directory\n", args);
return;
}
thisProcess->CurrentWorkingDirectory = thisNode;
}

View File

@ -15,10 +15,11 @@
along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
*/
#include <kshell.hpp>
#include <debug.h>
#include "../cmds.hpp"
void StartKernelShell()
#include "../../kernel.h"
void cmd_echo(const char *args)
{
stub;
printf("%s\n", args);
}

View File

@ -15,27 +15,19 @@
along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef __FENNIX_KERNEL_RECOVERY_H__
#define __FENNIX_KERNEL_RECOVERY_H__
#include "../cmds.hpp"
#include <types.h>
#include <memory.hpp>
#include <filesystem.hpp>
#include <task.hpp>
namespace Recovery
#include "../../kernel.h"
using namespace VirtualFileSystem;
using namespace Tasking;
void cmd_exit(const char *)
{
class KernelRecovery
{
private:
Memory::MemMgr *mem;
Tasking::TCB *guiThread;
Tasking::TCB *recoveryThread;
public:
void RecoveryThread();
KernelRecovery();
~KernelRecovery();
};
KernelShutdownThread(false);
// TaskManager->KillThread(thisThread, KILL_SUCCESS);
CPU::Halt(true);
}
#endif // !__FENNIX_KERNEL_RECOVERY_H__

View File

@ -15,20 +15,25 @@
along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef __FENNIX_KERNEL_ICONS_AND_FONTS_H__
#define __FENNIX_KERNEL_ICONS_AND_FONTS_H__
#include "../cmds.hpp"
#include <types.h>
#include <filesystem.hpp>
#include <task.hpp>
extern char CursorArrow[];
extern char CursorHand[];
extern char CursorWait[];
extern char CursorIBeam[];
extern char CursorResizeAll[];
extern char CloseButton[];
extern char MinimizeButton[];
extern char MaximizeButtonNormal[];
extern char MaximizeButtonMaximized[];
extern char ResizeHint[];
#include "../../kernel.h"
#endif // !__FENNIX_KERNEL_ICONS_AND_FONTS_H__
using namespace VirtualFileSystem;
using namespace Tasking;
void cmd_kill(const char *args)
{
PID pid = atoi(args);
PCB *pcb = TaskManager->GetProcessByID(pid);
if (pcb == nullptr)
{
printf("No process with PID %d\n", pid);
return;
}
TaskManager->KillProcess(pcb, KILL_BY_OTHER_PROCESS);
}

View File

@ -0,0 +1,37 @@
/*
This file is part of Fennix Kernel.
Fennix Kernel is free software: you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation, either version 3 of
the License, or (at your option) any later version.
Fennix Kernel is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
*/
#include "../cmds.hpp"
#include <filesystem.hpp>
#include <task.hpp>
#include "../../kernel.h"
using namespace VirtualFileSystem;
using namespace Tasking;
void cmd_killall(const char *args)
{
foreach (auto Proc in TaskManager->GetProcessList())
{
if (strcmp(Proc->Name, args) == 0)
{
TaskManager->KillProcess(Proc, KILL_BY_OTHER_PROCESS);
}
}
}

View File

@ -0,0 +1,57 @@
/*
This file is part of Fennix Kernel.
Fennix Kernel is free software: you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation, either version 3 of
the License, or (at your option) any later version.
Fennix Kernel is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
*/
#include "../cmds.hpp"
#include <filesystem.hpp>
#include "../../kernel.h"
using namespace VirtualFileSystem;
void cmd_ls(const char *args)
{
if (args[0] == '\0')
{
Node *rootNode = thisProcess->CurrentWorkingDirectory;
if (rootNode == nullptr)
rootNode = vfs->GetRootNode()->Children[0];
foreach (auto var in rootNode->Children)
printf("%s\n", var->Name);
}
else
{
Node *thisNode = vfs->GetNodeFromPath(args, thisProcess->CurrentWorkingDirectory);
if (thisNode == nullptr)
{
printf("ls: %s: No such file or directory\n", args);
return;
}
if (thisNode->Flags != NodeFlags::DIRECTORY)
{
printf("%s\n", thisNode->Name);
return;
}
foreach (auto var in thisNode->Children)
printf("%s\n", var->Name);
}
}

View File

@ -0,0 +1,35 @@
/*
This file is part of Fennix Kernel.
Fennix Kernel is free software: you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation, either version 3 of
the License, or (at your option) any later version.
Fennix Kernel is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
*/
#include "../cmds.hpp"
#include "../../kernel.h"
void cmd_lsof(const char *)
{
printf("PROCESS FD NAME\n");
foreach (auto Proc in TaskManager->GetProcessList())
{
if (!Proc)
continue;
std::vector<VirtualFileSystem::FileDescriptorTable::FileDescriptor> fds_array = Proc->FileDescriptors->GetFileDescriptors();
foreach (auto fd in fds_array)
printf("%s %d: %s\n", Proc->Name, fd.Descriptor,
fd.Handle->AbsolutePath.c_str());
}
}

View File

@ -0,0 +1,41 @@
/*
This file is part of Fennix Kernel.
Fennix Kernel is free software: you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation, either version 3 of
the License, or (at your option) any later version.
Fennix Kernel is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
*/
#include "../cmds.hpp"
#include <filesystem.hpp>
#include "../../kernel.h"
using namespace VirtualFileSystem;
void cmd_lspci(const char *)
{
foreach (auto Device in PCIManager->GetDevices())
{
printf("%02x:%02x.%d: %s: %s %s %s\n",
// Device->Bus,
// Device->Device,
// Device->Function,
// FIXME
0, 0, 0,
PCI::Descriptors::BridgeDeviceSubclassName(Device->Subclass),
PCI::Descriptors::GetVendorName(Device->VendorID),
PCI::Descriptors::GetDeviceName(Device->VendorID, Device->DeviceID),
PCI::Descriptors::GetSubclassName(Device->Class, Device->Subclass));
}
}

View File

@ -0,0 +1,64 @@
/*
This file is part of Fennix Kernel.
Fennix Kernel is free software: you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation, either version 3 of
the License, or (at your option) any later version.
Fennix Kernel is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
*/
#include "../cmds.hpp"
#include <filesystem.hpp>
#include <task.hpp>
#include "../../kernel.h"
using namespace VirtualFileSystem;
using namespace Tasking;
void cmd_mem(const char *)
{
uint64_t total = KernelAllocator.GetTotalMemory();
uint64_t used = KernelAllocator.GetUsedMemory();
uint64_t free = KernelAllocator.GetFreeMemory();
uint64_t reserved = KernelAllocator.GetReservedMemory();
int usedPercent = (int)((used * 100) / total);
int usedBar = (int)(usedPercent / 2);
int reservedPercent = (int)((reserved * 100) / total);
int reservedBar = (int)(reservedPercent / 2);
printf("[");
for (int i = 0; i < usedBar; i++)
printf("=");
for (int i = 0; i < 50 - usedBar; i++)
printf(" ");
printf("] %d%% Used\n", usedPercent);
printf("[");
for (int i = 0; i < reservedBar; i++)
printf("=");
for (int i = 0; i < 50 - reservedBar; i++)
printf(" ");
printf("] %d%% Reserved\n", reservedPercent);
// printf("Total: %d MiB\n", (int)(TO_MiB(total)));
// printf("Used: %d MiB\n", (int)(TO_MiB(used)));
// printf("Free: %d MiB\n", (int)(TO_MiB(free)));
// printf("Reserved: %d MiB\n", (int)(TO_MiB(reserved)));
printf("TOTAL USED FREE RESERVED\n");
printf("%d MiB %d MiB %d MiB %d MiB\n",
(int)(TO_MiB(total)), (int)(TO_MiB(used)),
(int)(TO_MiB(free)), (int)(TO_MiB(reserved)));
}

View File

@ -0,0 +1,33 @@
/*
This file is part of Fennix Kernel.
Fennix Kernel is free software: you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation, either version 3 of
the License, or (at your option) any later version.
Fennix Kernel is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
*/
#include "../cmds.hpp"
#include <filesystem.hpp>
#include <task.hpp>
#include "../../kernel.h"
using namespace VirtualFileSystem;
using namespace Tasking;
void cmd_ps(const char *)
{
printf("PID Name\n");
foreach (auto p in TaskManager->GetProcessList())
printf("%d %s\n", p->ID, p->Name);
}

View File

@ -0,0 +1,32 @@
/*
This file is part of Fennix Kernel.
Fennix Kernel is free software: you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation, either version 3 of
the License, or (at your option) any later version.
Fennix Kernel is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
*/
#include "../cmds.hpp"
#include <filesystem.hpp>
#include <task.hpp>
#include "../../kernel.h"
using namespace VirtualFileSystem;
using namespace Tasking;
void cmd_reboot(const char *)
{
KernelShutdownThread(true);
CPU::Halt(true);
}

View File

@ -0,0 +1,32 @@
/*
This file is part of Fennix Kernel.
Fennix Kernel is free software: you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation, either version 3 of
the License, or (at your option) any later version.
Fennix Kernel is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
*/
#include "../cmds.hpp"
#include <filesystem.hpp>
#include <task.hpp>
#include "../../kernel.h"
using namespace VirtualFileSystem;
using namespace Tasking;
void cmd_shutdown(const char *)
{
KernelShutdownThread(false);
CPU::Halt(true);
}

View File

@ -0,0 +1,46 @@
/*
This file is part of Fennix Kernel.
Fennix Kernel is free software: you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation, either version 3 of
the License, or (at your option) any later version.
Fennix Kernel is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
*/
#include "../cmds.hpp"
#include <filesystem.hpp>
#include <task.hpp>
#include "../../kernel.h"
using namespace VirtualFileSystem;
using namespace Tasking;
void cmd_top(const char *)
{
printf("\e9400A1PID \e9CA100Name \e00A15BState \eCCCCCCPriority Memory Usage CPU Usage\n");
foreach (auto Proc in TaskManager->GetProcessList())
{
printf("\e9400A1%-4d \e9CA100%-20s \e00A15B%s \eCCCCCC%d %ld %ld\n",
Proc->ID, Proc->Name, Proc->Status == Running ? "Running" : "Stopped",
Proc->Info.Priority, Proc->Memory->GetAllocatedMemorySize(),
Proc->Info.UserTime + Proc->Info.KernelTime);
foreach (auto Thrd in Proc->Threads)
{
printf(" \eA80011%-4d \e9CA100%-20s \e00A15B%s \eCCCCCC%d %ld %ld\n",
Thrd->ID, Thrd->Name, Thrd->Status == Running ? "Running" : "Stopped",
Thrd->Info.Priority, Thrd->Memory->GetAllocatedMemorySize(),
Thrd->Info.UserTime + Thrd->Info.KernelTime);
}
}
}

View File

@ -0,0 +1,65 @@
/*
This file is part of Fennix Kernel.
Fennix Kernel is free software: you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation, either version 3 of
the License, or (at your option) any later version.
Fennix Kernel is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
*/
#include "../cmds.hpp"
#include <filesystem.hpp>
#include "../../kernel.h"
using namespace VirtualFileSystem;
void cmd_uname(const char *args)
{
if (args)
{
if (strcmp(args, "-a") == 0)
{
printf("Fennix Kernel %s %s %s %s\n",
KERNEL_VERSION, KERNEL_NAME, __DATE__,
KERNEL_ARCH);
}
else if (strcmp(args, "-s") == 0)
{
printf("%s\n", KERNEL_NAME);
}
else if (strcmp(args, "-v") == 0)
{
printf("%s\n", KERNEL_VERSION);
}
else if (strcmp(args, "-n") == 0)
{
printf("unknown\n");
}
else if (strcmp(args, "-r") == 0)
{
printf("%s\n", KERNEL_NAME);
}
else if (strcmp(args, "-m") == 0)
{
printf("%s\n", KERNEL_ARCH);
}
else
{
printf("uname: invalid option: %s\n", args);
}
}
else
{
printf("Fennix Kernel\n");
}
}

View File

@ -0,0 +1,51 @@
/*
This file is part of Fennix Kernel.
Fennix Kernel is free software: you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation, either version 3 of
the License, or (at your option) any later version.
Fennix Kernel is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
*/
#include "../cmds.hpp"
#include <filesystem.hpp>
#include "../../kernel.h"
using namespace VirtualFileSystem;
void cmd_uptime(const char *)
{
if (TimeManager)
{
size_t Nanoseconds =
TimeManager->GetNanosecondsSinceClassCreation();
size_t Seconds = Nanoseconds / 10000000;
size_t Minutes = Seconds / 60;
size_t Hours = Minutes / 60;
size_t Days = Hours / 24;
debug("Nanoseconds: %ld", Nanoseconds);
Seconds %= 60;
Minutes %= 60;
Hours %= 24;
printf("%ld days, %ld hours, %ld minutes, %ld %s\n",
Days, Hours, Minutes, Seconds,
Seconds == 1 ? "second" : "seconds");
}
else
{
printf("Could not get uptime\n");
}
}

View File

@ -0,0 +1,29 @@
/*
This file is part of Fennix Kernel.
Fennix Kernel is free software: you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation, either version 3 of
the License, or (at your option) any later version.
Fennix Kernel is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
*/
#include "../cmds.hpp"
#include <filesystem.hpp>
#include "../../kernel.h"
using namespace VirtualFileSystem;
void cmd_whoami(const char *)
{
printf("kernel\n");
}

422
KernelShell/Shell.cpp Normal file
View File

@ -0,0 +1,422 @@
/*
This file is part of Fennix Kernel.
Fennix Kernel is free software: you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation, either version 3 of
the License, or (at your option) any later version.
Fennix Kernel is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
*/
#include <kshell.hpp>
#include <filesystem.hpp>
#include <driver.hpp>
#include <lock.hpp>
#include <debug.h>
#include "../Modules/PersonalSystem2/keyboard.hpp"
#include "../kernel.h"
#include "../Fex.hpp"
#include "../DAPI.hpp"
#include "cmds.hpp"
using namespace PS2Keyboard;
NewLock(ShellLock);
const char sc_ascii_low[] = {'?', '?', '1', '2', '3', '4', '5', '6',
'7', '8', '9', '0', '-', '=', '?', '?', 'q', 'w', 'e', 'r', 't', 'y',
'u', 'i', 'o', 'p', '[', ']', '?', '?', 'a', 's', 'd', 'f', 'g',
'h', 'j', 'k', 'l', ';', '\'', '`', '?', '\\', 'z', 'x', 'c', 'v',
'b', 'n', 'm', ',', '.', '/', '?', '?', '?', ' '};
const char sc_ascii_high[] = {'?', '?', '!', '@', '#', '$', '%', '^',
'&', '*', '(', ')', '_', '+', '?', '?', 'Q', 'W', 'E', 'R', 'T', 'Y',
'U', 'I', 'O', 'P', '{', '}', '?', '?', 'A', 'S', 'D', 'F', 'G',
'H', 'J', 'K', 'L', ';', '\"', '~', '?', '|', 'Z', 'X', 'C', 'V',
'B', 'N', 'M', '<', '>', '?', '?', '?', '?', ' '};
static int LowerCase = true;
char GetLetterFromScanCode(uint8_t ScanCode)
{
if (ScanCode & 0x80)
{
switch (ScanCode)
{
case KEY_U_LSHIFT:
LowerCase = true;
return 0;
case KEY_U_RSHIFT:
LowerCase = true;
return 0;
default:
return 0;
}
}
else
{
switch (ScanCode)
{
case KEY_D_RETURN:
return '\n';
case KEY_D_LSHIFT:
LowerCase = false;
return 0;
case KEY_D_RSHIFT:
LowerCase = false;
return 0;
case KEY_D_BACKSPACE:
return ScanCode;
default:
{
if (ScanCode > 0x39)
break;
if (LowerCase)
return sc_ascii_low[ScanCode];
else
return sc_ascii_high[ScanCode];
}
}
}
return 0;
}
int GetChar()
{
return 0;
}
struct Command
{
const char *Name;
void (*Function)(const char *);
};
static Command commands[] = {
{"lsof", cmd_lsof},
{"ls", cmd_ls},
{"cd", cmd_cd},
{"cat", cmd_cat},
{"echo", cmd_echo},
{"mkdir", nullptr},
{"touch", nullptr},
{"rm", nullptr},
{"rmdir", nullptr},
{"mv", nullptr},
{"cp", nullptr},
{"clear", nullptr},
{"help", nullptr},
{"exit", cmd_exit},
{"reboot", cmd_reboot},
{"shutdown", cmd_shutdown},
{"ps", cmd_ps},
{"kill", cmd_kill},
{"killall", cmd_killall},
{"top", cmd_top},
{"mem", cmd_mem},
{"mount", nullptr},
{"umount", nullptr},
{"uname", cmd_uname},
{"whoami", cmd_whoami},
{"passwd", nullptr},
{"su", nullptr},
{"login", nullptr},
{"logout", nullptr},
{"uptime", cmd_uptime},
{"chown", nullptr},
{"chgrp", nullptr},
{"chmod", nullptr},
{"chroot", nullptr},
{"lspci", cmd_lspci}};
void StartKernelShell()
{
SmartLock(ShellLock);
debug("Starting kernel shell...");
printf("Starting kernel shell...\n");
thisThread->SetPriority(Tasking::TaskPriority::High);
Display->SetBuffer(0);
Driver::DriverFile KeyboardModule;
if (likely(DriverManager->GetDrivers().size() > 0))
{
foreach (auto Driver in DriverManager->GetDrivers())
{
if (((FexExtended *)Driver.ExtendedHeaderAddress)->Driver.Type == FexDriverType::FexDriverType_Input &&
((FexExtended *)Driver.ExtendedHeaderAddress)->Driver.TypeFlags & FexDriverInputTypes::FexDriverInputTypes_Keyboard)
{
KeyboardModule = Driver;
printf("Using driver \eCA21F6%s\eCCCCCC for keyboard input.\n",
((FexExtended *)Driver.ExtendedHeaderAddress)->Driver.Name);
break;
}
}
}
Display->SetBuffer(0);
std::string Buffer;
std::vector<std::string *> History;
size_t HistoryIndex = 0;
bool CtrlDown = false;
bool TabDoublePress = false;
while (true)
{
size_t BackspaceCount = 0;
Buffer.clear();
VirtualFileSystem::Node *cwd = thisProcess->CurrentWorkingDirectory;
if (!cwd)
cwd = vfs->GetNodeFromPath("/");
printf("\e34C6EB%s@%s:%s$ \eCCCCCC",
"kernel",
"fennix",
cwd->FileSystem->GetPathFromNode(cwd).c_str());
Display->SetBuffer(0);
while (true)
{
KernelCallback callback{};
callback.Reason = PollWaitReason;
DriverManager->IOCB(KeyboardModule.DriverUID, &callback);
char c = GetLetterFromScanCode(callback.InputCallback.Keyboard.Key);
switch (callback.InputCallback.Keyboard.Key)
{
case KEY_D_LCTRL:
{
CtrlDown = true;
continue;
}
case KEY_U_LCTRL:
{
CtrlDown = false;
continue;
}
case KEY_D_BACKSPACE:
{
if (BackspaceCount == 0)
continue;
Display->Print('\b', 0);
Buffer.pop_back();
BackspaceCount--;
Display->SetBuffer(0);
continue;
}
case KEY_D_UP:
{
if (History.size() == 0 ||
HistoryIndex == 0)
continue;
HistoryIndex--;
for (size_t i = 0; i < Buffer.size(); i++)
Display->Print('\b', 0);
Display->SetBuffer(0);
Buffer = History[HistoryIndex]->c_str();
for (size_t i = 0; i < strlen(Buffer.c_str()); i++)
Display->Print(Buffer[i], 0);
BackspaceCount = Buffer.size();
Display->SetBuffer(0);
continue;
}
case KEY_D_DOWN:
{
if (History.size() == 0 ||
HistoryIndex == History.size())
continue;
if (HistoryIndex == History.size() - 1)
{
HistoryIndex++;
for (size_t i = 0; i < Buffer.size(); i++)
Display->Print('\b', 0);
BackspaceCount = Buffer.size();
Display->SetBuffer(0);
continue;
}
for (size_t i = 0; i < Buffer.size(); i++)
Display->Print('\b', 0);
Display->SetBuffer(0);
HistoryIndex++;
Buffer = History[HistoryIndex]->c_str();
for (size_t i = 0; i < strlen(Buffer.c_str()); i++)
Display->Print(Buffer[i], 0);
BackspaceCount = Buffer.size();
Display->SetBuffer(0);
continue;
}
case KEY_D_TAB:
{
if (!TabDoublePress)
{
TabDoublePress = true;
continue;
}
TabDoublePress = false;
if (Buffer.size() == 0)
{
for (size_t i = 0; i < sizeof(commands) / sizeof(commands[0]); i++)
{
printf("%s ", commands[i].Name);
Display->SetBuffer(0);
}
Display->Print('\n', 0);
Display->SetBuffer(0);
goto SecLoopEnd;
}
for (size_t i = 0; i < Buffer.size(); i++)
Display->Print('\b', 0);
Display->SetBuffer(0);
for (size_t i = 0; i < sizeof(commands) / sizeof(commands[0]); i++)
{
if (strncmp(Buffer.c_str(), commands[i].Name, Buffer.size()) == 0)
{
Buffer = commands[i].Name;
for (size_t i = 0; i < strlen(Buffer.c_str()); i++)
Display->Print(Buffer[i], 0);
BackspaceCount = Buffer.size();
Display->SetBuffer(0);
break;
}
}
continue;
}
default:
break;
}
if (c == 0)
continue;
if (CtrlDown)
{
switch (std::toupper((char)c))
{
case 'C':
{
Display->Print('^', 0);
Display->Print('C', 0);
Display->Print('\n', 0);
fixme("No SIGINT handler yet.");
Display->SetBuffer(0);
goto SecLoopEnd;
}
case 'D':
{
Display->Print('^', 0);
Display->Print('D', 0);
Display->Print('\n', 0);
fixme("No SIGKILL handler yet.");
Display->SetBuffer(0);
goto SecLoopEnd;
}
default:
continue;
}
}
Display->Print(c, 0);
if (c == '\n')
{
if (Buffer.length() > 0)
{
std::string *hBuff = new std::string(Buffer.c_str());
History.push_back(hBuff);
HistoryIndex = History.size();
}
break;
}
Buffer += c;
BackspaceCount++;
Display->SetBuffer(0);
}
SecLoopEnd:
if (Buffer.length() == 0)
continue;
bool Found = false;
for (size_t i = 0; i < sizeof(commands) / sizeof(Command); i++)
{
std::string cmd_extracted;
for (size_t i = 0; i < Buffer.length(); i++)
{
if (Buffer[i] == ' ')
break;
cmd_extracted += Buffer[i];
}
debug("cmd: %s, array[%d]: %s", cmd_extracted.c_str(), i, commands[i].Name);
if (strncmp(commands[i].Name, cmd_extracted.c_str(), cmd_extracted.size()) == 0)
{
if (strlen(commands[i].Name) != cmd_extracted.size())
continue;
Found = true;
std::string arg_only;
const char *cmd_name = commands[i].Name;
for (size_t i = strlen(cmd_name) + 1; i < Buffer.length(); i++)
arg_only += Buffer[i];
if (commands[i].Function)
commands[i].Function(arg_only.c_str());
else
{
std::string cmd_only;
for (size_t i = 0; i < Buffer.length(); i++)
{
if (Buffer[i] == ' ')
break;
cmd_only += Buffer[i];
}
printf("%s: command not implemented\n",
cmd_only.c_str());
}
break;
}
}
if (!Found)
{
std::string cmd_only;
for (size_t i = 0; i < Buffer.length(); i++)
{
if (Buffer[i] == ' ')
break;
cmd_only += Buffer[i];
}
printf("%s: command not found\n",
cmd_only.c_str());
}
}
}
void KShellThread()
{
StartKernelShell();
inf_loop;
}

View File

@ -15,36 +15,27 @@
along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef __FENNIX_KERNEL_SHELL_CMDS_H__
#define __FENNIX_KERNEL_SHELL_CMDS_H__
#include <types.h>
#include "../syscalls.h"
void cmd_lsof(const char *args);
void cmd_echo(const char *args);
void cmd_ls(const char *args);
void cmd_cd(const char *args);
void cmd_cat(const char *args);
void cmd_ps(const char *args);
void cmd_uptime(const char *args);
void cmd_whoami(const char *args);
void cmd_uname(const char *args);
void cmd_mem(const char *args);
void cmd_kill(const char *args);
void cmd_killall(const char *args);
void cmd_top(const char *args);
void cmd_exit(const char *args);
void cmd_shutdown(const char *args);
void cmd_reboot(const char *args);
void cmd_lspci(const char *args);
#ifdef DEBUG
__aligned(0x1000) __no_stack_protector void TestSyscalls()
{
#if defined(a64)
__asm__ __volatile__("syscall"
:
: "a"(_Print), "D"('H'), "S"(0)
: "rcx", "r11", "memory");
int fork_id = -0xda;
__asm__ __volatile__("syscall"
: "=a"(fork_id)
: "a"(_Fork)
: "rcx", "r11", "memory");
__asm__ __volatile__("syscall"
:
: "a"(_Exit), "D"(fork_id)
: "rcx", "r11", "memory");
#elif defined(a32)
#elif defined(aa64)
#endif
while (1)
;
}
#endif
#endif // !__FENNIX_KERNEL_SHELL_CMDS_H__

View File

@ -21,13 +21,14 @@
#endif
#include <filesystem/ustar.hpp>
#include <kshell.hpp>
#include <power.hpp>
#include <lock.hpp>
#include <printf.h>
#include <exec.hpp>
#include <cwalk.h>
#include <vm.hpp>
#include <vector>
#define STB_IMAGE_IMPLEMENTATION
#define STBI_NO_STDIO
#define STBI_NO_LINEAR
@ -39,22 +40,17 @@
#include "DAPI.hpp"
#include "Fex.hpp"
using VirtualFileSystem::File;
using VirtualFileSystem::FileStatus;
using VirtualFileSystem::Node;
using VirtualFileSystem::NodeFlags;
Driver::Driver *DriverManager = nullptr;
Disk::Manager *DiskManager = nullptr;
NetworkInterfaceManager::NetworkInterface *NIManager = nullptr;
Recovery::KernelRecovery *RecoveryScreen = nullptr;
VirtualFileSystem::Node *DevFS = nullptr;
VirtualFileSystem::Node *MntFS = nullptr;
VirtualFileSystem::Node *ProcFS = nullptr;
VirtualFileSystem::Node *VarLogFS = nullptr;
NewLock(ShutdownLock);
#ifdef DEBUG
void TreeFS(Node *node, int Depth)
{
@ -62,6 +58,7 @@ void TreeFS(Node *node, int Depth)
foreach (auto Chld in node->Children)
{
printf("%*c %s\eFFFFFF\n", Depth, ' ', Chld->Name);
if (!Config.BootAnimation)
Display->SetBuffer(0);
TaskManager->Sleep(100);
@ -74,8 +71,8 @@ const char *Statuses[] = {
"AAFF00", /* Ready */
"00AA00", /* Running */
"FFAA00", /* Sleeping */
"FFAA00", /* Waiting */
"FF0088", /* Stopped */
"FFAA00", /* Blocked */
"FF0088", /* Zombie */
"FF0000", /* Terminated */
};
@ -135,14 +132,16 @@ static int ShowTaskManager = 0;
void TaskMgr()
{
TaskManager->GetCurrentThread()->Rename("Debug Task Manager");
TaskManager->GetCurrentThread()->SetPriority(Tasking::Low);
thisThread->Rename("Debug Task Manager");
thisThread->SetPriority(Tasking::Idle);
while (ShowTaskManager == 0)
CPU::Pause();
TaskManager->CreateThread(TaskManager->GetCurrentProcess(), (Tasking::IP)TaskMgr_Dummy100Usage)->Rename("Dummy 100% Usage");
TaskManager->CreateThread(TaskManager->GetCurrentProcess(), (Tasking::IP)TaskMgr_Dummy0Usage)->Rename("Dummy 0% Usage");
thisThread->SetPriority(Tasking::Idle);
TaskManager->CreateThread(thisProcess, Tasking::IP(TaskMgr_Dummy100Usage))->Rename("Dummy 100% Usage");
TaskManager->CreateThread(thisProcess, Tasking::IP(TaskMgr_Dummy0Usage))->Rename("Dummy 0% Usage");
while (true)
{
@ -169,7 +168,7 @@ void TaskMgr()
{
if (!Proc)
continue;
int Status = Proc->Status;
int Status = Proc->Status.load();
uint64_t ProcessCpuUsage = GetUsage(OldSystemTime, &Proc->Info);
printf("\e%s-> \eAABBCC%s \e00AAAA%s %ld%% (KT: %ld UT: %ld)\n",
Statuses[Status], Proc->Name, StatusesSign[Status], ProcessCpuUsage, Proc->Info.KernelTime, Proc->Info.UserTime);
@ -178,7 +177,7 @@ void TaskMgr()
{
if (!Thd)
continue;
Status = Thd->Status;
Status = Thd->Status.load();
uint64_t ThreadCpuUsage = GetUsage(OldSystemTime, &Thd->Info);
#if defined(a64)
printf(" \e%s-> \eAABBCC%s \e00AAAA%s %ld%% (KT: %ld UT: %ld, IP: \e24FF2B%#lx \eEDFF24%s\e00AAAA)\n\eAABBCC",
@ -213,49 +212,87 @@ void TaskMgr()
}
}
void TestSyscallsKernel()
static int ShowOpenFiles = 0;
void lsof()
{
return;
KPrint("Testing syscalls...");
Tasking::PCB *SyscallsTestProcess = TaskManager->CreateProcess(TaskManager->GetCurrentProcess(),
"Syscalls Test",
Tasking::TaskTrustLevel::User,
KernelSymbolTable);
thisThread->Rename("Debug File List");
thisThread->SetPriority(Tasking::Idle);
Tasking::TCB *SyscallsTestThread = TaskManager->CreateThread(SyscallsTestProcess,
(Tasking::IP)TestSyscalls,
nullptr,
nullptr,
std::vector<AuxiliaryVector>(),
Tasking::TaskArchitecture::x64,
Tasking::TaskCompatibility::Native,
true);
SyscallsTestThread->SetCritical(true);
TaskManager->GetSecurityManager()->TrustToken(SyscallsTestThread->Security.UniqueToken, Tasking::TTL::FullTrust);
while (ShowOpenFiles == 0)
CPU::Pause();
Memory::Virtual vmm = Memory::Virtual(SyscallsTestProcess->PageTable);
thisThread->SetPriority(Tasking::High);
// vmm.Remap((void *)TestSyscalls, vmm.GetPhysical((void *)TestSyscalls), Memory::P | Memory::RW | Memory::US);
vfs->Create("/dummy_lsof_file", NodeFlags::FILE);
fopen("/dummy_lsof_file", "r");
// for (uintptr_t k = (uintptr_t)&_kernel_start; k < (uintptr_t)&_kernel_end; k += PAGE_SIZE)
// {
// vmm.Remap((void *)k, (void *)vmm.GetPhysical((void *)k), Memory::P | Memory::RW | Memory::US);
// debug("Remapped %#lx %#lx", k, vmm.GetPhysical((void *)k));
// }
for (uintptr_t k = (uintptr_t)TestSyscalls - PAGE_SIZE; k < (uintptr_t)TestSyscalls + FROM_PAGES(5); k += PAGE_SIZE)
while (true)
{
vmm.Remap((void *)k, (void *)vmm.GetPhysical((void *)k), Memory::P | Memory::RW | Memory::US);
debug("Remapped %#lx %#lx", k, vmm.GetPhysical((void *)k));
while (ShowOpenFiles == 0)
CPU::Pause();
Video::ScreenBuffer *sb = Display->GetBuffer(0);
for (short i = 0; i < 500; i++)
{
for (short j = 0; j < 500; j++)
{
uint32_t *Pixel = (uint32_t *)((uintptr_t)sb->Buffer + (j * sb->Width + i) * (bInfo.Framebuffer[0].BitsPerPixel / 8));
*Pixel = 0x222222;
}
}
SyscallsTestThread->Status = Tasking::TaskStatus::Ready;
TaskManager->WaitForThread(SyscallsTestThread);
KPrint("Test complete");
uint32_t tmpX, tmpY;
Display->GetBufferCursor(0, &tmpX, &tmpY);
Display->SetBufferCursor(0, 0, 0);
printf("\eF02C21Open Files (%ld):\e00AAAA\n",
TaskManager->GetProcessList().size());
foreach (auto Proc in TaskManager->GetProcessList())
{
if (!Proc)
continue;
printf("%s:\n", Proc->Name);
std::vector<VirtualFileSystem::FileDescriptorTable::FileDescriptor> fds_array = Proc->FileDescriptors->GetFileDescriptors();
foreach (auto fd in fds_array)
printf(" %d: %s\n", fd.Descriptor, fd.Handle->AbsolutePath.c_str());
}
Display->SetBufferCursor(0, tmpX, tmpY);
if (!Config.BootAnimation)
Display->SetBuffer(0);
}
}
#include <mutex>
std::mutex test_mutex;
void mutex_test_long()
{
while (true)
{
test_mutex.lock();
debug("Long Thread %d got mutex",
thisThread->ID);
// TaskManager->Sleep(2000);
test_mutex.unlock();
}
}
void mutex_test()
{
while (true)
{
test_mutex.lock();
debug("Thread %d got mutex",
thisThread->ID);
// TaskManager->Sleep(200);
test_mutex.unlock();
}
}
#endif
Execute::SpawnData SpawnInit()
int SpawnInit()
{
const char *envp[5] = {
"PATH=/bin:/usr/bin",
@ -284,18 +321,17 @@ void BootLogoAnimationThread()
while (FrameCount < 27)
{
sprintf(BootAnimPath, "/etc/boot/%ld.tga", FrameCount);
File ba = vfs->Open(BootAnimPath);
if (!ba.IsOK())
RefNode *frame = vfs->Open(BootAnimPath);
if (!frame)
{
vfs->Close(ba);
debug("Failed to load boot animation frame %s", BootAnimPath);
break;
}
FrameSizes[FrameCount] = s_cst(uint32_t, ba.GetLength());
Frames[FrameCount] = new uint8_t[ba.GetLength()];
vfs->Read(ba, Frames[FrameCount], ba.GetLength());
vfs->Close(ba);
FrameSizes[FrameCount] = s_cst(uint32_t, frame->Length);
Frames[FrameCount] = new uint8_t[frame->Length];
frame->Read(Frames[FrameCount], frame->Length);
delete frame;
FrameCount++;
}
@ -306,10 +342,13 @@ void BootLogoAnimationThread()
{
int x, y, channels;
if (!stbi_info_from_memory((uint8_t *)Frames[i], FrameSizes[i], &x, &y, &channels))
if (!stbi_info_from_memory((uint8_t *)Frames[i], FrameSizes[i],
&x, &y, &channels))
continue;
uint8_t *img = stbi_load_from_memory((uint8_t *)Frames[i], FrameSizes[i], &x, &y, &channels, STBI_rgb_alpha);
uint8_t *img = stbi_load_from_memory((uint8_t *)Frames[i],
FrameSizes[i], &x, &y,
&channels, STBI_rgb_alpha);
if (img == NULL)
continue;
@ -332,7 +371,8 @@ void BootLogoAnimationThread()
b = (b * a) / 0xFF;
}
Display->SetPixel((i % x) + offsetX, (i / x) + offsetY, (r << 16) | (g << 8) | (b << 0), 1);
Display->SetPixel((i % x) + offsetX, (i / x) + offsetY,
(r << 16) | (g << 8) | (b << 0), 1);
}
free(img);
@ -359,14 +399,17 @@ void ExitLogoAnimationThread()
uint32_t DispX = Display->GetBuffer(1)->Width;
uint32_t DispY = Display->GetBuffer(1)->Height;
for (size_t i = 40; i > 25; i--)
for (size_t i = FrameCount - 1; i > 0; i--)
{
int x, y, channels;
if (!stbi_info_from_memory((uint8_t *)Frames[i], FrameSizes[i], &x, &y, &channels))
if (!stbi_info_from_memory((uint8_t *)Frames[i], FrameSizes[i],
&x, &y, &channels))
continue;
uint8_t *img = stbi_load_from_memory((uint8_t *)Frames[i], FrameSizes[i], &x, &y, &channels, STBI_rgb_alpha);
uint8_t *img = stbi_load_from_memory((uint8_t *)Frames[i],
FrameSizes[i], &x, &y,
&channels, STBI_rgb_alpha);
if (img == NULL)
continue;
@ -389,7 +432,8 @@ void ExitLogoAnimationThread()
b = (b * a) / 0xFF;
}
Display->SetPixel((i % x) + offsetX, (i / x) + offsetY, (r << 16) | (g << 8) | (b << 0), 1);
Display->SetPixel((i % x) + offsetX, (i / x) + offsetY,
(r << 16) | (g << 8) | (b << 0), 1);
}
free(img);
@ -411,28 +455,49 @@ void CleanupProcessesThreadWrapper() { TaskManager->CleanupProcessesThread(); }
void KernelMainThread()
{
Tasking::TCB *clnThd = TaskManager->CreateThread(TaskManager->GetCurrentProcess(), (Tasking::IP)CleanupProcessesThreadWrapper);
// TaskManager->CreateThread(thisProcess, Tasking::IP(mutex_test_long));
// TaskManager->Yield();
// TaskManager->CreateThread(thisProcess, Tasking::IP(mutex_test));
// TaskManager->CreateThread(thisProcess, Tasking::IP(mutex_test));
// TaskManager->CreateThread(thisProcess, Tasking::IP(mutex_test));
// TaskManager->CreateThread(thisProcess, Tasking::IP(mutex_test));
// TaskManager->CreateThread(thisProcess, Tasking::IP(mutex_test));
// TaskManager->CreateThread(thisProcess, Tasking::IP(mutex_test));
// TaskManager->CreateThread(thisProcess, Tasking::IP(mutex_test));
// TaskManager->CreateThread(thisProcess, Tasking::IP(mutex_test));
// TaskManager->CreateThread(thisProcess, Tasking::IP(mutex_test));
// ilp;
Tasking::TCB *clnThd =
TaskManager->CreateThread(thisProcess,
Tasking::IP(CleanupProcessesThreadWrapper));
clnThd->SetPriority(Tasking::Idle);
TaskManager->SetCleanupThread(clnThd);
TaskManager->GetCurrentThread()->SetPriority(Tasking::Critical);
thisThread->SetPriority(Tasking::Critical);
Tasking::TCB *blaThread = nullptr;
if (Config.BootAnimation)
{
blaThread = TaskManager->CreateThread(TaskManager->GetCurrentProcess(), (Tasking::IP)BootLogoAnimationThread);
blaThread =
TaskManager->CreateThread(thisProcess,
Tasking::IP(BootLogoAnimationThread));
blaThread->Rename("Logo Animation");
}
#ifdef DEBUG
TaskManager->CreateThread(TaskManager->GetCurrentProcess(), (Tasking::IP)TaskMgr);
TaskManager->CreateThread(thisProcess, Tasking::IP(TaskMgr));
TaskManager->CreateThread(thisProcess, Tasking::IP(lsof));
TreeFS(vfs->GetRootNode(), 0);
TestSyscallsKernel();
#endif
KPrint("Kernel Compiled at: %s %s with C++ Standard: %d", __DATE__, __TIME__, CPP_LANGUAGE_STANDARD);
KPrint("Kernel Compiled at: %s %s with C++ Standard: %d",
__DATE__, __TIME__, CPP_LANGUAGE_STANDARD);
KPrint("C++ Language Version (__cplusplus): %ld", __cplusplus);
if (IsVirtualizedEnvironment())
KPrint("Running in Virtualized Environment");
KPrint("Initializing Disk Manager...");
DiskManager = new Disk::Manager;
@ -455,47 +520,23 @@ void KernelMainThread()
KPrint("Starting Network Interface Manager...");
NIManager->StartService();
printf("\eCCCCCC[\e00AEFFKernel Thread\eCCCCCC] Setting up userspace");
if (!Config.BootAnimation)
Display->SetBuffer(0);
Execute::SpawnData ret = {Execute::ExStatus::Unknown, nullptr, nullptr};
Tasking::TCB *ExecuteThread = nullptr;
KPrint("Setting up userspace");
int ExitCode = -1;
ExecuteThread = TaskManager->CreateThread(TaskManager->GetCurrentProcess(), (Tasking::IP)Execute::LibraryManagerService);
ExecuteThread->Rename("Library Manager");
ExecuteThread->SetCritical(true);
ExecuteThread->SetPriority(Tasking::Idle);
Display->Print('.', 0);
if (!Config.BootAnimation)
Display->SetBuffer(0);
ret = SpawnInit();
Display->Print('.', 0);
if (!Config.BootAnimation)
Display->SetBuffer(0);
if (ret.Status != Execute::ExStatus::OK)
Tasking::TCB *initThread = nullptr;
int tid = SpawnInit();
if (tid < 0)
{
KPrint("\eE85230Failed to start %s! Code: %d", Config.InitPath, ret.Status);
KPrint("\eE85230Failed to start %s! Code: %d", Config.InitPath, tid);
goto Exit;
}
ret.Thread->SetCritical(true);
TaskManager->GetSecurityManager()->TrustToken(ret.Process->Security.UniqueToken, Tasking::TTL::FullTrust);
TaskManager->GetSecurityManager()->TrustToken(ret.Thread->Security.UniqueToken, Tasking::TTL::FullTrust);
Display->Print('.', 0);
Display->Print('\n', 0);
if (!Config.BootAnimation)
Display->SetBuffer(0);
initThread = TaskManager->GetThreadByID(tid);
initThread->SetCritical(true);
KPrint("Waiting for \e22AAFF%s\eCCCCCC to start...", Config.InitPath);
TaskManager->GetCurrentThread()->SetPriority(Tasking::Idle);
thisThread->SetPriority(Tasking::Idle);
TaskManager->WaitForThread(ret.Thread);
ExitCode = ret.Thread->GetExitCode();
TaskManager->WaitForThread(initThread);
ExitCode = initThread->GetExitCode();
Exit:
if (ExitCode == 0)
{
@ -505,25 +546,27 @@ Exit:
CPU::Halt(true);
}
KPrint("\eE85230Userspace process exited with code %d (%#x)", ExitCode,
ExitCode < 0 ? -ExitCode : ExitCode);
KPrint("Dropping to recovery screen...");
TaskManager->Sleep(2500);
KPrint("\eE85230Userspace process exited with code %d (%#x)",
ExitCode, ExitCode < 0 ? -ExitCode : ExitCode);
KPrint("Dropping to kernel shell...");
TaskManager->Sleep(1000);
TaskManager->WaitForThread(blaThread);
RecoveryScreen = new Recovery::KernelRecovery;
TaskManager->CreateThread(thisProcess,
Tasking::IP(KShellThread))
->Rename("Kernel Shell");
CPU::Halt(true);
}
NewLock(ShutdownLock);
void __no_stack_protector KernelShutdownThread(bool Reboot)
{
SmartLock(ShutdownLock);
debug("KernelShutdownThread(%s)", Reboot ? "true" : "false");
if (Config.BootAnimation && TaskManager)
{
if (RecoveryScreen)
delete RecoveryScreen, RecoveryScreen = nullptr;
Tasking::TCB *elaThread = TaskManager->CreateThread(TaskManager->GetCurrentProcess(), (Tasking::IP)ExitLogoAnimationThread);
Tasking::TCB *elaThread =
TaskManager->CreateThread(thisProcess,
Tasking::IP(ExitLogoAnimationThread));
elaThread->Rename("Logo Animation");
TaskManager->WaitForThread(elaThread);
}

View File

@ -631,10 +631,8 @@ to attach them to the start of each source file to most effectively
state the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
A kernel that serves as the core of an operating system, managing
hardware resources and providing essential services to user-level
applications.
Copyright (C) 2023 EnderIce2
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
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
@ -654,7 +652,7 @@ Also add information on how to contact you by electronic and paper mail.
If the program does terminal interaction, make it output a short
notice like this when it starts in an interactive mode:
Fennix Kernel Copyright (C) 2023 EnderIce2
<program> Copyright (C) <year> <name of author>
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.

View File

@ -17,17 +17,18 @@
#include <bitmap.hpp>
bool Bitmap::operator[](uint64_t index) { return Get(index); }
bool Bitmap::Get(uint64_t index)
{
if (index > Size * 8)
return false;
uint64_t byteIndex = index / 8;
uint8_t bitIndex = index % 8;
uint8_t bitIndexer = 0b10000000 >> bitIndex;
if ((Buffer[byteIndex] & bitIndexer) > 0)
return true;
return false;
}
@ -35,11 +36,16 @@ bool Bitmap::Set(uint64_t index, bool value)
{
if (index > Size * 8)
return false;
uint64_t byteIndex = index / 8;
uint8_t bitIndex = index % 8;
uint8_t bitIndexer = 0b10000000 >> bitIndex;
Buffer[byteIndex] &= ~bitIndexer;
if (value)
Buffer[byteIndex] |= bitIndexer;
return true;
}
bool Bitmap::operator[](uint64_t index) { return this->Get(index); }

View File

@ -474,6 +474,7 @@ size_t wcslen(const wchar_t *s)
size_t wcsrtombs(char *dst, const wchar_t **src, size_t len, mbstate_t *ps)
{
UNUSED(ps);
size_t count = 0;
while (len > 0)
@ -792,6 +793,8 @@ EXTERNC __no_stack_protector void *__memcpy_chk(void *dest, const void *src, siz
__chk_fail();
void *ret = nullptr;
if (0) /* FIXME */
{
uint64_t simd = CPU::CheckSIMD();
if (simd & CPU::x86SIMDType::SIMD_SSE42)
ret = memcpy_sse4_2(dest, src, len);
@ -807,6 +810,14 @@ EXTERNC __no_stack_protector void *__memcpy_chk(void *dest, const void *src, siz
ret = memcpy_sse(dest, src, len);
else
ret = memcpy_unsafe(dest, src, len);
}
else
{
static int once = 0;
if (!once++)
fixme("SIMD memcpy disabled");
ret = memcpy_unsafe(dest, src, len);
}
#ifdef DEBUG
if (EnableExternalMemoryTracer)
{
@ -857,6 +868,8 @@ EXTERNC __no_stack_protector void *__memset_chk(void *dest, int val, size_t len,
__chk_fail();
void *ret = nullptr;
if (0) /* FIXME */
{
uint64_t simd = CPU::CheckSIMD();
if (simd & CPU::x86SIMDType::SIMD_SSE42)
ret = memset_sse4_2(dest, val, len);
@ -872,6 +885,14 @@ EXTERNC __no_stack_protector void *__memset_chk(void *dest, int val, size_t len,
ret = memset_sse(dest, val, len);
else
ret = memset_unsafe(dest, val, len);
}
else
{
static int once = 0;
if (!once++)
fixme("SIMD memset disabled");
ret = memset_unsafe(dest, val, len);
}
#ifdef DEBUG
if (EnableExternalMemoryTracer)
{
@ -928,6 +949,8 @@ EXTERNC __no_stack_protector void *__memmove_chk(void *dest, const void *src, si
__chk_fail();
void *ret = nullptr;
if (0) /* FIXME */
{
uint64_t simd = CPU::CheckSIMD();
if (simd & CPU::x86SIMDType::SIMD_SSE42)
ret = memmove_sse4_2(dest, src, len);
@ -943,6 +966,14 @@ EXTERNC __no_stack_protector void *__memmove_chk(void *dest, const void *src, si
ret = memmove_sse(dest, src, len);
else
ret = memmove_unsafe(dest, src, len);
}
else
{
static int once = 0;
if (!once++)
fixme("SIMD memmove disabled");
ret = memmove_unsafe(dest, src, len);
}
#ifdef DEBUG
if (EnableExternalMemoryTracer)
{

View File

@ -37,10 +37,25 @@ namespace __cxxabiv1
return &GetCurrentCPU()->EHGlobals;
}
/**
* @param f The destructor
* @param objptr The object to be destructed
* @param dso The DSO from which the object was obtained (unused in our case)
* @return Zero on success, non-zero on failure
*/
extern "C" int __cxa_atexit(void (*f)(void *), void *objptr, void *dso)
{
debug("Registering atexit function %p( %p, %p )",
f, objptr, dso);
if (KernelSymbolTable)
{
debug("Registering atexit function for \"%s\" with destructor \"%s\"",
KernelSymbolTable->GetSymbolFromAddress((uintptr_t)objptr),
KernelSymbolTable->GetSymbolFromAddress((uintptr_t)f));
}
else
{
debug("Registering atexit function for %p with destructor %p",
objptr, f);
}
if (__atexit_func_count >= ATEXIT_MAX_FUNCS)
return -1;
@ -53,24 +68,39 @@ namespace __cxxabiv1
extern "C" void __cxa_finalize(void *f)
{
fixme("__cxa_finalize( %p ) called.", f);
function("%p", f);
uarch_t i = __atexit_func_count;
if (!f)
if (f == nullptr)
{
while (i--)
{
if (__atexit_funcs[i].destructor_func)
{
if (KernelSymbolTable)
{
debug("Calling atexit function \"%s\"",
KernelSymbolTable->GetSymbolFromAddress((uintptr_t)__atexit_funcs[i].destructor_func));
}
else
{
debug("Calling atexit function %p",
__atexit_funcs[i].destructor_func);
}
(*__atexit_funcs[i].destructor_func)(__atexit_funcs[i].obj_ptr);
}
}
return;
}
while (i--)
{
if (__atexit_funcs[i].destructor_func == f)
{
(*__atexit_funcs[i].destructor_func)(__atexit_funcs[i].obj_ptr);
__atexit_funcs[i].destructor_func = 0;
}
}
}
extern "C" _Unwind_Reason_Code __gxx_personality_v0(int version, _Unwind_Action actions, _Unwind_Exception_Class exception_class, _Unwind_Exception *ue_header, _Unwind_Context *context)
{
@ -122,8 +152,8 @@ namespace __cxxabiv1
{
if (TaskManager && !TaskManager->IsPanic())
{
TaskManager->KillThread(TaskManager->GetCurrentThread(), Tasking::KILL_CXXABI_EXCEPTION);
TaskManager->Schedule();
TaskManager->KillThread(thisThread, Tasking::KILL_CXXABI_EXCEPTION);
TaskManager->Yield();
}
error("No task manager to kill thread!");

View File

@ -26,6 +26,9 @@ namespace __cxxabiv1
unsigned outer) const
{
#ifndef __GXX_RTTI
UNUSED(ThrowType);
UNUSED(ThrowObject);
UNUSED(outer);
return false;
#else
if (*this == *ThrowType)

View File

@ -28,6 +28,9 @@ namespace __cxxabiv1
unsigned Outer) const
{
#ifndef __GXX_RTTI
UNUSED(ThrownType);
UNUSED(ThrowObject);
UNUSED(Outer);
return false;
#else
if (Outer < 2 && *this->Pointee == typeid(void))

View File

@ -19,9 +19,15 @@
#include <types.h>
#include <debug.h>
#include <atomic>
#include "../../kernel.h"
__aligned(16) static int errno_value = 0;
int *__errno_location(void)
{
fixme("errno_location() is not implemented yet!");
return nullptr;
if (unlikely(!TaskManager || !thisThread))
return &errno_value;
return &thisThread->ErrorNumber;
}

81
Library/std/mutex.cpp Normal file
View File

@ -0,0 +1,81 @@
/*
This file is part of Fennix Kernel.
Fennix Kernel is free software: you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation, either version 3 of
the License, or (at your option) any later version.
Fennix Kernel is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
*/
#include <mutex>
#include <algorithm>
#include <assert.h>
#include <cpu.hpp>
#include "../../kernel.h"
using namespace Tasking;
namespace std
{
void mutex::lock()
{
bool Result = this->Locked.exchange(true, std::memory_order_acquire);
__sync;
if (Result)
{
this->Waiting.push_back(thisThread);
thisThread->Block();
TaskManager->Yield();
return;
}
this->Holder = thisThread;
this->Waiting.erase(std::find(this->Waiting.begin(),
this->Waiting.end(),
thisThread));
}
bool mutex::try_lock()
{
bool Result = this->Locked.exchange(true, std::memory_order_acquire);
__sync;
if (!Result)
{
this->Holder = thisThread;
this->Waiting.erase(std::find(this->Waiting.begin(),
this->Waiting.end(),
thisThread));
}
return !Result;
}
void mutex::unlock()
{
__sync;
this->Locked.store(false, std::memory_order_release);
if (!this->Waiting.empty())
{
this->Holder = this->Waiting[0];
this->Holder = this->Waiting.front();
this->Waiting.erase(this->Waiting.begin());
this->Holder->Unblock();
TaskManager->Yield();
}
else
this->Holder = nullptr;
}
}

View File

@ -27,6 +27,9 @@ namespace std
unsigned Outer) const
{
stub;
UNUSED(ThrowType);
UNUSED(ThrowObject);
UNUSED(Outer);
return false;
}
@ -34,6 +37,8 @@ namespace std
void **ObjectPointer) const
{
stub;
UNUSED(Target);
UNUSED(ObjectPointer);
return false;
}
}

View File

@ -52,12 +52,13 @@ LDFLAGS := -Wl,-Map kernel.map -static -nostdlib -nodefaultlibs -nolibc
WARNCFLAG = -Wall -Wextra \
-Wfloat-equal -Wpointer-arith -Wcast-align \
-Wredundant-decls -Winit-self -Wswitch-default \
-Wstrict-overflow=5 -Wconversion
-Wstrict-overflow=5 -Wconversion -Wno-error=cpp -Werror
# https://gcc.gnu.org/onlinedocs/gcc/x86-Options.html
CFLAGS := \
$(INCLUDE_DIR) \
-DKERNEL_NAME='"$(OSNAME)"' \
-DKERNEL_ARCH='"$(OSARCH)"' \
-DKERNEL_VERSION='"$(KERNEL_VERSION)"' \
-DGIT_COMMIT='"$(GIT_COMMIT)"' \
-DGIT_COMMIT_SHORT='"$(GIT_COMMIT_SHORT)"'
@ -66,9 +67,8 @@ SIMD_FLAGS := -msse -msse2 -msse3 -mssse3 -msse4.1 -msse4.2 -mavx -mavx2 -mavx51
ifeq ($(OSARCH), amd64)
CFLAGS += -fno-pic -fno-pie \
-mno-red-zone -march=core2 -pipe \
-mcmodel=kernel -fno-builtin -Da64 -Da86
CFLAGS += -fno-pic -fno-pie -mno-red-zone -march=core2 \
-mcmodel=kernel -fno-builtin -Da64 -Da86 -m64
CFLAG_STACK_PROTECTOR := -fstack-protector-all
LDFLAGS += -TArchitecture/amd64/linker.ld \
-fno-pic -fno-pie \
@ -78,9 +78,8 @@ LDFLAGS += -TArchitecture/amd64/linker.ld \
else ifeq ($(OSARCH), i386)
CFLAGS += -fno-pic -fno-pie -mno-80387 -mno-mmx -mno-3dnow \
-mno-red-zone -march=pentium -pipe -fno-builtin \
-Da32 -Da86
CFLAGS += -fno-pic -fno-pie -mno-red-zone -march=pentium \
-fno-builtin -Da32 -Da86 -m32
CFLAG_STACK_PROTECTOR := -fstack-protector-all
LDFLAGS += -TArchitecture/i386/linker.ld \
-fno-pic -fno-pie \
@ -90,7 +89,7 @@ LDFLAGS += -TArchitecture/i386/linker.ld \
else ifeq ($(OSARCH), aarch64)
CFLAGS += -pipe -fno-builtin -Wstack-protector -Daa64 -fPIC -mno-outline-atomics
CFLAGS += -fno-builtin -Wstack-protector -Daa64 -fPIC -mno-outline-atomics
CFLAG_STACK_PROTECTOR := -fstack-protector-all
LDFLAGS += -TArchitecture/aarch64/linker.ld -fPIC -pie \
-Wl,-static,--no-dynamic-linker,-ztext \
@ -112,7 +111,10 @@ ifeq ($(DEBUG), 1)
# CFLAGS += --coverage
# CFLAGS += -pg
# CFLAGS += -finstrument-functions
CFLAGS += -DDEBUG -ggdb3 -O0 -fdiagnostics-color=always -fverbose-asm -fstack-usage -fsanitize=undefined
CFLAGS += -DDEBUG -ggdb3 -O0 -fdiagnostics-color=always -fstack-usage -fsanitize=undefined
ifeq ($(OSARCH), amd64)
CFLAGS += -fverbose-asm
endif
ifneq ($(OSARCH), aarch64)
CFLAGS += -fstack-check
endif

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