Created
December 15, 2021 00:17
-
-
Save heimskr/9b701378d759e32d3af6630b5dc6721e to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# 1 "../Kernel/src/Objects/Process.cpp" | |
# 1 "<built-in>" 1 | |
# 1 "<built-in>" 3 | |
# 403 "<built-in>" 3 | |
# 1 "<command line>" 1 | |
# 1 "<built-in>" 2 | |
# 1 "../Kernel/src/Objects/Process.cpp" 2 | |
# 1 "../Kernel/include/Objects/Process.h" 1 | |
# 1 "/home/kai/.local/share/lemon/sysroot/system/include/abi-bits/pid_t.h" 1 3 | |
typedef int pid_t; | |
# 4 "../Kernel/include/Objects/Process.h" 2 | |
# 1 "../Kernel/include/Arch/x86_64/CPU.h" 1 | |
# 1 "../Kernel/include/Arch/x86_64/Compiler.h" 1 | |
# 1 "/home/kai/.local/share/lemon/sysroot/system/include/c++/v1/stddef.h" 1 3 | |
# 39 "/home/kai/.local/share/lemon/sysroot/system/include/c++/v1/stddef.h" 3 | |
# 1 "/home/kai/.local/share/lemon/sysroot/system/include/c++/v1/__config" 1 3 | |
# 13 "/home/kai/.local/share/lemon/sysroot/system/include/c++/v1/__config" 3 | |
# 1 "/home/kai/.local/share/lemon/bin/../include/x86_64-unknown-lemon/c++/v1/__config_site" 1 3 | |
# 14 "/home/kai/.local/share/lemon/sysroot/system/include/c++/v1/__config" 2 3 | |
# 23 "/home/kai/.local/share/lemon/sysroot/system/include/c++/v1/__config" 3 | |
# 812 "/home/kai/.local/share/lemon/sysroot/system/include/c++/v1/__config" 3 | |
namespace std { inline namespace __1 { } } | |
# 40 "/home/kai/.local/share/lemon/sysroot/system/include/c++/v1/stddef.h" 2 3 | |
# 43 "/home/kai/.local/share/lemon/sysroot/system/include/c++/v1/stddef.h" 3 | |
# 1 "/home/kai/.local/share/lemon/lib/clang/13.0.0/include/stddef.h" 1 3 4 | |
# 35 "/home/kai/.local/share/lemon/lib/clang/13.0.0/include/stddef.h" 3 4 | |
typedef long int ptrdiff_t; | |
# 46 "/home/kai/.local/share/lemon/lib/clang/13.0.0/include/stddef.h" 3 4 | |
typedef long unsigned int size_t; | |
# 60 "/home/kai/.local/share/lemon/lib/clang/13.0.0/include/stddef.h" 3 4 | |
typedef long unsigned int rsize_t; | |
# 102 "/home/kai/.local/share/lemon/lib/clang/13.0.0/include/stddef.h" 3 4 | |
# 1 "/home/kai/.local/share/lemon/lib/clang/13.0.0/include/__stddef_max_align_t.h" 1 3 4 | |
# 19 "/home/kai/.local/share/lemon/lib/clang/13.0.0/include/__stddef_max_align_t.h" 3 4 | |
typedef struct { | |
long long __clang_max_align_nonce1 | |
__attribute__((__aligned__(__alignof__(long long)))); | |
long double __clang_max_align_nonce2 | |
__attribute__((__aligned__(__alignof__(long double)))); | |
} max_align_t; | |
# 103 "/home/kai/.local/share/lemon/lib/clang/13.0.0/include/stddef.h" 2 3 4 | |
# 46 "/home/kai/.local/share/lemon/sysroot/system/include/c++/v1/stddef.h" 2 3 | |
extern "C++" { | |
# 1 "/home/kai/.local/share/lemon/sysroot/system/include/c++/v1/__nullptr" 1 3 | |
# 17 "/home/kai/.local/share/lemon/sysroot/system/include/c++/v1/__nullptr" 3 | |
# 54 "/home/kai/.local/share/lemon/sysroot/system/include/c++/v1/__nullptr" 3 | |
namespace std | |
{ | |
typedef decltype(nullptr) nullptr_t; | |
} | |
# 51 "/home/kai/.local/share/lemon/sysroot/system/include/c++/v1/stddef.h" 2 3 | |
using std::nullptr_t; | |
} | |
# 6 "../Kernel/include/Arch/x86_64/Compiler.h" 2 | |
__attribute__(( always_inline )) inline void* operator new(size_t, void* p){ | |
return p; | |
} | |
# 4 "../Kernel/include/Arch/x86_64/CPU.h" 2 | |
# 1 "../Kernel/include/Arch/x86_64/System.h" 1 | |
# 1 "/home/kai/.local/share/lemon/sysroot/system/include/c++/v1/stdint.h" 1 3 | |
# 110 "/home/kai/.local/share/lemon/sysroot/system/include/c++/v1/stdint.h" 3 | |
# 123 "/home/kai/.local/share/lemon/sysroot/system/include/c++/v1/stdint.h" 3 | |
# 1 "/home/kai/.local/share/lemon/lib/clang/13.0.0/include/stdint.h" 1 3 4 | |
# 96 "/home/kai/.local/share/lemon/lib/clang/13.0.0/include/stdint.h" 3 4 | |
typedef long int int64_t; | |
typedef long unsigned int uint64_t; | |
# 110 "/home/kai/.local/share/lemon/lib/clang/13.0.0/include/stdint.h" 3 4 | |
typedef int64_t int_least64_t; | |
typedef uint64_t uint_least64_t; | |
typedef int64_t int_fast64_t; | |
typedef uint64_t uint_fast64_t; | |
# 167 "/home/kai/.local/share/lemon/lib/clang/13.0.0/include/stdint.h" 3 4 | |
typedef int int32_t; | |
typedef unsigned int uint32_t; | |
# 184 "/home/kai/.local/share/lemon/lib/clang/13.0.0/include/stdint.h" 3 4 | |
typedef int32_t int_least32_t; | |
typedef uint32_t uint_least32_t; | |
typedef int32_t int_fast32_t; | |
typedef uint32_t uint_fast32_t; | |
# 205 "/home/kai/.local/share/lemon/lib/clang/13.0.0/include/stdint.h" 3 4 | |
typedef short int16_t; | |
typedef unsigned short uint16_t; | |
typedef int16_t int_least16_t; | |
typedef uint16_t uint_least16_t; | |
typedef int16_t int_fast16_t; | |
typedef uint16_t uint_fast16_t; | |
typedef signed char int8_t; | |
typedef unsigned char uint8_t; | |
typedef int8_t int_least8_t; | |
typedef uint8_t uint_least8_t; | |
typedef int8_t int_fast8_t; | |
typedef uint8_t uint_fast8_t; | |
# 249 "/home/kai/.local/share/lemon/lib/clang/13.0.0/include/stdint.h" 3 4 | |
typedef long int intptr_t; | |
typedef long unsigned int uintptr_t; | |
typedef long int intmax_t; | |
typedef long unsigned int uintmax_t; | |
# 124 "/home/kai/.local/share/lemon/sysroot/system/include/c++/v1/stdint.h" 2 3 | |
# 6 "../Kernel/include/Arch/x86_64/System.h" 2 | |
extern "C" { | |
void outportb(uint16_t port, uint8_t value); | |
void outportw(uint16_t port, uint16_t value); | |
void outportd(uint16_t port, uint32_t value); | |
void outportl(uint16_t port, uint32_t value); | |
uint8_t inportb(uint16_t port); | |
uint16_t inportw(uint16_t port); | |
uint32_t inportd(uint16_t port); | |
uint32_t inportl(uint16_t port); | |
} | |
struct RegisterContext { | |
uint64_t r15; | |
uint64_t r14; | |
uint64_t r13; | |
uint64_t r12; | |
uint64_t r11; | |
uint64_t r10; | |
uint64_t r9; | |
uint64_t r8; | |
uint64_t rbp; | |
uint64_t rdi; | |
uint64_t rsi; | |
uint64_t rdx; | |
uint64_t rcx; | |
uint64_t rbx; | |
uint64_t rax; | |
uint64_t rip; | |
uint64_t cs; | |
uint64_t rflags; | |
uint64_t rsp; | |
uint64_t ss; | |
}; | |
typedef struct { | |
uint16_t fcw; | |
uint16_t fsw; | |
uint8_t ftw; | |
uint8_t zero; | |
uint16_t fop; | |
uint64_t rip; | |
uint64_t rdp; | |
uint32_t mxcsr; | |
uint32_t mxcsrMask; | |
uint8_t st[8][16]; | |
uint8_t xmm[16][16]; | |
} __attribute__((packed)) fx_state_t; | |
static inline int CheckInterrupts() { | |
unsigned long flags; | |
asm volatile("pushf;" | |
"pop %%rax;" | |
: "=a"(flags)::"cc"); | |
return (flags & 0x200); | |
} | |
# 5 "../Kernel/include/Arch/x86_64/CPU.h" 2 | |
# 1 "../Kernel/include/Arch/x86_64/TSS.h" 1 | |
typedef struct { | |
uint32_t reserved __attribute__((aligned(16))); | |
uint64_t rsp0; | |
uint64_t rsp1; | |
uint64_t rsp2; | |
uint64_t reserved2; | |
uint64_t ist1; | |
uint64_t ist2; | |
uint64_t ist3; | |
uint64_t ist4; | |
uint64_t ist5; | |
uint64_t ist6; | |
uint64_t ist7; | |
uint64_t reserved3; | |
uint32_t reserved4; | |
uint32_t iopbOffset; | |
} __attribute__((packed)) tss_t; | |
namespace TSS | |
{ | |
void InitializeTSS(tss_t* tss, void* gdt); | |
inline void SetKernelStack(tss_t* tss, uint64_t stack){ | |
tss->rsp0 = stack; | |
} | |
} | |
# 6 "../Kernel/include/Arch/x86_64/CPU.h" 2 | |
class Process; | |
struct Thread; | |
template <typename T> class FastList; | |
typedef struct { | |
uint16_t limit; | |
uint64_t base; | |
} __attribute__((packed)) gdt_ptr_t; | |
struct CPU { | |
CPU* self; | |
uint64_t id; | |
void* gdt; | |
gdt_ptr_t gdtPtr; | |
Thread* currentThread = nullptr; | |
Thread* idleThread = nullptr; | |
Process* idleProcess; | |
volatile int runQueueLock = 0; | |
FastList<Thread*>* runQueue; | |
tss_t tss __attribute__((aligned(16))); | |
}; | |
enum { | |
CPUID_ECX_SSE3 = 1 << 0, | |
CPUID_ECX_PCLMUL = 1 << 1, | |
CPUID_ECX_DTES64 = 1 << 2, | |
CPUID_ECX_MONITOR = 1 << 3, | |
CPUID_ECX_DS_CPL = 1 << 4, | |
CPUID_ECX_VMX = 1 << 5, | |
CPUID_ECX_SMX = 1 << 6, | |
CPUID_ECX_EST = 1 << 7, | |
CPUID_ECX_TM2 = 1 << 8, | |
CPUID_ECX_SSSE3 = 1 << 9, | |
CPUID_ECX_CID = 1 << 10, | |
CPUID_ECX_FMA = 1 << 12, | |
CPUID_ECX_CX16 = 1 << 13, | |
CPUID_ECX_ETPRD = 1 << 14, | |
CPUID_ECX_PDCM = 1 << 15, | |
CPUID_ECX_PCIDE = 1 << 17, | |
CPUID_ECX_DCA = 1 << 18, | |
CPUID_ECX_SSE4_1 = 1 << 19, | |
CPUID_ECX_SSE4_2 = 1 << 20, | |
CPUID_ECX_x2APIC = 1 << 21, | |
CPUID_ECX_MOVBE = 1 << 22, | |
CPUID_ECX_POPCNT = 1 << 23, | |
CPUID_ECX_AES = 1 << 25, | |
CPUID_ECX_XSAVE = 1 << 26, | |
CPUID_ECX_OSXSAVE = 1 << 27, | |
CPUID_ECX_AVX = 1 << 28, | |
CPUID_EDX_FPU = 1 << 0, | |
CPUID_EDX_VME = 1 << 1, | |
CPUID_EDX_DE = 1 << 2, | |
CPUID_EDX_PSE = 1 << 3, | |
CPUID_EDX_TSC = 1 << 4, | |
CPUID_EDX_MSR = 1 << 5, | |
CPUID_EDX_PAE = 1 << 6, | |
CPUID_EDX_MCE = 1 << 7, | |
CPUID_EDX_CX8 = 1 << 8, | |
CPUID_EDX_APIC = 1 << 9, | |
CPUID_EDX_SEP = 1 << 11, | |
CPUID_EDX_MTRR = 1 << 12, | |
CPUID_EDX_PGE = 1 << 13, | |
CPUID_EDX_MCA = 1 << 14, | |
CPUID_EDX_CMOV = 1 << 15, | |
CPUID_EDX_PAT = 1 << 16, | |
CPUID_EDX_PSE36 = 1 << 17, | |
CPUID_EDX_PSN = 1 << 18, | |
CPUID_EDX_CLF = 1 << 19, | |
CPUID_EDX_DTES = 1 << 21, | |
CPUID_EDX_ACPI = 1 << 22, | |
CPUID_EDX_MMX = 1 << 23, | |
CPUID_EDX_FXSR = 1 << 24, | |
CPUID_EDX_SSE = 1 << 25, | |
CPUID_EDX_SSE2 = 1 << 26, | |
CPUID_EDX_SS = 1 << 27, | |
CPUID_EDX_HTT = 1 << 28, | |
CPUID_EDX_TM1 = 1 << 29, | |
CPUID_EDX_IA64 = 1 << 30, | |
CPUID_EDX_PBE = 1 << 31 | |
}; | |
typedef struct { | |
char vendorString[12]; | |
char nullTerminator = '\0'; | |
uint32_t features_ecx; | |
uint32_t features_edx; | |
} __attribute__((packed)) cpuid_info_t; | |
cpuid_info_t CPUID(); | |
__attribute__(( always_inline )) inline uintptr_t GetRBP() { | |
volatile uintptr_t val; | |
asm volatile("mov %%rbp, %0" : "=r"(val)); | |
return val; | |
} | |
__attribute__(( always_inline )) inline uintptr_t GetCR3() { | |
volatile uintptr_t val; | |
asm volatile("mov %%cr3, %0" : "=r"(val)); | |
return val; | |
} | |
static __attribute__(( always_inline )) inline void SetCPULocal(CPU* val) { | |
val->self = val; | |
asm volatile("wrmsr" ::"a"((uintptr_t)val & 0xFFFFFFFF) , | |
"d"(((uintptr_t)val >> 32) & 0xFFFFFFFF) , "c"(0xC0000102) ); | |
asm volatile("wrmsr" ::"a"((uintptr_t)val & 0xFFFFFFFF) , | |
"d"(((uintptr_t)val >> 32) & 0xFFFFFFFF) , "c"(0xC0000101) ); | |
} | |
static __attribute__(( always_inline )) inline CPU* GetCPULocal() { | |
CPU* ret; | |
int intEnable = CheckInterrupts(); | |
asm("cli"); | |
asm volatile("swapgs; movq %%gs:0, %0; swapgs;" | |
: "=r"(ret)); | |
if (intEnable) | |
asm("sti"); | |
return ret; | |
} | |
class InterruptDisabler { | |
public: | |
__attribute__(( always_inline )) inline InterruptDisabler() : m_intsWereEnabled(CheckInterrupts()) { asm volatile("cli"); } | |
__attribute__(( always_inline )) inline ~InterruptDisabler() { | |
if (m_intsWereEnabled) { | |
asm volatile("sti"); | |
} | |
} | |
private: | |
bool m_intsWereEnabled = false; | |
}; | |
# 6 "../Kernel/include/Objects/Process.h" 2 | |
# 1 "../Kernel/include/Arch/x86_64/ELF.h" 1 | |
typedef struct ELF64Header { | |
unsigned char id[16]; | |
uint16_t type; | |
uint16_t machine; | |
uint32_t version; | |
uint64_t entry; | |
uint64_t phOff; | |
uint64_t shOff; | |
uint32_t flags; | |
uint16_t hdrSize; | |
uint16_t phEntrySize; | |
uint16_t phNum; | |
uint16_t shEntrySize; | |
uint16_t shNum; | |
uint16_t shStrIndex; | |
} __attribute__((packed)) elf64_header_t; | |
typedef struct ELF64ProgramHeader { | |
uint32_t type; | |
uint32_t flags; | |
uint64_t offset; | |
uint64_t vaddr; | |
uint64_t paddr; | |
uint64_t fileSize; | |
uint64_t memSize; | |
uint64_t align; | |
} __attribute__((packed)) elf64_program_header_t; | |
typedef struct ELF64DynamicEntry { | |
int64_t tag; | |
union { | |
uint64_t val; | |
uint64_t ptr; | |
}; | |
} __attribute__((packed)) elf64_dynamic_t; | |
typedef struct ELF64Symbol { | |
uint32_t name; | |
uint8_t info; | |
uint8_t other; | |
uint16_t shIndex; | |
uint64_t value; | |
uint64_t size; | |
} __attribute__((packed)) elf64_symbol_t; | |
typedef struct ELF64Section { | |
uint32_t name; | |
uint32_t type; | |
uint64_t flags; | |
uint64_t addr; | |
uint64_t off; | |
uint64_t size; | |
uint32_t link; | |
uint32_t info; | |
uint64_t align; | |
uint64_t entSize; | |
} __attribute__((packed)) elf64_section_t; | |
typedef struct ELF64Relocation { | |
uint64_t offset; | |
uint64_t info; | |
} __attribute__((packed)) elf64_rel_t; | |
typedef struct ELF64RelocationA { | |
uint64_t offset; | |
uint64_t info; | |
int64_t addend; | |
} __attribute__((packed)) elf64_rela_t; | |
typedef struct { | |
uint64_t entry; | |
uint64_t pHdrSegment; | |
uint64_t phEntrySize; | |
uint64_t phNum; | |
char* linkerPath; | |
} elf_info_t; | |
# 172 "../Kernel/include/Arch/x86_64/ELF.h" | |
using ELFHeader = ELF64Header; | |
using ELFProgramHeader = ELF64ProgramHeader; | |
using ELFDynamicEntry = ELF64DynamicEntry; | |
using ELFSymbol = ELF64Symbol; | |
using ELFSection = ELF64Section; | |
using ELFRelocation = ELF64Relocation; | |
using ELFRelocationA = ELF64RelocationA; | |
class Process; | |
int VerifyELF(void* elf); | |
elf_info_t LoadELFSegments(Process* proc, void* elf, uintptr_t base); | |
# 8 "../Kernel/include/Objects/Process.h" 2 | |
# 1 "../Kernel/include/Errno.h" 1 | |
# 9 "../Kernel/include/Objects/Process.h" 2 | |
# 1 "../Kernel/include/Fs/Filesystem.h" 1 | |
# 1 "/home/kai/.local/share/lemon/sysroot/system/include/c++/v1/stddef.h" 1 3 | |
# 4 "../Kernel/include/Fs/Filesystem.h" 2 | |
# 1 "../Kernel/include/List.h" 1 | |
# 1 "../Kernel/include/Assert.h" 1 | |
extern "C" | |
[[noreturn]] | |
void KernelAssertionFailed(const char* msg, const char* file, int line); | |
# 4 "../Kernel/include/List.h" 2 | |
# 1 "../Kernel/include/CString.h" 1 | |
# 1 "/home/kai/.local/share/lemon/sysroot/system/include/c++/v1/stddef.h" 1 3 | |
# 5 "../Kernel/include/CString.h" 2 | |
# 1 "../Kernel/include/Arch/x86_64/Paging.h" 1 | |
# 58 "../Kernel/include/Arch/x86_64/Paging.h" | |
typedef uint64_t page_t; | |
typedef uint64_t pd_entry_t; | |
typedef uint64_t pdpt_entry_t; | |
typedef uint64_t pml4_entry_t; | |
typedef struct { | |
uint64_t phys; | |
page_t* virt; | |
} __attribute__((packed)) page_table_t; | |
using page_dir_t = pd_entry_t[512]; | |
using pdpt_t = pdpt_entry_t[512]; | |
using pml4_t = pml4_entry_t[512]; | |
typedef struct PageMap { | |
pdpt_entry_t* pdpt; | |
pd_entry_t** pageDirs; | |
uint64_t* pageDirsPhys; | |
page_t*** pageTables; | |
pml4_entry_t* pml4; | |
uint64_t pdptPhys; | |
uint64_t pml4Phys; | |
} __attribute__((packed)) page_map_t; | |
struct PageFaultTrap { | |
uintptr_t instructionPointer; | |
void(*handler)(); | |
}; | |
class AddressSpace; | |
namespace Memory { | |
extern pml4_t kernelPML4; | |
PageMap* CreatePageMap(); | |
PageMap* ClonePageMap(PageMap* pageMap); | |
void DestroyPageMap(PageMap* pageMap); | |
void InitializeVirtualMemory(); | |
void LateInitializeVirtualMemory(); | |
void* KernelAllocate4KPages(uint64_t amount); | |
void Free4KPages(void* addr, uint64_t amount, page_map_t* addressSpace); | |
void KernelFree4KPages(void* addr, uint64_t amount); | |
void FreeVirtualMemory(void* pointer, uint64_t size); | |
# 115 "../Kernel/include/Arch/x86_64/Paging.h" | |
void KernelMapVirtualMemory4K(uint64_t phys, uint64_t virt, uint64_t amount); | |
# 125 "../Kernel/include/Arch/x86_64/Paging.h" | |
void KernelMapVirtualMemory4K(uint64_t phys, uint64_t virt, uint64_t amount, uint64_t flags); | |
# 135 "../Kernel/include/Arch/x86_64/Paging.h" | |
void MapVirtualMemory4K(uint64_t phys, uint64_t virt, uint64_t amount, PageMap* pageMap); | |
# 146 "../Kernel/include/Arch/x86_64/Paging.h" | |
void MapVirtualMemory4K(uint64_t phys, uint64_t virt, uint64_t amount, uint64_t flags, PageMap* pageMap); | |
uintptr_t GetIOMapping(uintptr_t addr); | |
bool CheckKernelPointer(uintptr_t addr, uint64_t len); | |
bool CheckUsermodePointer(uintptr_t addr, uint64_t len, AddressSpace* addressSpace); | |
uint64_t VirtualToPhysicalAddress(uint64_t addr); | |
uint64_t VirtualToPhysicalAddress(uint64_t addr, page_map_t* addressSpace); | |
void SwitchPageDirectory(uint64_t phys); | |
void RegisterPageFaultTrap(PageFaultTrap trap); | |
void PageFaultHandler(void*, RegisterContext* regs); | |
inline void SetPageFrame(uint64_t* page, uint64_t addr) { *page = (*page & ~0xFFFFFFFFFF000ULL) | (addr & 0xFFFFFFFFFF000ULL); } | |
inline void SetPageFlags(uint64_t* page, uint64_t flags) { *page |= flags; } | |
inline uint32_t GetPageFrame(uint64_t p) { return (p & 0xFFFFFFFFFF000ULL) >> 12; } | |
inline void invlpg(uintptr_t addr) { asm volatile("invlpg (%0)" ::"r"(addr)); } | |
} | |
# 7 "../Kernel/include/CString.h" 2 | |
long strlenSafe(const char* str, size_t& size, AddressSpace* aSpace); | |
char* itoa(unsigned long long num, char* str, int base); | |
int HexStringToPointer(const char* buffer, size_t bufferSize, uintptr_t& pointerValue); | |
extern "C" void* memset(void* src, int c, size_t count); | |
extern "C" void* memcpy(void* dest, const void* src, size_t count); | |
extern "C" int memcmp(const void* s1, const void* s2, size_t n); | |
void memcpy_optimized(void* dest, void* src, size_t count); | |
void strcpy(char* dest, const char* src); | |
void strncpy(char* dest, const char* src, size_t n); | |
int strcmp(const char* s1, const char* s2); | |
char* strtok_r(char* str, const char* delim, char** saveptr); | |
size_t strlen(const char* str); | |
char* strcat(char* dest, const char* src); | |
char* strncat(char* dest, const char* src, size_t n); | |
int strncmp(const char* s1, const char* s2, size_t n); | |
char* strupr(char* s); | |
char* strnupr(char* s, size_t n); | |
char* strchr(const char* s, int c); | |
char* strnchr(const char* s, int c, size_t n); | |
char* strrchr(const char* s, int c); | |
char* strdup(const char* s); | |
# 5 "../Kernel/include/List.h" 2 | |
# 1 "../Kernel/include/MM/KMalloc.h" 1 | |
# 1 "/home/kai/.local/share/lemon/sysroot/system/include/c++/v1/stddef.h" 1 3 | |
# 4 "../Kernel/include/MM/KMalloc.h" 2 | |
void* kmalloc(size_t); | |
void kfree(void*); | |
void* krealloc(void*, size_t); | |
# 7 "../Kernel/include/List.h" 2 | |
# 1 "../Kernel/include/Move.h" 1 | |
namespace std { | |
template<typename T> | |
__attribute__(( always_inline )) inline constexpr T&& move(T& t) { | |
return static_cast<T&&>(t); | |
} | |
} | |
# 8 "../Kernel/include/List.h" 2 | |
# 1 "../Kernel/include/Spinlock.h" 1 | |
typedef volatile int lock_t; | |
# 51 "../Kernel/include/Spinlock.h" | |
template <bool disableInterrupts = false> class ScopedSpinLock final { | |
public: | |
__attribute__(( always_inline )) inline ScopedSpinLock(lock_t& lock) : m_lock(lock) { | |
if constexpr (disableInterrupts) { | |
(void)((CheckInterrupts()) || (KernelAssertionFailed("CheckInterrupts()", "../Kernel/include/Spinlock.h", 55), 0)); | |
({ unsigned i = 0; (void)((CheckInterrupts()) || (KernelAssertionFailed("CheckInterrupts()", "../Kernel/include/Spinlock.h", 56), 0)); asm volatile("cli"); while (__sync_lock_test_and_set(&m_lock, 1) && ++i < 0xFFFFFFF) asm("sti; pause; cli"); if (i >= 0xFFFFFFF) { (void)((!"Deadlock!") || (KernelAssertionFailed("!\"Deadlock!\"", "../Kernel/include/Spinlock.h", 56), 0)); } }); | |
} else { | |
({ unsigned i = 0; while (__sync_lock_test_and_set(&m_lock, 1) && ++i < 0xFFFFFFF) asm("pause"); if (i >= 0xFFFFFFF) { (void)((!"Deadlock!") || (KernelAssertionFailed("!\"Deadlock!\"", "../Kernel/include/Spinlock.h", 58), 0)); } }); | |
} | |
} | |
__attribute__(( always_inline )) inline ~ScopedSpinLock() { | |
({ __sync_lock_release(&m_lock); });; | |
if constexpr (disableInterrupts) { | |
asm volatile("sti"); | |
} | |
} | |
private: | |
lock_t& m_lock; | |
}; | |
# 9 "../Kernel/include/List.h" 2 | |
template <typename T> struct ListNode { | |
ListNode* next = nullptr; | |
ListNode* prev = nullptr; | |
T obj; | |
}; | |
template <typename T> class List; | |
template <typename T> class ListIterator { | |
friend class List<T>; | |
protected: | |
ListNode<T>* node = nullptr; | |
public: | |
ListIterator() = default; | |
ListIterator(const ListIterator<T>&) = default; | |
ListIterator& operator++() { | |
(void)((node) || (KernelAssertionFailed("node", "../Kernel/include/List.h", 29), 0)); | |
node = node->next; | |
return *this; | |
} | |
ListIterator operator++(int) { | |
ListIterator<T> v = ListIterator<T>(*this); | |
(void)((node) || (KernelAssertionFailed("node", "../Kernel/include/List.h", 38), 0)); | |
node = node->next; | |
return v; | |
} | |
ListIterator& operator=(const ListIterator& other) { | |
node = other.node; | |
return *this; | |
} | |
T& operator*() { | |
(void)((node) || (KernelAssertionFailed("node", "../Kernel/include/List.h", 51), 0)); | |
return node->obj; | |
} | |
T* operator->() { | |
(void)((node) || (KernelAssertionFailed("node", "../Kernel/include/List.h", 57), 0)); | |
return &node->obj; | |
} | |
friend bool operator==(const ListIterator& l, const ListIterator& r) { | |
if (l.node == r.node) { | |
return true; | |
} else { | |
return false; | |
} | |
} | |
friend bool operator!=(const ListIterator& l, const ListIterator& r) { | |
if (l.node != r.node) { | |
return true; | |
} else { | |
return false; | |
} | |
} | |
}; | |
template <typename T> class FastList final { | |
public: | |
FastList() { | |
front = __null; | |
back = __null; | |
num = 0; | |
} | |
FastList(T&& other) { | |
front = other.front; | |
back = other.back; | |
num = other.num; | |
memset(&other, 0, sizeof(FastList<T>)); | |
} | |
__attribute__(( always_inline )) inline FastList<T>& operator=(FastList<T>&& other) { | |
front = other.front; | |
back = other.back; | |
num = other.num; | |
memset(&other, 0, sizeof(FastList<T>)); | |
return *this; | |
} | |
FastList(FastList& other) = delete; | |
__attribute__(( always_inline )) inline FastList<T>& operator=(const FastList<T>& other) = delete; | |
~FastList() {} | |
void clear() { | |
front = __null; | |
back = __null; | |
num = 0; | |
} | |
void add_back(const T& obj) { | |
obj->next = front; | |
if (!front) { | |
obj->prev = obj; | |
obj->next = obj; | |
front = obj; | |
} else { | |
(void)((back) || (KernelAssertionFailed("back", "../Kernel/include/List.h", 126), 0)); | |
obj->prev = back; | |
back->next = obj; | |
front->prev = obj; | |
} | |
back = obj; | |
num++; | |
} | |
void add_front(const T& obj) { | |
if (!back) { | |
obj->prev = obj; | |
obj->next = obj; | |
back = obj; | |
} else { | |
(void)((front) || (KernelAssertionFailed("front", "../Kernel/include/List.h", 144), 0)); | |
obj->next = front; | |
front->prev = obj; | |
back->next = obj; | |
} | |
front = obj; | |
obj->prev = back; | |
num++; | |
} | |
void insert(const T& obj, T& it) { | |
if (it == front) { | |
add_front(obj); | |
return; | |
} | |
(void)((it) || (KernelAssertionFailed("it", "../Kernel/include/List.h", 163), 0)); | |
obj->prev = it->prev; | |
obj->next = it; | |
if (it->prev) { | |
it->prev->next = obj; | |
} | |
it->prev = obj; | |
num++; | |
} | |
T operator[](unsigned pos) { return get_at(pos); } | |
T get_at(unsigned pos) { | |
(void)((num > 0 && pos < num && front) || (KernelAssertionFailed("num > 0 && pos < num && front", "../Kernel/include/List.h", 179), 0)); | |
T current = front; | |
for (unsigned int i = 0; i < pos && i < num && current->next; i++) | |
current = current->next; | |
return current; | |
} | |
__attribute__((always_inline)) inline unsigned get_length() const { return num; } | |
T remove_at(unsigned pos) { | |
(void)((num > 0) || (KernelAssertionFailed("num > 0", "../Kernel/include/List.h", 192), 0)); | |
(void)((pos < num) || (KernelAssertionFailed("pos < num", "../Kernel/include/List.h", 193), 0)); | |
(void)((front != nullptr) || (KernelAssertionFailed("front != nullptr", "../Kernel/include/List.h", 194), 0)); | |
T current = front; | |
for (unsigned int i = 0; i < pos && current; i++) | |
current = current->next; | |
(void)((current) || (KernelAssertionFailed("current", "../Kernel/include/List.h", 201), 0)); | |
if (current->next) | |
current->next->prev = current->prev; | |
if (current->prev) | |
current->prev->next = current->next; | |
if (front == current) | |
front = current->next; | |
if (back == current) | |
back = current->prev; | |
current->next = current->prev = nullptr; | |
if (!(--num)) | |
front = back = nullptr; | |
return current; | |
} | |
void remove(T obj) { | |
if (!front || !num) { | |
(void)((front && num) || (KernelAssertionFailed("front && num", "../Kernel/include/List.h", 222), 0)); | |
return; | |
} | |
if (obj->next && obj->next != obj) { | |
(void)((obj->next->prev == obj) || (KernelAssertionFailed("obj->next->prev == obj", "../Kernel/include/List.h", 227), 0)); | |
obj->next->prev = obj->prev; | |
} | |
if (obj->prev && obj->prev != obj) { | |
(void)((obj->prev->next == obj) || (KernelAssertionFailed("obj->prev->next == obj", "../Kernel/include/List.h", 232), 0)); | |
obj->prev->next = obj->next; | |
} | |
if (front == obj) | |
front = obj->next; | |
if (back == obj) | |
back = obj->prev; | |
obj->next = obj->prev = nullptr; | |
--num; | |
if (!num) | |
front = back = nullptr; | |
} | |
__attribute__((always_inline)) inline T next(const T& o) const { | |
if (o->next == front) { | |
return nullptr; | |
} | |
return o->next; | |
} | |
__attribute__((always_inline)) inline T get_front() const { return front; } | |
__attribute__((always_inline)) inline T get_back() const { return back; } | |
public: | |
T front; | |
T back; | |
unsigned num; | |
}; | |
template <typename T> class List { | |
public: | |
List() { | |
front = __null; | |
back = __null; | |
num = 0; | |
lock = 0; | |
} | |
~List() { | |
({ __sync_lock_release(&lock); });; | |
clear(); | |
while (cache.get_length()) { | |
kfree(cache.remove_at(0)); | |
} | |
} | |
List& operator=(const List& l) { | |
clear(); | |
for (auto& i : l) { | |
add_back(i); | |
} | |
return *this; | |
} | |
List& operator=(List&& l) { | |
({ unsigned i = 0; while (__sync_lock_test_and_set(&l.lock, 1) && ++i < 0xFFFFFFF) asm("pause"); if (i >= 0xFFFFFFF) { (void)((!"Deadlock!") || (KernelAssertionFailed("!\"Deadlock!\"", "../Kernel/include/List.h", 297), 0)); } }); | |
front = l.front; | |
back = l.back; | |
num = l.num; | |
cache = std::move(l.cache); | |
l.front = nullptr; | |
l.back = nullptr; | |
l.num = 0; | |
({ __sync_lock_release(&l.lock); });; | |
return *this; | |
} | |
void clear() { | |
({ unsigned i = 0; while (__sync_lock_test_and_set(&lock, 1) && ++i < 0xFFFFFFF) asm("pause"); if (i >= 0xFFFFFFF) { (void)((!"Deadlock!") || (KernelAssertionFailed("!\"Deadlock!\"", "../Kernel/include/List.h", 314), 0)); } }); | |
ListNode<T>* node = front; | |
while (node && node->next) { | |
ListNode<T>* n = node->next; | |
DestroyNode(node); | |
node = n; | |
} | |
front = __null; | |
back = __null; | |
num = 0; | |
({ __sync_lock_release(&lock); });; | |
} | |
T& add_back(T&& obj) { | |
({ unsigned i = 0; while (__sync_lock_test_and_set(&lock, 1) && ++i < 0xFFFFFFF) asm("pause"); if (i >= 0xFFFFFFF) { (void)((!"Deadlock!") || (KernelAssertionFailed("!\"Deadlock!\"", "../Kernel/include/List.h", 331), 0)); } }); | |
ListNode<T>* node = AllocateNode(); | |
(void)((node) || (KernelAssertionFailed("node", "../Kernel/include/List.h", 334), 0)); | |
new (&node->obj) T(std::move(obj)); | |
node->next = node->prev = nullptr; | |
if (!front) { | |
front = node; | |
} else if (back) { | |
back->next = node; | |
node->prev = back; | |
} | |
back = node; | |
num++; | |
({ __sync_lock_release(&lock); });; | |
return node->obj; | |
} | |
T& add_back(const T& obj) { | |
({ unsigned i = 0; while (__sync_lock_test_and_set(&lock, 1) && ++i < 0xFFFFFFF) asm("pause"); if (i >= 0xFFFFFFF) { (void)((!"Deadlock!") || (KernelAssertionFailed("!\"Deadlock!\"", "../Kernel/include/List.h", 354), 0)); } }); | |
ListNode<T>* node = AllocateNode(); | |
(void)((node) || (KernelAssertionFailed("node", "../Kernel/include/List.h", 357), 0)); | |
new (&node->obj) T(obj); | |
node->next = node->prev = nullptr; | |
if (!front) { | |
front = node; | |
} else if (back) { | |
back->next = node; | |
node->prev = back; | |
} | |
back = node; | |
num++; | |
({ __sync_lock_release(&lock); });; | |
return node->obj; | |
} | |
void add_back_unlocked(const T& obj) { | |
({ unsigned i = 0; while (__sync_lock_test_and_set(&lock, 1) && ++i < 0xFFFFFFF) asm("pause"); if (i >= 0xFFFFFFF) { (void)((!"Deadlock!") || (KernelAssertionFailed("!\"Deadlock!\"", "../Kernel/include/List.h", 377), 0)); } }); | |
ListNode<T>* node = AllocateNode(); | |
(void)((node) || (KernelAssertionFailed("node", "../Kernel/include/List.h", 381), 0)); | |
new (&node->obj) T(obj); | |
node->next = node->prev = nullptr; | |
if (!front) { | |
front = node; | |
} else if (back) { | |
back->next = node; | |
node->prev = back; | |
} | |
back = node; | |
num++; | |
({ __sync_lock_release(&lock); });; | |
} | |
T& add_front(const T& obj) { | |
({ unsigned i = 0; while (__sync_lock_test_and_set(&lock, 1) && ++i < 0xFFFFFFF) asm("pause"); if (i >= 0xFFFFFFF) { (void)((!"Deadlock!") || (KernelAssertionFailed("!\"Deadlock!\"", "../Kernel/include/List.h", 399), 0)); } }); | |
ListNode<T>* node = AllocateNode(); | |
new (&node->obj) T(obj); | |
node->next = node->prev = nullptr; | |
if (!back) { | |
back = node; | |
} else if (front) { | |
front->prev = node; | |
node->next = front; | |
} | |
front = node; | |
num++; | |
({ __sync_lock_release(&lock); });; | |
return node->obj; | |
} | |
void insert(const T& obj, size_t pos) { | |
if (!num) { | |
add_back(obj); | |
return; | |
} | |
if (!pos) { | |
add_front(obj); | |
return; | |
} | |
({ unsigned i = 0; while (__sync_lock_test_and_set(&lock, 1) && ++i < 0xFFFFFFF) asm("pause"); if (i >= 0xFFFFFFF) { (void)((!"Deadlock!") || (KernelAssertionFailed("!\"Deadlock!\"", "../Kernel/include/List.h", 432), 0)); } }); | |
ListNode<T>* current = front; | |
for (unsigned int i = 0; i < pos && i < num && current->next; i++) | |
current = current->next; | |
ListNode<T>* node = AllocateNode(); | |
(void)((node) || (KernelAssertionFailed("node", "../Kernel/include/List.h", 440), 0)); | |
new (&node->obj) T(obj); | |
InsertNodeAfter(current); | |
({ __sync_lock_release(&lock); });; | |
} | |
T& insert(const T& obj, ListIterator<T>& it) { | |
if (it.node == back) { | |
return add_back(obj); | |
} | |
(void)((it.node) || (KernelAssertionFailed("it.node", "../Kernel/include/List.h", 453), 0)); | |
ListNode<T>* current = it.node; | |
({ unsigned i = 0; while (__sync_lock_test_and_set(&lock, 1) && ++i < 0xFFFFFFF) asm("pause"); if (i >= 0xFFFFFFF) { (void)((!"Deadlock!") || (KernelAssertionFailed("!\"Deadlock!\"", "../Kernel/include/List.h", 456), 0)); } }); | |
ListNode<T>* node = AllocateNode(); | |
(void)((node) || (KernelAssertionFailed("node", "../Kernel/include/List.h", 459), 0)); | |
new (&node->obj) T(obj); | |
InsertNodeBefore(node, current); | |
({ __sync_lock_release(&lock); });; | |
return node->obj; | |
} | |
T& insert(T&& obj, ListIterator<T>& it) { | |
if (it.node == back) { | |
return add_back(obj); | |
} | |
(void)((it.node) || (KernelAssertionFailed("it.node", "../Kernel/include/List.h", 474), 0)); | |
ListNode<T>* current = it.node; | |
({ unsigned i = 0; while (__sync_lock_test_and_set(&lock, 1) && ++i < 0xFFFFFFF) asm("pause"); if (i >= 0xFFFFFFF) { (void)((!"Deadlock!") || (KernelAssertionFailed("!\"Deadlock!\"", "../Kernel/include/List.h", 477), 0)); } }); | |
ListNode<T>* node = AllocateNode(); | |
(void)((node) || (KernelAssertionFailed("node", "../Kernel/include/List.h", 480), 0)); | |
new (&node->obj) T(std::move(obj)); | |
InsertNodeBefore(node, current); | |
({ __sync_lock_release(&lock); });; | |
return node->obj; | |
} | |
__attribute__(( always_inline )) inline T& operator[](unsigned pos) { return get_at(pos); } | |
T& get_at(unsigned pos) { | |
(void)((num > 0 && pos < num && front != nullptr) || (KernelAssertionFailed("num > 0 && pos < num && front != nullptr", "../Kernel/include/List.h", 493), 0)); | |
ListNode<T>* current = front; | |
for (unsigned int i = 0; i < pos && i < num && current->next; i++) | |
current = current->next; | |
return current->obj; | |
} | |
void replace_at(unsigned pos, const T& obj) { | |
(void)((num > 0 && pos < num) || (KernelAssertionFailed("num > 0 && pos < num", "../Kernel/include/List.h", 504), 0)); | |
({ unsigned i = 0; while (__sync_lock_test_and_set(&lock, 1) && ++i < 0xFFFFFFF) asm("pause"); if (i >= 0xFFFFFFF) { (void)((!"Deadlock!") || (KernelAssertionFailed("!\"Deadlock!\"", "../Kernel/include/List.h", 506), 0)); } }); | |
ListNode<T>* current = front; | |
for (unsigned int i = 0; i < pos; i++) | |
current = current->next; | |
if (current) { | |
current->obj = obj; | |
} | |
({ __sync_lock_release(&lock); });; | |
} | |
void replace_at(unsigned pos, T&& obj) { | |
(void)((num > 0 && pos < num) || (KernelAssertionFailed("num > 0 && pos < num", "../Kernel/include/List.h", 521), 0)); | |
({ unsigned i = 0; while (__sync_lock_test_and_set(&lock, 1) && ++i < 0xFFFFFFF) asm("pause"); if (i >= 0xFFFFFFF) { (void)((!"Deadlock!") || (KernelAssertionFailed("!\"Deadlock!\"", "../Kernel/include/List.h", 523), 0)); } }); | |
ListNode<T>* current = front; | |
for (unsigned int i = 0; i < pos; i++) | |
current = current->next; | |
if (current) { | |
current->obj = obj; | |
} | |
({ __sync_lock_release(&lock); });; | |
} | |
__attribute__(( always_inline )) inline unsigned get_length() const { return num; } | |
T remove_at(unsigned pos) { | |
(void)((num > 0) || (KernelAssertionFailed("num > 0", "../Kernel/include/List.h", 540), 0)); | |
(void)((pos < num) || (KernelAssertionFailed("pos < num", "../Kernel/include/List.h", 541), 0)); | |
({ unsigned i = 0; while (__sync_lock_test_and_set(&lock, 1) && ++i < 0xFFFFFFF) asm("pause"); if (i >= 0xFFFFFFF) { (void)((!"Deadlock!") || (KernelAssertionFailed("!\"Deadlock!\"", "../Kernel/include/List.h", 543), 0)); } }); | |
(void)((front != nullptr) || (KernelAssertionFailed("front != nullptr", "../Kernel/include/List.h", 544), 0)); | |
ListNode<T>* current = front; | |
for (unsigned int i = 0; i < pos && current; i++) | |
current = current->next; | |
(void)((current) || (KernelAssertionFailed("current", "../Kernel/include/List.h", 551), 0)); | |
T obj = std::move(current->obj); | |
num--; | |
if (front == current) | |
front = current->next; | |
if (back == current) | |
back = current->prev; | |
if (current->next) | |
current->next->prev = current->prev; | |
if (current->prev) | |
current->prev->next = current->next; | |
current->obj.~T(); | |
if (cache.get_length() >= maxCache) { | |
kfree(current); | |
} else { | |
cache.add_back(current); | |
} | |
if (!num) | |
front = back = nullptr; | |
({ __sync_lock_release(&lock); });; | |
return obj; | |
} | |
T remove_at_force_cache(unsigned pos) { | |
(void)((num > 0) || (KernelAssertionFailed("num > 0", "../Kernel/include/List.h", 583), 0)); | |
(void)((pos < num) || (KernelAssertionFailed("pos < num", "../Kernel/include/List.h", 584), 0)); | |
(void)((front != nullptr) || (KernelAssertionFailed("front != nullptr", "../Kernel/include/List.h", 585), 0)); | |
({ unsigned i = 0; while (__sync_lock_test_and_set(&lock, 1) && ++i < 0xFFFFFFF) asm("pause"); if (i >= 0xFFFFFFF) { (void)((!"Deadlock!") || (KernelAssertionFailed("!\"Deadlock!\"", "../Kernel/include/List.h", 587), 0)); } }); | |
ListNode<T>* current = front; | |
for (unsigned int i = 0; i < pos && current; i++) | |
current = current->next; | |
(void)((current) || (KernelAssertionFailed("current", "../Kernel/include/List.h", 594), 0)); | |
T obj = std::move(current->obj); | |
num--; | |
if (front == current) | |
front = current->next; | |
if (back == current) | |
back = current->prev; | |
if (current->next) | |
current->next->prev = current->prev; | |
if (current->prev) | |
current->prev->next = current->next; | |
current->obj.~T(); | |
cache.add_back(current); | |
if (!num) | |
front = back = nullptr; | |
({ __sync_lock_release(&lock); });; | |
return obj; | |
} | |
void remove(T val) { | |
if (num <= 0 || !front) { | |
return; | |
} | |
({ unsigned i = 0; while (__sync_lock_test_and_set(&lock, 1) && ++i < 0xFFFFFFF) asm("pause"); if (i >= 0xFFFFFFF) { (void)((!"Deadlock!") || (KernelAssertionFailed("!\"Deadlock!\"", "../Kernel/include/List.h", 625), 0)); } }); | |
ListNode<T>* current = front; | |
while (current && current != back && current->obj != val) | |
current = current->next; | |
if (current) { | |
if (current->prev) | |
current->prev->next = current->next; | |
if (current->next) | |
current->next->prev = current->prev; | |
if (front == current) | |
front = current->next; | |
if (back == current) | |
back = current->prev; | |
num--; | |
DestroyNode(current); | |
} | |
({ __sync_lock_release(&lock); });; | |
} | |
void remove(ListIterator<T>& it) { | |
(void)((it.node) || (KernelAssertionFailed("it.node", "../Kernel/include/List.h", 651), 0)); | |
ListNode<T>* current = it.node; | |
if (current) { | |
({ unsigned i = 0; while (__sync_lock_test_and_set(&lock, 1) && ++i < 0xFFFFFFF) asm("pause"); if (i >= 0xFFFFFFF) { (void)((!"Deadlock!") || (KernelAssertionFailed("!\"Deadlock!\"", "../Kernel/include/List.h", 655), 0)); } }); | |
if (current->prev) | |
current->prev->next = current->next; | |
if (current->next) | |
current->next->prev = current->prev; | |
if (front == current) | |
front = current->next; | |
if (back == current) | |
back = current->prev; | |
it.node = current->prev; | |
num--; | |
DestroyNode(current); | |
({ __sync_lock_release(&lock); });; | |
} | |
} | |
void allocate(unsigned count) { | |
({ unsigned i = 0; while (__sync_lock_test_and_set(&lock, 1) && ++i < 0xFFFFFFF) asm("pause"); if (i >= 0xFFFFFFF) { (void)((!"Deadlock!") || (KernelAssertionFailed("!\"Deadlock!\"", "../Kernel/include/List.h", 677), 0)); } }); | |
while (count--) { | |
cache.add_back((ListNode<T>*)kmalloc(sizeof(ListNode<T>))); | |
} | |
({ __sync_lock_release(&lock); });; | |
} | |
T& get_front() const { | |
(void)((front) || (KernelAssertionFailed("front", "../Kernel/include/List.h", 687), 0)); | |
return front->obj; | |
} | |
T& get_back() const { | |
(void)((back) || (KernelAssertionFailed("back", "../Kernel/include/List.h", 692), 0)); | |
return back->obj; | |
} | |
ListIterator<T> begin() const { | |
ListIterator<T> it; | |
if (!num || !front) { | |
it.node = nullptr; | |
} else { | |
it.node = front; | |
} | |
return it; | |
} | |
ListIterator<T> end() const { | |
ListIterator<T> it; | |
it.node = nullptr; | |
return it; | |
} | |
private: | |
__attribute__(( always_inline )) inline void InsertNodeBefore(ListNode<T>* node, ListNode<T>* existingNode) { | |
(void)((node && existingNode) || (KernelAssertionFailed("node && existingNode", "../Kernel/include/List.h", 716), 0)); | |
node->prev = existingNode->prev; | |
node->next = existingNode; | |
if (existingNode->prev) { | |
existingNode->prev->next = node; | |
} | |
existingNode->prev = node; | |
if (existingNode == front) { | |
front = node; | |
} | |
num++; | |
} | |
__attribute__(( always_inline )) inline void InsertNodeAfter(ListNode<T>* node, ListNode<T>* existingNode) { | |
(void)((node && existingNode) || (KernelAssertionFailed("node && existingNode", "../Kernel/include/List.h", 734), 0)); | |
node->prev = existingNode; | |
node->next = existingNode->next; | |
if (existingNode->next) { | |
existingNode->next->prev = node; | |
} | |
existingNode->next = node; | |
if (existingNode == back) { | |
back = node; | |
} | |
num++; | |
} | |
__attribute__(( always_inline )) inline ListNode<T>* AllocateNode() { | |
if (!cache.get_length()) { | |
return (ListNode<T>*)kmalloc(sizeof(ListNode<T>)); | |
} else { | |
return cache.remove_at(0); | |
} | |
} | |
__attribute__(( always_inline )) inline void DestroyNode(ListNode<T>* node) { | |
node->obj.~T(); | |
if (cache.get_length() >= maxCache) { | |
kfree(node); | |
} else { | |
cache.add_back(node); | |
} | |
} | |
ListNode<T>* front; | |
ListNode<T>* back; | |
unsigned num; | |
volatile int lock = 0; | |
const unsigned maxCache = 6; | |
FastList<ListNode<T>*> cache; | |
}; | |
# 7 "../Kernel/include/Fs/Filesystem.h" 2 | |
# 1 "../Kernel/include/Lock.h" 1 | |
# 1 "../Kernel/include/Arch/x86_64/Thread.h" 1 | |
# 1 "../Kernel/include/MiscHdr.h" 1 | |
enum { | |
VideoModeIndexed = 0, | |
VideoModeRGB = 1, | |
VideoModeText = 2, | |
}; | |
typedef struct{ | |
uint32_t width; | |
uint32_t height; | |
uint16_t bpp; | |
uint32_t pitch; | |
void* address; | |
uintptr_t physicalAddress; | |
int type; | |
} video_mode_t; | |
typedef struct { | |
uintptr_t totalMemory; | |
} memory_info_t; | |
typedef struct { | |
uintptr_t base; | |
uintptr_t size; | |
} boot_module_t; | |
# 6 "../Kernel/include/Arch/x86_64/Thread.h" 2 | |
# 1 "../Kernel/include/Signal.h" 1 | |
typedef void (*__sighandler) (int); | |
# 1 "/home/kai/.local/share/lemon/sysroot/system/include/abi-bits/signal.h" 1 3 | |
# 1 "/home/kai/.local/share/lemon/sysroot/system/include/abi-bits/uid_t.h" 1 3 | |
typedef unsigned int uid_t; | |
# 6 "/home/kai/.local/share/lemon/sysroot/system/include/abi-bits/signal.h" 2 3 | |
# 1 "/home/kai/.local/share/lemon/sysroot/system/include/bits/size_t.h" 1 3 | |
# 1 "/home/kai/.local/share/lemon/sysroot/system/include/c++/v1/stddef.h" 1 3 | |
# 15 "/home/kai/.local/share/lemon/sysroot/system/include/c++/v1/stddef.h" 3 | |
# 1 "/home/kai/.local/share/lemon/lib/clang/13.0.0/include/stddef.h" 1 3 4 | |
# 46 "/home/kai/.local/share/lemon/lib/clang/13.0.0/include/stddef.h" 3 4 | |
typedef long unsigned int size_t; | |
# 18 "/home/kai/.local/share/lemon/sysroot/system/include/c++/v1/stddef.h" 2 3 | |
# 6 "/home/kai/.local/share/lemon/sysroot/system/include/bits/size_t.h" 2 3 | |
# 7 "/home/kai/.local/share/lemon/sysroot/system/include/abi-bits/signal.h" 2 3 | |
union sigval { | |
int sival_int; | |
void *sival_ptr; | |
}; | |
typedef struct { | |
int si_signo; | |
int si_code; | |
int si_errno; | |
pid_t si_pid; | |
uid_t si_uid; | |
void *si_addr; | |
int si_status; | |
union sigval si_value; | |
} siginfo_t; | |
extern "C" { | |
# 69 "/home/kai/.local/share/lemon/sysroot/system/include/abi-bits/signal.h" 3 | |
typedef long sigset_t; | |
# 91 "/home/kai/.local/share/lemon/sysroot/system/include/abi-bits/signal.h" 3 | |
typedef struct __stack { | |
void *ss_sp; | |
size_t ss_size; | |
int ss_flags; | |
} stack_t; | |
# 114 "/home/kai/.local/share/lemon/sysroot/system/include/abi-bits/signal.h" 3 | |
struct sigevent { | |
int sigev_notify; | |
int sigev_signo; | |
union sigval sigev_value; | |
void (*sigev_notify_function)(union sigval); | |
}; | |
struct sigaction { | |
void (*sa_handler)(int); | |
sigset_t sa_mask; | |
int sa_flags; | |
void (*sa_sigaction)(int, siginfo_t *, void *); | |
}; | |
typedef struct { | |
unsigned long oldmask; | |
unsigned long gregs[16]; | |
unsigned long pc, pr, sr; | |
unsigned long gbr, mach, macl; | |
unsigned long fpregs[16]; | |
unsigned long xfpregs[16]; | |
unsigned int fpscr, fpul, ownedfp; | |
} mcontext_t; | |
} | |
# 7 "../Kernel/include/Signal.h" 2 | |
enum class SignalAction : int { | |
Die = 0, | |
Ignore = 1, | |
UsermodeHandler = 2, | |
}; | |
__attribute__(( always_inline )) inline SignalAction DefaultActionForSignal(int signum){ | |
switch(signum){ | |
case 11: | |
case 7: | |
case 4: | |
case 8: | |
case 6: | |
case 14: | |
case 1: | |
case 2: | |
case 29: | |
case 9: | |
case 13: | |
case 30: | |
case 3: | |
return SignalAction::Die; | |
default: | |
return SignalAction::Ignore; | |
} | |
} | |
struct SignalHandler { | |
enum class HandlerAction { | |
Default = 0, | |
Ignore = 1, | |
UsermodeHandler = 2, | |
}; | |
enum { | |
FlagSignalInfo = (1 << 4), | |
FlagNoChildStop = (1 << 0), | |
FlagNoChildWait = (1 << 5), | |
FlagNoDefer = (1 << 6), | |
FlagOnStack = (1 << 1), | |
FlagResetHand = (1 << 2), | |
FlagRestart = (1 << 3), | |
}; | |
static const int supportedFlags = (1 << 6); | |
HandlerAction action = HandlerAction::Default; | |
int flags = 0; | |
sigset_t mask = 0; | |
void* userHandler = nullptr; | |
__attribute__(( always_inline )) inline bool Ignore() const { return action == HandlerAction::Ignore; } | |
}; | |
# 8 "../Kernel/include/Arch/x86_64/Thread.h" 2 | |
# 1 "../Kernel/include/Arch/x86_64/Timer.h" 1 | |
# 1 "/home/kai/.local/share/lemon/sysroot/system/include/bits/posix/timeval.h" 1 3 | |
# 1 "/home/kai/.local/share/lemon/sysroot/system/include/bits/ansi/time_t.h" 1 3 | |
typedef long time_t; | |
# 5 "/home/kai/.local/share/lemon/sysroot/system/include/bits/posix/timeval.h" 2 3 | |
# 1 "/home/kai/.local/share/lemon/sysroot/system/include/bits/posix/suseconds_t.h" 1 3 | |
typedef long suseconds_t; | |
# 6 "/home/kai/.local/share/lemon/sysroot/system/include/bits/posix/timeval.h" 2 3 | |
struct timeval { | |
time_t tv_sec; | |
suseconds_t tv_usec; | |
}; | |
# 6 "../Kernel/include/Arch/x86_64/Timer.h" 2 | |
# 1 "/home/kai/.local/share/lemon/sysroot/system/include/bits/ansi/timespec.h" 1 3 | |
struct timespec { | |
time_t tv_sec; | |
long tv_nsec; | |
}; | |
# 7 "../Kernel/include/Arch/x86_64/Timer.h" 2 | |
typedef long time_t; | |
typedef struct timespec timespec_t; | |
static inline bool operator<(timeval l, timeval r){ | |
return (l.tv_sec < r.tv_sec) || (l.tv_sec == r.tv_sec && l.tv_usec < r.tv_usec); | |
} | |
namespace Timer{ | |
uint64_t GetSystemUptime(); | |
uint32_t GetTicks(); | |
uint32_t GetFrequency(); | |
timeval GetSystemUptimeStruct(); | |
long TimeDifference(const timeval& newTime, const timeval& oldTime); | |
void Wait(long ms); | |
void SleepCurrentThread(timeval& time); | |
void Initialize(uint32_t freq); | |
} | |
inline long operator-(const timeval& l, const timeval& r){ | |
return Timer::TimeDifference(l, r); | |
} | |
# 9 "../Kernel/include/Arch/x86_64/Thread.h" 2 | |
enum { | |
ThreadStateRunning, | |
ThreadStateBlocked, | |
ThreadStateZombie, | |
ThreadStateDying, | |
}; | |
class Process; | |
struct Thread; | |
class ThreadBlocker{ | |
friend struct Thread; | |
protected: | |
lock_t lock = 0; | |
Thread* thread = nullptr; | |
bool shouldBlock = true; | |
bool interrupted = false; | |
bool removed = false; | |
public: | |
virtual ~ThreadBlocker() = default; | |
virtual void Interrupt(); | |
virtual void Unblock(); | |
inline bool ShouldBlock() { return shouldBlock; } | |
inline bool WasInterrupted() { return interrupted; } | |
}; | |
class GenericThreadBlocker : public ThreadBlocker{ | |
public: | |
inline void Interrupt() {} | |
}; | |
using FutexThreadBlocker = GenericThreadBlocker; | |
struct Thread { | |
lock_t lock = 0; | |
lock_t stateLock = 0; | |
Process* parent; | |
pid_t tid = 1; | |
void* stack = nullptr; | |
void* stackLimit = nullptr; | |
void* kernelStack = nullptr; | |
uint32_t timeSlice = 10; | |
uint32_t timeSliceDefault = 10; | |
RegisterContext registers; | |
RegisterContext lastSyscall; | |
void* fxState; | |
Thread* next = nullptr; | |
Thread* prev = nullptr; | |
uint8_t priority = 0; | |
uint8_t state = ThreadStateRunning; | |
uint64_t fsBase = 0; | |
bool blockTimedOut = false; | |
ThreadBlocker* blocker = nullptr; | |
uint64_t pendingSignals = 0; | |
uint64_t signalMask = 0; | |
Thread(class Process* _parent, pid_t _tid); | |
void Signal(int signal); | |
void HandlePendingSignal(RegisterContext* regs); | |
# 101 "../Kernel/include/Arch/x86_64/Thread.h" | |
[[nodiscard]] bool Block(ThreadBlocker* blocker); | |
# 113 "../Kernel/include/Arch/x86_64/Thread.h" | |
[[nodiscard]] bool Block(ThreadBlocker* blocker, long& usTimeout); | |
void Sleep(long us); | |
# 130 "../Kernel/include/Arch/x86_64/Thread.h" | |
void Unblock(); | |
}; | |
# 7 "../Kernel/include/Lock.h" 2 | |
# 1 "../Kernel/include/Logging.h" 1 | |
# 1 "../Kernel/include/Video/VideoConsole.h" 1 | |
struct ConsoleCharacter | |
{ | |
char c; | |
uint8_t r, g, b; | |
} __attribute__((packed)); | |
class VideoConsole{ | |
public: | |
int cursorX; | |
int cursorY; | |
int x; | |
int y; | |
int width; | |
int height; | |
int widthInCharacters; | |
int heightInCharacters; | |
ConsoleCharacter* characterBuffer; | |
VideoConsole(int x, int y, int width, int height); | |
void Update(); | |
void Clear(uint8_t r, uint8_t g, uint8_t b); | |
void Print(char c, uint8_t r, uint8_t g, uint8_t b); | |
void Print(const char* str, uint8_t r, uint8_t g, uint8_t b); | |
void PrintN(const char* str, unsigned n, uint8_t r, uint8_t g, uint8_t b); | |
private: | |
void Scroll(); | |
}; | |
# 4 "../Kernel/include/Logging.h" 2 | |
# 1 "/home/kai/.local/share/lemon/lib/clang/13.0.0/include/stdarg.h" 1 3 4 | |
# 14 "/home/kai/.local/share/lemon/lib/clang/13.0.0/include/stdarg.h" 3 4 | |
typedef __builtin_va_list va_list; | |
# 32 "/home/kai/.local/share/lemon/lib/clang/13.0.0/include/stdarg.h" 3 4 | |
typedef __builtin_va_list __gnuc_va_list; | |
# 5 "../Kernel/include/Logging.h" 2 | |
# 1 "../Kernel/include/Arch/x86_64/Debug.h" 1 | |
enum{ | |
DebugLevelQuiet = 0, | |
DebugLevelNormal = 1, | |
DebugLevelVerbose = 2, | |
}; | |
# 17 "../Kernel/include/Arch/x86_64/Debug.h" | |
extern const int debugLevelHAL; | |
extern const int debugLevelScheduler; | |
extern const int debugLevelMisc; | |
extern const int debugLevelModules; | |
extern const int debugLevelSymbols; | |
extern const int debugLevelACPI; | |
extern const int debugLevelAHCI; | |
extern const int debugLevelATA; | |
extern const int debugLevelNVMe; | |
extern const int debugLevelPartitions; | |
extern const int debugLevelFilesystem; | |
extern const int debugLevelTmpFS; | |
extern const int debugLevelExt2; | |
extern const int debugLevelXHCI; | |
extern const int debugLevelInterrupts; | |
extern const int debugLevelMessageEndpoint; | |
extern const int debugLevelSyscalls; | |
extern const int debugLevelUsermodeMM; | |
extern const int debugLevelNetwork; | |
# 7 "../Kernel/include/Logging.h" 2 | |
namespace Log{ | |
extern VideoConsole* console; | |
void LateInitialize(); | |
void SetVideoConsole(VideoConsole* con); | |
void DisableBuffer(); | |
void EnableBuffer(); | |
void WriteF(const char* __restrict format, va_list args); | |
void Write(const char* str, uint8_t r = 255, uint8_t g = 255, uint8_t b = 255); | |
void Write(unsigned long long num, bool hex = true, uint8_t r = 255, uint8_t g = 255, uint8_t b = 255); | |
void Print(const char* __restrict fmt, ...); | |
void Warning(unsigned long long num); | |
void Warning(const char* __restrict fmt, ...); | |
void Error(unsigned long long num, bool hex = true); | |
void Error(const char* __restrict fmt, ...); | |
void Info(unsigned long long num, bool hex = true); | |
void Info(const char* __restrict fmt, ...); | |
__attribute__((always_inline)) inline static void Debug(const int& var, const int lvl, const char* __restrict fmt, ...){ | |
if(var >= lvl){ | |
Write("\r\n[INFO] "); | |
va_list args; | |
__builtin_va_start(args, fmt); | |
WriteF(fmt, args); | |
__builtin_va_end(args); | |
} | |
} | |
} | |
# 8 "../Kernel/include/Lock.h" 2 | |
class Semaphore { | |
protected: | |
lock_t value = 0; | |
lock_t lock = 0; | |
class SemaphoreBlocker : public ThreadBlocker{ | |
friend class Semaphore; | |
public: | |
SemaphoreBlocker* next = nullptr; | |
SemaphoreBlocker* prev = nullptr; | |
Semaphore* semaphore = nullptr; | |
inline SemaphoreBlocker(Semaphore* sema) : semaphore(sema) { | |
} | |
void Interrupt(){ | |
interrupted = true; | |
shouldBlock = false; | |
({ unsigned i = 0; while (__sync_lock_test_and_set(&lock, 1) && ++i < 0xFFFFFFF) asm("pause"); if (i >= 0xFFFFFFF) { (void)((!"Deadlock!") || (KernelAssertionFailed("!\"Deadlock!\"", "../Kernel/include/Lock.h", 30), 0)); } }); | |
if(semaphore){ | |
semaphore->blocked.remove(this); | |
semaphore = nullptr; | |
} | |
if(thread){ | |
thread->Unblock(); | |
} | |
thread = nullptr; | |
({ __sync_lock_release(&lock); });; | |
} | |
void Unblock(){ | |
shouldBlock = false; | |
({ unsigned i = 0; while (__sync_lock_test_and_set(&lock, 1) && ++i < 0xFFFFFFF) asm("pause"); if (i >= 0xFFFFFFF) { (void)((!"Deadlock!") || (KernelAssertionFailed("!\"Deadlock!\"", "../Kernel/include/Lock.h", 47), 0)); } }); | |
if(semaphore){ | |
semaphore->blocked.remove(this); | |
} | |
semaphore = nullptr; | |
if(thread){ | |
thread->Unblock(); | |
} | |
({ __sync_lock_release(&lock); });; | |
} | |
~SemaphoreBlocker(){ | |
if(semaphore){ | |
semaphore->blocked.remove(this); | |
} | |
} | |
}; | |
FastList<SemaphoreBlocker*> blocked; | |
public: | |
Semaphore(int val) : value(val) {}; | |
inline void SetValue(int val){ | |
value = val; | |
} | |
inline lock_t GetValue(){ | |
return value; | |
} | |
[[nodiscard]] bool Wait(); | |
[[nodiscard]] bool WaitTimeout(long& timeout); | |
void Signal(); | |
}; | |
class ReadWriteLock { | |
unsigned activeReaders = 0; | |
lock_t fileLock = 0; | |
lock_t lock = 0; | |
bool writerAcquiredLock = false; | |
FastList<Thread*> readers; | |
FastList<Thread*> writers; | |
public: | |
__attribute__(( always_inline )) inline ReadWriteLock() {} | |
__attribute__(( always_inline )) inline void AcquireRead(){ | |
({ unsigned i = 0; while (__sync_lock_test_and_set(&lock, 1) && ++i < 0xFFFFFFF) asm("pause"); if (i >= 0xFFFFFFF) { (void)((!"Deadlock!") || (KernelAssertionFailed("!\"Deadlock!\"", "../Kernel/include/Lock.h", 98), 0)); } }); | |
if(__atomic_add_fetch(&activeReaders, 1, 2) == 1){ | |
({ unsigned i = 0; while (__sync_lock_test_and_set(&fileLock, 1) && ++i < 0xFFFFFFF) asm("pause"); if (i >= 0xFFFFFFF) { (void)((!"Deadlock!") || (KernelAssertionFailed("!\"Deadlock!\"", "../Kernel/include/Lock.h", 101), 0)); } }); | |
} | |
({ __sync_lock_release(&lock); });; | |
} | |
__attribute__(( always_inline )) inline void AcquireWrite(){ | |
({ unsigned i = 0; while (__sync_lock_test_and_set(&lock, 1) && ++i < 0xFFFFFFF) asm("pause"); if (i >= 0xFFFFFFF) { (void)((!"Deadlock!") || (KernelAssertionFailed("!\"Deadlock!\"", "../Kernel/include/Lock.h", 108), 0)); } }); | |
({ unsigned i = 0; while (__sync_lock_test_and_set(&fileLock, 1) && ++i < 0xFFFFFFF) asm("pause"); if (i >= 0xFFFFFFF) { (void)((!"Deadlock!") || (KernelAssertionFailed("!\"Deadlock!\"", "../Kernel/include/Lock.h", 109), 0)); } }); | |
} | |
__attribute__(( always_inline )) inline bool TryAcquireWrite(){ | |
if(!writerAcquiredLock && ({ int status; status = __sync_lock_test_and_set(&lock, 1); status; })){ | |
return true; | |
} | |
writerAcquiredLock = true; | |
if(({ int status; status = __sync_lock_test_and_set(&fileLock, 1); status; })){ | |
return true; | |
} | |
writerAcquiredLock = false; | |
return false; | |
} | |
__attribute__(( always_inline )) inline void ReleaseRead(){ | |
if(__atomic_sub_fetch(&activeReaders, 1, 3) == 0){ | |
({ __sync_lock_release(&fileLock); });; | |
} | |
} | |
__attribute__(( always_inline )) inline void ReleaseWrite(){ | |
({ __sync_lock_release(&fileLock); });; | |
({ __sync_lock_release(&lock); });; | |
} | |
__attribute__(( always_inline )) inline bool IsWriteLocked() const { return lock && activeReaders == 0; } | |
}; | |
using FilesystemLock = ReadWriteLock; | |
# 8 "../Kernel/include/Fs/Filesystem.h" 2 | |
# 1 "../Kernel/include/RefPtr.h" 1 | |
# 1 "../Kernel/include/TTraits.h" 1 | |
template <typename T> class TTraits { | |
public: | |
__attribute__(( always_inline )) inline static constexpr bool is_trivial() { return false; } | |
__attribute__(( always_inline )) inline static constexpr const char* name() { return "undefined"; } | |
}; | |
template <> class TTraits<char> { | |
public: | |
__attribute__(( always_inline )) inline static constexpr bool is_trivial() { return true; } | |
__attribute__(( always_inline )) inline static constexpr const char* name() { return "char"; } | |
}; | |
template <> class TTraits<int8_t> { | |
public: | |
__attribute__(( always_inline )) inline static constexpr bool is_trivial() { return true; } | |
__attribute__(( always_inline )) inline static constexpr const char* name() { return "int8_t"; } | |
}; | |
template <> class TTraits<uint8_t> { | |
public: | |
__attribute__(( always_inline )) inline static constexpr bool is_trivial() { return true; } | |
__attribute__(( always_inline )) inline static constexpr const char* name() { return "uint8_t"; } | |
}; | |
template <> class TTraits<int16_t> { | |
public: | |
__attribute__(( always_inline )) inline static constexpr bool is_trivial() { return true; } | |
__attribute__(( always_inline )) inline static constexpr const char* name() { return "int16_t"; } | |
}; | |
template <> class TTraits<uint16_t> { | |
public: | |
__attribute__(( always_inline )) inline static constexpr bool is_trivial() { return true; } | |
__attribute__(( always_inline )) inline static constexpr const char* name() { return "uint16_t"; } | |
}; | |
template <> class TTraits<int32_t> { | |
public: | |
__attribute__(( always_inline )) inline static constexpr bool is_trivial() { return true; } | |
__attribute__(( always_inline )) inline static constexpr const char* name() { return "int32_t"; } | |
}; | |
template <> class TTraits<uint32_t> { | |
public: | |
__attribute__(( always_inline )) inline static constexpr bool is_trivial() { return true; } | |
__attribute__(( always_inline )) inline static constexpr const char* name() { return "uint32_t"; } | |
}; | |
template <> class TTraits<int64_t> { | |
public: | |
__attribute__(( always_inline )) inline static constexpr bool is_trivial() { return true; } | |
__attribute__(( always_inline )) inline static constexpr const char* name() { return "int64_t"; } | |
}; | |
template <> class TTraits<uint64_t> { | |
public: | |
__attribute__(( always_inline )) inline static constexpr bool is_trivial() { return true; } | |
__attribute__(( always_inline )) inline static constexpr const char* name() { return "uint64_t"; } | |
}; | |
template <typename T> class TTraits<T*> { | |
public: | |
__attribute__(( always_inline )) inline static constexpr bool is_trivial() { return true; } | |
__attribute__(( always_inline )) inline static constexpr const char* name() { return "T*"; } | |
}; | |
# 5 "../Kernel/include/RefPtr.h" 2 | |
# 1 "../subprojects/cxxshim/stage2/include/cstddef" 1 | |
# 1 "/home/kai/.local/share/lemon/sysroot/system/include/c++/v1/stddef.h" 1 3 | |
# 5 "../subprojects/cxxshim/stage2/include/cstddef" 2 | |
namespace std { | |
enum class [[gnu::may_alias]] byte : unsigned char { }; | |
using nullptr_t = decltype(nullptr); | |
} | |
# 12 "../Kernel/include/RefPtr.h" 2 | |
template <typename T> class FancyRefPtr { | |
public: | |
template <class U> FancyRefPtr(const FancyRefPtr<U>& s, T* p) : refCount(s.GetRefCount()), obj(p) { | |
__sync_fetch_and_add(refCount, 1); | |
} | |
FancyRefPtr() : refCount(nullptr), obj(nullptr) {} | |
FancyRefPtr(std::nullptr_t) : refCount(nullptr), obj(nullptr) {} | |
FancyRefPtr(T&& v) { | |
refCount = new unsigned(1); | |
obj = new T(v); | |
} | |
FancyRefPtr(T* p) : obj(p) { | |
if (obj) { | |
refCount = new unsigned(1); | |
} else { | |
refCount = nullptr; | |
} | |
} | |
FancyRefPtr(const FancyRefPtr<T>& ptr) { | |
obj = ptr.obj; | |
refCount = ptr.refCount; | |
if (obj && refCount) { | |
__sync_fetch_and_add(refCount, 1); | |
} | |
} | |
FancyRefPtr(FancyRefPtr<T>&& ptr) { | |
obj = ptr.obj; | |
refCount = ptr.refCount; | |
ptr.obj = nullptr; | |
ptr.refCount = nullptr; | |
} | |
virtual ~FancyRefPtr() { Dereference(); } | |
__attribute__(( always_inline )) inline T* get() const { return obj; } | |
__attribute__(( always_inline )) inline unsigned* GetRefCount() const { return refCount; } | |
FancyRefPtr<T>& operator=(const FancyRefPtr<T>& ptr) { | |
Dereference(); | |
obj = ptr.obj; | |
refCount = ptr.refCount; | |
if (obj && refCount) { | |
__sync_fetch_and_add(refCount, 1); | |
} | |
return *this; | |
} | |
FancyRefPtr<T>& operator=(FancyRefPtr<T>&& ptr) { | |
Dereference(); | |
obj = ptr.obj; | |
refCount = ptr.refCount; | |
ptr.obj = nullptr; | |
ptr.refCount = nullptr; | |
return *this; | |
} | |
__attribute__(( always_inline )) inline FancyRefPtr& operator=(std::nullptr_t) { | |
Dereference(); | |
obj = nullptr; | |
refCount = nullptr; | |
return *this; | |
} | |
__attribute__(( always_inline )) inline bool operator==(const T* p) { return (obj == p); } | |
__attribute__(( always_inline )) inline bool operator!=(const T* p) { return (obj != p); } | |
__attribute__(( always_inline )) inline T& operator*() const { | |
(void)((obj) || (KernelAssertionFailed("obj", "../Kernel/include/RefPtr.h", 108), 0)); | |
return *(obj); | |
} | |
__attribute__(( always_inline )) inline T* operator->() const { | |
(void)((obj) || (KernelAssertionFailed("obj", "../Kernel/include/RefPtr.h", 116), 0)); | |
return obj; | |
} | |
__attribute__(( always_inline )) inline operator bool() { return obj; } | |
protected: | |
__attribute__(( always_inline )) inline void Dereference() { | |
if (refCount) { | |
__sync_fetch_and_sub(refCount, 1); | |
if (*refCount <= 0 && obj) { | |
delete obj; | |
delete refCount; | |
} | |
} | |
refCount = nullptr; | |
obj = nullptr; | |
} | |
unsigned* refCount = nullptr; | |
T* obj = nullptr; | |
}; | |
template <class T, class U> | |
__attribute__(( always_inline )) inline static constexpr FancyRefPtr<T> static_pointer_cast(const FancyRefPtr<U>& src) { | |
return FancyRefPtr<T>(src, static_cast<T*>(src.get())); | |
} | |
# 9 "../Kernel/include/Fs/Filesystem.h" 2 | |
# 1 "../Kernel/include/String.h" 1 | |
# 10 "../Kernel/include/String.h" | |
# 1 "../Kernel/include/Vector.h" 1 | |
# 1 "../Kernel/include/Arch/x86_64/Memory.h" 1 | |
# 1 "../Kernel/include/Arch/x86_64/PhysicalAllocator.h" 1 | |
# 1 "../Kernel/include/Arch/x86_64/Serial.h" 1 | |
namespace Serial { | |
void Initialize(); | |
void Unlock(); | |
void Write(const char c); | |
void Write(const char* s); | |
void Write(const char* s, unsigned n); | |
} | |
# 6 "../Kernel/include/Arch/x86_64/PhysicalAllocator.h" 2 | |
# 1 "/home/kai/.local/share/lemon/sysroot/system/include/c++/v1/stddef.h" 1 3 | |
# 7 "../Kernel/include/Arch/x86_64/PhysicalAllocator.h" 2 | |
# 17 "../Kernel/include/Arch/x86_64/PhysicalAllocator.h" | |
extern void* kernel_end; | |
namespace Memory { | |
void InitializePhysicalAllocator(memory_info_t* mem_info); | |
uint64_t GetFirstFreeMemoryBlock(); | |
void MarkMemoryRegionUsed(uint64_t base, size_t size); | |
void MarkMemoryRegionFree(uint64_t base, size_t size); | |
uint64_t AllocatePhysicalMemoryBlock(); | |
uint64_t AllocateLargePhysicalMemoryBlock(); | |
void FreePhysicalMemoryBlock(uint64_t addr); | |
extern uint64_t usedPhysicalBlocks; | |
extern uint64_t maxPhysicalBlocks; | |
} | |
# 7 "../Kernel/include/Arch/x86_64/Memory.h" 2 | |
typedef struct { | |
uint64_t base; | |
uint64_t pageCount; | |
} mem_region_t; | |
# 5 "../Kernel/include/Vector.h" 2 | |
template <typename T> class Vector { | |
class VectorIterator { | |
friend class Vector; | |
protected: | |
size_t pos = 0; | |
const Vector<T>& vector; | |
public: | |
VectorIterator(const Vector<T>& newVector) : vector(newVector){}; | |
VectorIterator(const VectorIterator& it) : vector(it.vector) { pos = it.pos; }; | |
VectorIterator& operator++() { | |
pos++; | |
return *this; | |
} | |
VectorIterator& operator++(int) { | |
auto it = *this; | |
pos++; | |
return it; | |
} | |
VectorIterator& operator=(const VectorIterator& other) { | |
VectorIterator(other.vector); | |
pos = other.pos; | |
return *this; | |
} | |
__attribute__(( always_inline )) inline T& operator*() const { return vector.data[pos]; } | |
__attribute__(( always_inline )) inline T* operator->() const { return &vector.data[pos]; } | |
__attribute__(( always_inline )) inline friend bool operator==(const VectorIterator& l, const VectorIterator& r) { | |
return l.pos == r.pos; | |
} | |
__attribute__(( always_inline )) inline friend bool operator!=(const VectorIterator& l, const VectorIterator& r) { | |
return l.pos != r.pos; | |
} | |
}; | |
private: | |
T* data = nullptr; | |
size_t count = 0; | |
size_t capacity = 0; | |
lock_t lock = 0; | |
public: | |
Vector() = default; | |
Vector(const Vector<T>& x) { | |
EnsureCapacity(x.get_length()); | |
for (unsigned i = 0; i < x.get_length(); i++) { | |
data[i] = x.data[i]; | |
} | |
} | |
template <typename... D> Vector(D... data) { (add_back(data), ...); } | |
__attribute__(( always_inline )) inline T& at(size_t pos) { | |
(void)((pos < count) || (KernelAssertionFailed("pos < count", "../Kernel/include/Vector.h", 74), 0)); | |
return data[pos]; | |
} | |
__attribute__(( always_inline )) inline const T& at(size_t pos) const { | |
(void)((pos < count) || (KernelAssertionFailed("pos < count", "../Kernel/include/Vector.h", 79), 0)); | |
return data[pos]; | |
} | |
__attribute__(( always_inline )) inline const T& get_at(size_t pos) const { return at(pos); } | |
__attribute__(( always_inline )) inline T& operator[](size_t pos) { return at(pos); } | |
__attribute__(( always_inline )) inline const T& operator[](size_t pos) const { return at(pos); } | |
__attribute__(( always_inline )) inline size_t size() const { return count; } | |
__attribute__(( always_inline )) inline size_t get_length() const { return count; } | |
void erase(unsigned pos) { | |
({ unsigned i = 0; while (__sync_lock_test_and_set(&lock, 1) && ++i < 0xFFFFFFF) asm("pause"); if (i >= 0xFFFFFFF) { (void)((!"Deadlock!") || (KernelAssertionFailed("!\"Deadlock!\"", "../Kernel/include/Vector.h", 94), 0)); } }); | |
EraseUnlocked(pos); | |
({ __sync_lock_release(&lock); });; | |
} | |
void reserve(size_t allocatedSize) { | |
({ unsigned i = 0; while (__sync_lock_test_and_set(&lock, 1) && ++i < 0xFFFFFFF) asm("pause"); if (i >= 0xFFFFFFF) { (void)((!"Deadlock!") || (KernelAssertionFailed("!\"Deadlock!\"", "../Kernel/include/Vector.h", 102), 0)); } }); | |
EnsureCapacity(allocatedSize); | |
({ __sync_lock_release(&lock); });; | |
} | |
void resize(size_t newSize) { | |
({ unsigned i = 0; while (__sync_lock_test_and_set(&lock, 1) && ++i < 0xFFFFFFF) asm("pause"); if (i >= 0xFFFFFFF) { (void)((!"Deadlock!") || (KernelAssertionFailed("!\"Deadlock!\"", "../Kernel/include/Vector.h", 110), 0)); } }); | |
EnsureCapacity(newSize); | |
size_t oldCount = count; | |
count = newSize; | |
if (count > oldCount) { | |
for (unsigned i = oldCount; i < count; i++) { | |
new (&data[i]) T(); | |
} | |
} else if (count < oldCount) { | |
if constexpr (!TTraits<T>::is_trivial()) { | |
for (unsigned i = count; i < oldCount; i++) { | |
data[i].~T(); | |
} | |
} | |
} | |
({ __sync_lock_release(&lock); });; | |
} | |
T& add_back(const T& val) { | |
({ unsigned i = 0; while (__sync_lock_test_and_set(&lock, 1) && ++i < 0xFFFFFFF) asm("pause"); if (i >= 0xFFFFFFF) { (void)((!"Deadlock!") || (KernelAssertionFailed("!\"Deadlock!\"", "../Kernel/include/Vector.h", 132), 0)); } }); | |
EnsureCapacity(count + 1); | |
T& ref = data[count]; | |
count++; | |
new (&ref) T(val); | |
({ __sync_lock_release(&lock); });; | |
return ref; | |
} | |
T& add_back(T&& val) { | |
({ unsigned i = 0; while (__sync_lock_test_and_set(&lock, 1) && ++i < 0xFFFFFFF) asm("pause"); if (i >= 0xFFFFFFF) { (void)((!"Deadlock!") || (KernelAssertionFailed("!\"Deadlock!\"", "../Kernel/include/Vector.h", 146), 0)); } }); | |
EnsureCapacity(count + 1); | |
T& ref = data[count]; | |
count++; | |
new (&ref) T(static_cast<T&&>(val)); | |
({ __sync_lock_release(&lock); });; | |
return ref; | |
} | |
T& pop_back() { | |
(void)((count) || (KernelAssertionFailed("count", "../Kernel/include/Vector.h", 160), 0)); | |
return data[--count]; | |
} | |
__attribute__(( always_inline )) inline T* Data() { return data; } | |
void remove(const T& val) { | |
({ unsigned i = 0; while (__sync_lock_test_and_set(&lock, 1) && ++i < 0xFFFFFFF) asm("pause"); if (i >= 0xFFFFFFF) { (void)((!"Deadlock!") || (KernelAssertionFailed("!\"Deadlock!\"", "../Kernel/include/Vector.h", 168), 0)); } }); | |
for (unsigned i = 0; i < count; i++) { | |
if (data[i] == val) { | |
EraseUnlocked(i); | |
return; | |
} | |
} | |
({ __sync_lock_release(&lock); });; | |
} | |
~Vector() { | |
if (data) { | |
kfree(data); | |
} | |
data = nullptr; | |
} | |
VectorIterator begin() const { | |
VectorIterator it = VectorIterator(*this); | |
it.pos = 0; | |
return it; | |
} | |
VectorIterator end() const { | |
VectorIterator it = VectorIterator(*this); | |
it.pos = count; | |
return it; | |
} | |
void clear() { | |
({ unsigned i = 0; while (__sync_lock_test_and_set(&lock, 1) && ++i < 0xFFFFFFF) asm("pause"); if (i >= 0xFFFFFFF) { (void)((!"Deadlock!") || (KernelAssertionFailed("!\"Deadlock!\"", "../Kernel/include/Vector.h", 204), 0)); } }); | |
if (data) { | |
kfree(data); | |
} | |
count = capacity = 0; | |
data = nullptr; | |
({ __sync_lock_release(&lock); });; | |
} | |
private: | |
__attribute__(( always_inline )) inline void EnsureCapacity(unsigned size) { | |
if (size >= capacity) { | |
size_t newCapacity = capacity + (size << 1) + 1; | |
if (data) { | |
T* oldData = data; | |
data = reinterpret_cast<T*>(kmalloc(newCapacity * sizeof(T))); | |
if constexpr (TTraits<T>::is_trivial()) { | |
memcpy(data, oldData, capacity * sizeof(T)); | |
memset(data + capacity, 0, sizeof(T) * (size - capacity)); | |
} else { | |
for (unsigned i = 0; i < count && i < capacity; i++) { | |
new (&data[i]) T(std::move(oldData[i])); | |
oldData[i].~T(); | |
} | |
for (unsigned i = capacity; i < size; i++) { | |
new (&data[i]) T(); | |
} | |
} | |
kfree(oldData); | |
} else { | |
data = reinterpret_cast<T*>(kmalloc(newCapacity * sizeof(T))); | |
} | |
capacity = newCapacity; | |
} | |
} | |
__attribute__(( always_inline )) inline void EraseUnlocked(unsigned pos) { | |
(void)((pos < count) || (KernelAssertionFailed("pos < count", "../Kernel/include/Vector.h", 247), 0)); | |
if constexpr (TTraits<T>::is_trivial()) { | |
memcpy(&data[pos], &data[pos + 1], (count - pos - 1) * sizeof(T)); | |
} else { | |
for (unsigned i = pos; i < count - 1; i++) { | |
data[i] = std::move(data[i + 1]); | |
} | |
} | |
count--; | |
} | |
}; | |
# 11 "../Kernel/include/String.h" 2 | |
template <typename T> class BasicString { | |
private: | |
const unsigned c_bufferRound = 32; | |
static_assert(TTraits<T>::is_trivial()); | |
public: | |
BasicString() { | |
m_buffer = nullptr; | |
m_bufferSize = 0; | |
m_len = 0; | |
(void)((Empty()) || (KernelAssertionFailed("Empty()", "../Kernel/include/String.h", 23), 0)); | |
} | |
BasicString(const T* data) { | |
m_buffer = nullptr; | |
CopyFromNullTerminatedBuffer(data); | |
} | |
BasicString(const T* data, size_t len) { | |
m_buffer = nullptr; | |
CopyFromBuffer(data, len); | |
} | |
BasicString(const BasicString& other) { | |
Resize(other.m_len); | |
memcpy(m_buffer, other.m_buffer, m_len * sizeof(T)); | |
m_buffer[m_len] = 0; | |
} | |
BasicString(BasicString&& other) { | |
ScopedSpinLock acq(other.m_lock); | |
m_len = other.m_len; | |
m_bufferSize = other.m_bufferSize; | |
m_buffer = other.m_buffer; | |
other.m_len = 0; | |
other.m_buffer = 0; | |
other.m_bufferSize = 0; | |
} | |
~BasicString() { | |
ScopedSpinLock acq(m_lock); | |
if (m_buffer) { | |
delete[] m_buffer; | |
m_buffer = nullptr; | |
} | |
m_len = 0; | |
m_bufferSize = 0; | |
} | |
BasicString& operator=(const BasicString& other) { | |
ScopedSpinLock acq(m_lock); | |
Resize(other.m_len); | |
memcpy(m_buffer, other.m_buffer, m_len * sizeof(T)); | |
m_buffer[m_len] = 0; | |
return *this; | |
} | |
BasicString& operator=(BasicString&& other) { | |
ScopedSpinLock acq(m_lock); | |
ScopedSpinLock acqOther(other.m_lock); | |
m_len = other.m_len; | |
m_bufferSize = other.m_bufferSize; | |
m_buffer = other.m_buffer; | |
other.m_len = 0; | |
other.m_buffer = 0; | |
return *this; | |
} | |
BasicString& operator+=(const BasicString& other) { | |
ScopedSpinLock acq(m_lock); | |
unsigned oldLen = m_len; | |
Resize(oldLen + other.m_len); | |
memcpy((m_buffer + oldLen), other.m_buffer, other.m_len * sizeof(T)); | |
return *this; | |
} | |
BasicString& operator+=(const T* data) { | |
ScopedSpinLock acq(m_lock); | |
unsigned oldLen = m_len; | |
unsigned dataLen = 0; | |
while (data[dataLen]) | |
dataLen++; | |
Resize(oldLen + dataLen); | |
memcpy((m_buffer + oldLen), data, dataLen); | |
return *this; | |
} | |
T& operator[](unsigned pos) { return m_buffer[pos]; } | |
const T& operator[](unsigned pos) const { return m_buffer[pos]; } | |
Vector<BasicString<T>> Split(T delim) const { | |
Vector<BasicString<T>> result; | |
int start = 0; | |
unsigned i = 0; | |
for (; i < m_len; i++) { | |
if (m_buffer[i] == delim) { | |
if ((i - start) > 0) { | |
result.add_back(BasicString<T>((m_buffer + start), (i - start))); | |
} | |
start = i + 1; | |
} | |
} | |
if ((i - start) > 0) { | |
result.add_back(BasicString<T>((m_buffer + start), (i - start))); | |
} | |
return result; | |
} | |
int Compare(const T* data) const { | |
const T* s1 = m_buffer; | |
while (*s1 == *data) { | |
if (!(*s1)) { | |
return 0; | |
} | |
s1++; | |
data++; | |
} | |
return (*s1) - (*data); | |
}; | |
__attribute__(( always_inline )) inline int Compare(const BasicString& other) const { return Compare(other.Data()); }; | |
__attribute__(( always_inline )) inline unsigned Length() const { return m_len; } | |
__attribute__(( always_inline )) inline const T* Data() const { return m_buffer; } | |
__attribute__(( always_inline )) inline const T* c_str() const { (void)((m_buffer) || (KernelAssertionFailed("m_buffer", "../Kernel/include/String.h", 167), 0)); return m_buffer; } | |
__attribute__(( always_inline )) inline bool Empty() const { return (!m_buffer) || (m_len == 0); } | |
protected: | |
lock_t m_lock = 0; | |
unsigned m_len = 0; | |
unsigned m_bufferSize = 0; | |
T* m_buffer = nullptr; | |
__attribute__(( always_inline )) inline void CopyFromNullTerminatedBuffer(const T* data) { | |
unsigned len = 0; | |
while (data[len]) | |
len++; | |
CopyFromBuffer(data, len); | |
} | |
__attribute__(( always_inline )) inline void CopyFromBuffer(const T* data, size_t len) { | |
Resize(len); | |
memcpy(m_buffer, data, m_len * sizeof(T)); | |
m_buffer[m_len] = 0; | |
} | |
__attribute__(( always_inline )) inline void Resize(unsigned newLen) { | |
if (m_buffer && newLen < m_bufferSize) { | |
m_len = newLen; | |
m_buffer[m_len] = 0; | |
return; | |
} | |
m_bufferSize = (newLen + 1 + c_bufferRound - 1) & ~(c_bufferRound - 1); | |
T* newBuffer = new T[m_bufferSize]; | |
if (m_buffer) { | |
memcpy(newBuffer, m_buffer, m_len * sizeof(T)); | |
delete[] m_buffer; | |
} | |
m_buffer = newBuffer; | |
m_len = newLen; | |
m_buffer[m_len] = 0; | |
} | |
}; | |
template <typename T> BasicString<T> operator+(const BasicString<T>& l, const T* r) { | |
BasicString<T> str(l); | |
str += r; | |
return str; | |
} | |
template <typename T, typename U> BasicString<T> operator+(const BasicString<T>& l, const U& r) { | |
BasicString<T> str(l); | |
str += r; | |
return str; | |
} | |
using String = BasicString<char>; | |
__attribute__(( always_inline )) inline String to_string(int num, int base = 10) { | |
char buf[128]; | |
buf[127] = 0; | |
int i = 127; | |
if (num == 0) { | |
buf[--i] = '0'; | |
} | |
while (num != 0 && i) { | |
int rem = num % base; | |
buf[--i] = (rem > 9) ? (rem - 10) + 'a' : rem + '0'; | |
num = num / base; | |
} | |
return String(buf + i); | |
} | |
__attribute__(( always_inline )) inline String to_string(long num, int base = 10) { | |
char buf[128]; | |
buf[127] = 0; | |
int i = 127; | |
if (num == 0) { | |
buf[--i] = '0'; | |
} | |
while (num != 0 && i) { | |
int rem = num % base; | |
buf[--i] = (rem > 9) ? (rem - 10) + 'a' : rem + '0'; | |
num = num / base; | |
} | |
return String(buf + i); | |
} | |
__attribute__(( always_inline )) inline String to_string(unsigned num, int base = 10) { | |
char buf[128]; | |
buf[127] = 0; | |
int i = 127; | |
if (num == 0) { | |
buf[--i] = '0'; | |
} | |
while (num != 0 && i) { | |
int rem = num % base; | |
buf[--i] = (rem > 9) ? (rem - 10) + 'a' : rem + '0'; | |
num = num / base; | |
} | |
return String(buf + i); | |
} | |
String to_string(const struct IPv4Address& addr); | |
String to_string(const struct MACAddress& addr); | |
# 10 "../Kernel/include/Fs/Filesystem.h" 2 | |
# 1 "../Kernel/include/Arch/x86_64/Types.h" 1 | |
typedef long long ssize_t; | |
# 11 "../Kernel/include/Fs/Filesystem.h" 2 | |
# 1 "/home/kai/.local/share/lemon/sysroot/system/include/abi-bits/abi.h" 1 3 | |
# 13 "../Kernel/include/Fs/Filesystem.h" 2 | |
# 1 "/home/kai/.local/share/lemon/sysroot/system/include/abi-bits/fcntl.h" 1 3 | |
# 14 "../Kernel/include/Fs/Filesystem.h" 2 | |
# 95 "../Kernel/include/Fs/Filesystem.h" | |
typedef int64_t ino_t; | |
typedef uint64_t dev_t; | |
typedef int64_t off_t; | |
typedef int32_t mode_t; | |
typedef int32_t nlink_t; | |
typedef int64_t volume_id_t; | |
typedef struct { | |
dev_t st_dev; | |
ino_t st_ino; | |
mode_t st_mode; | |
nlink_t st_nlink; | |
uid_t st_uid; | |
uid_t st_gid; | |
dev_t st_rdev; | |
off_t st_size; | |
int64_t st_blksize; | |
int64_t st_blocks; | |
} stat_t; | |
class FsNode; | |
struct UNIXFileDescriptor; | |
struct pollfd { | |
int fd; | |
short events; | |
short revents; | |
}; | |
typedef struct { | |
char fds_bits[128]; | |
} fd_set_t; | |
static inline void FD_CLR(int fd, fd_set_t* fds) { | |
(void)((fd < 1024) || (KernelAssertionFailed("fd < FD_SETSIZE", "../Kernel/include/Fs/Filesystem.h", 129), 0)); | |
fds->fds_bits[fd / 8] &= ~(1 << (fd % 8)); | |
} | |
static inline int FD_ISSET(int fd, fd_set_t* fds) { | |
(void)((fd < 1024) || (KernelAssertionFailed("fd < FD_SETSIZE", "../Kernel/include/Fs/Filesystem.h", 134), 0)); | |
return fds->fds_bits[fd / 8] & (1 << (fd % 8)); | |
} | |
static inline void FD_SET(int fd, fd_set_t* fds) { | |
(void)((fd < 1024) || (KernelAssertionFailed("fd < FD_SETSIZE", "../Kernel/include/Fs/Filesystem.h", 139), 0)); | |
fds->fds_bits[fd / 8] |= 1 << (fd % 8); | |
} | |
class FilesystemWatcher; | |
class DirectoryEntry; | |
class FsNode { | |
friend class FilesystemBlocker; | |
public: | |
lock_t blockedLock = 0; | |
FastList<class FilesystemBlocker*> blocked; | |
uint32_t flags = 0; | |
uint32_t pmask = 0; | |
uid_t uid = 0; | |
ino_t inode = 0; | |
size_t size = 0; | |
int nlink = 0; | |
unsigned handleCount = 0; | |
volume_id_t volumeID; | |
int error = 0; | |
virtual ~FsNode(); | |
# 176 "../Kernel/include/Fs/Filesystem.h" | |
virtual ssize_t Read(size_t off, size_t size, uint8_t* buffer); | |
# 188 "../Kernel/include/Fs/Filesystem.h" | |
virtual ssize_t Write(size_t off, size_t size, uint8_t* buffer); | |
virtual UNIXFileDescriptor* Open(size_t flags); | |
virtual void Close(); | |
virtual int ReadDir(DirectoryEntry*, uint32_t); | |
virtual FsNode* FindDir(const char* name); | |
virtual int Create(DirectoryEntry* ent, uint32_t mode); | |
virtual int CreateDirectory(DirectoryEntry* ent, uint32_t mode); | |
virtual ssize_t ReadLink(char* pathBuffer, size_t bufSize); | |
virtual int Link(FsNode*, DirectoryEntry*); | |
virtual int Unlink(DirectoryEntry*, bool unlinkDirectories = false); | |
virtual int Truncate(off_t length); | |
virtual int Ioctl(uint64_t cmd, uint64_t arg); | |
virtual void Sync(); | |
virtual bool CanRead() { return true; } | |
virtual bool CanWrite() { return true; } | |
virtual void Watch(FilesystemWatcher& watcher, int events); | |
virtual void Unwatch(FilesystemWatcher& watcher); | |
virtual inline bool IsFile() { return (flags & 0xF000) == 0x8000; } | |
virtual inline bool IsDirectory() { return (flags & 0xF000) == 0x4000; } | |
virtual inline bool IsBlockDevice() { return (flags & 0xF000) == 0x6000; } | |
virtual inline bool IsSymlink() { return (flags & 0xF000) == 0xA000; } | |
virtual inline bool IsCharDevice() { return (flags & 0xF000) == 0x2000; } | |
virtual inline bool IsSocket() { return (flags & 0xF000) == 0xC000; } | |
virtual inline bool IsEPoll() const { return false; } | |
void UnblockAll(); | |
FsNode* link; | |
FsNode* parent; | |
FilesystemLock nodeLock; | |
}; | |
typedef struct UNIXFileDescriptor { | |
FsNode* node = nullptr; | |
off_t pos = 0; | |
mode_t mode = 0; | |
~UNIXFileDescriptor(); | |
} fs_fd_t; | |
class DirectoryEntry { | |
public: | |
char name[255]; | |
FsNode* node = nullptr; | |
uint32_t inode = 0; | |
DirectoryEntry* parent = nullptr; | |
mode_t flags = 0; | |
DirectoryEntry(FsNode* node, const char* name); | |
DirectoryEntry() {} | |
static mode_t FileToDirentFlags(mode_t flags) { | |
switch (flags & 0xF000) { | |
case 0x8000: | |
flags = 8; | |
break; | |
case 0x4000: | |
flags = 4; | |
break; | |
case 0x2000: | |
flags = 2; | |
break; | |
case 0x6000: | |
flags = 6; | |
break; | |
case 0xC000: | |
flags = 12; | |
break; | |
case 0xA000: | |
flags = 10; | |
break; | |
default: | |
(void)((!"Invalid file flags!") || (KernelAssertionFailed("!\"Invalid file flags!\"", "../Kernel/include/Fs/Filesystem.h", 273), 0)); | |
} | |
return flags; | |
} | |
}; | |
class FilesystemWatcher : public Semaphore { | |
List<UNIXFileDescriptor*> watching; | |
public: | |
FilesystemWatcher() : Semaphore(0) {} | |
inline void WatchNode(FsNode* node, int events) { | |
UNIXFileDescriptor* desc = node->Open(0); | |
(void)((desc) || (KernelAssertionFailed("desc", "../Kernel/include/Fs/Filesystem.h", 290), 0)); | |
desc->node->Watch(*this, events); | |
watching.add_back(desc); | |
} | |
~FilesystemWatcher() { | |
for (auto& fd : watching) { | |
fd->node->Unwatch(*this); | |
delete fd; | |
} | |
} | |
}; | |
class FilesystemBlocker : public ThreadBlocker { | |
friend FsNode; | |
friend FastList<FilesystemBlocker*>; | |
public: | |
enum BlockType { | |
BlockRead, | |
BlockWrite, | |
}; | |
protected: | |
FsNode* node = nullptr; | |
FilesystemBlocker* next; | |
FilesystemBlocker* prev; | |
int blockType = BlockType::BlockRead; | |
size_t requestedLength = 1; | |
public: | |
FilesystemBlocker(FsNode* _node) : node(_node) { | |
({ unsigned i = 0; while (__sync_lock_test_and_set(&lock, 1) && ++i < 0xFFFFFFF) asm("pause"); if (i >= 0xFFFFFFF) { (void)((!"Deadlock!") || (KernelAssertionFailed("!\"Deadlock!\"", "../Kernel/include/Fs/Filesystem.h", 327), 0)); } }); | |
({ unsigned i = 0; while (__sync_lock_test_and_set(&node->blockedLock, 1) && ++i < 0xFFFFFFF) asm("pause"); if (i >= 0xFFFFFFF) { (void)((!"Deadlock!") || (KernelAssertionFailed("!\"Deadlock!\"", "../Kernel/include/Fs/Filesystem.h", 329), 0)); } }); | |
node->blocked.add_back(this); | |
({ __sync_lock_release(&node->blockedLock); });; | |
({ __sync_lock_release(&lock); });; | |
} | |
FilesystemBlocker(FsNode* _node, size_t len) : node(_node), requestedLength(len) { | |
({ unsigned i = 0; while (__sync_lock_test_and_set(&lock, 1) && ++i < 0xFFFFFFF) asm("pause"); if (i >= 0xFFFFFFF) { (void)((!"Deadlock!") || (KernelAssertionFailed("!\"Deadlock!\"", "../Kernel/include/Fs/Filesystem.h", 337), 0)); } }); | |
({ unsigned i = 0; while (__sync_lock_test_and_set(&node->blockedLock, 1) && ++i < 0xFFFFFFF) asm("pause"); if (i >= 0xFFFFFFF) { (void)((!"Deadlock!") || (KernelAssertionFailed("!\"Deadlock!\"", "../Kernel/include/Fs/Filesystem.h", 339), 0)); } }); | |
node->blocked.add_back(this); | |
({ __sync_lock_release(&node->blockedLock); });; | |
({ __sync_lock_release(&lock); });; | |
} | |
void Interrupt(); | |
inline void Unblock() { | |
shouldBlock = false; | |
({ unsigned i = 0; while (__sync_lock_test_and_set(&lock, 1) && ++i < 0xFFFFFFF) asm("pause"); if (i >= 0xFFFFFFF) { (void)((!"Deadlock!") || (KernelAssertionFailed("!\"Deadlock!\"", "../Kernel/include/Fs/Filesystem.h", 351), 0)); } }); | |
if (node && !removed) { | |
node->blocked.remove(this); | |
removed = true; | |
} | |
node = nullptr; | |
if (thread) { | |
thread->Unblock(); | |
} | |
({ __sync_lock_release(&lock); });; | |
} | |
inline size_t RequestedLength() { return requestedLength; } | |
~FilesystemBlocker(); | |
}; | |
typedef struct fs_dirent { | |
uint32_t inode; | |
uint32_t type; | |
char name[255]; | |
} fs_dirent_t; | |
namespace fs { | |
class FsVolume; | |
class FsDriver { | |
public: | |
virtual ~FsDriver() = default; | |
virtual FsVolume* Mount(FsNode* device, const char* name) = 0; | |
virtual FsVolume* Unmount(FsVolume* volume) = 0; | |
virtual int Identify(FsNode* device) = 0; | |
virtual const char* ID() const = 0; | |
}; | |
extern List<FsDriver*> drivers; | |
void Initialize(); | |
FsNode* GetRoot(); | |
# 405 "../Kernel/include/Fs/Filesystem.h" | |
void RegisterDriver(FsDriver* driver); | |
void UnregisterDriver(FsDriver* driver); | |
FsDriver* IdentifyFilesystem(FsNode* node); | |
# 418 "../Kernel/include/Fs/Filesystem.h" | |
FsNode* FollowLink(FsNode* link, FsNode* workingDir); | |
# 428 "../Kernel/include/Fs/Filesystem.h" | |
FsNode* ResolvePath(const String& path, const char* workingDir = nullptr, bool followSymlinks = true); | |
# 438 "../Kernel/include/Fs/Filesystem.h" | |
FsNode* ResolvePath(const String& path, FsNode* workingDir, bool followSymlinks = true); | |
# 448 "../Kernel/include/Fs/Filesystem.h" | |
FsNode* ResolveParent(const char* path, const char* workingDir = nullptr); | |
char* CanonicalizePath(const char* path, char* workingDir); | |
char* BaseName(const char* path); | |
# 464 "../Kernel/include/Fs/Filesystem.h" | |
ssize_t Read(FsNode* node, size_t offset, size_t size, void* buffer); | |
# 478 "../Kernel/include/Fs/Filesystem.h" | |
ssize_t Write(FsNode* node, size_t offset, size_t size, void* buffer); | |
UNIXFileDescriptor* Open(FsNode* node, uint32_t flags = 0); | |
void Close(FsNode* node); | |
void Close(UNIXFileDescriptor* handle); | |
int ReadDir(FsNode* node, DirectoryEntry* dirent, uint32_t index); | |
FsNode* FindDir(FsNode* node, const char* name); | |
ssize_t Read(const FancyRefPtr<UNIXFileDescriptor>& handle, size_t size, uint8_t* buffer); | |
ssize_t Write(const FancyRefPtr<UNIXFileDescriptor>& handle, size_t size, uint8_t* buffer); | |
int ReadDir(const FancyRefPtr<UNIXFileDescriptor>& handle, DirectoryEntry* dirent, uint32_t index); | |
FsNode* FindDir(const FancyRefPtr<UNIXFileDescriptor>& handle, const char* name); | |
int Link(FsNode*, FsNode*, DirectoryEntry*); | |
int Unlink(FsNode*, DirectoryEntry*, bool unlinkDirectories = false); | |
int Ioctl(const FancyRefPtr<UNIXFileDescriptor>& handle, uint64_t cmd, uint64_t arg); | |
int Rename(FsNode* olddir, char* oldpath, FsNode* newdir, char* newpath); | |
} | |
__attribute__(( always_inline )) inline UNIXFileDescriptor::~UNIXFileDescriptor() { fs::Close(this); } | |
# 10 "../Kernel/include/Objects/Process.h" 2 | |
# 1 "../Kernel/include/Hash.h" 1 | |
static inline unsigned HashU(unsigned value){ | |
unsigned hash = value; | |
hash = ((hash >> 5) ^ hash) * 47499631; | |
hash = ((hash >> 5) ^ hash) * 47499631; | |
hash = (hash >> 5) ^ hash; | |
return hash; | |
} | |
template<typename T> | |
unsigned Hash(const T& value); | |
template<typename K, typename T> | |
class HashMap{ | |
public: | |
class KeyValuePair{ | |
friend class HashMap; | |
friend class HashMapIterator; | |
protected: | |
T value; | |
K key; | |
KeyValuePair(K key, T value) : value(value), key(key){} | |
}; | |
class HashMapIterator { | |
friend class HashMap<K, T>; | |
protected: | |
HashMap<K, T>* map; | |
unsigned bucketIndex = 0; | |
List<KeyValuePair>* bucket; | |
ListIterator<KeyValuePair> listIt; | |
public: | |
HashMapIterator() = default; | |
HashMapIterator(const HashMapIterator&) = default; | |
HashMapIterator& operator++(){ | |
(void)((listIt != bucket->end()) || (KernelAssertionFailed("listIt != bucket->end()", "../Kernel/include/Hash.h", 47), 0)); | |
listIt++; | |
if(listIt == bucket->end() && bucketIndex < map->bucketCount - 1){ | |
bucket = map->buckets[++bucketIndex]; | |
listIt = bucket->begin(); | |
} | |
return *this; | |
} | |
HashMapIterator& operator++(int){ | |
ListIterator<KeyValuePair> v = ListIterator<KeyValuePair>(*this); | |
(void)((listIt != bucket->end()) || (KernelAssertionFailed("listIt != bucket->end()", "../Kernel/include/Hash.h", 62), 0)); | |
listIt++; | |
if(listIt == bucket->end() && bucketIndex < map->bucketCount - 1){ | |
bucket = map->buckets[++bucketIndex]; | |
listIt = bucket->begin(); | |
} | |
return v; | |
} | |
T& operator*(){ | |
return listIt.operator*().value; | |
} | |
T* operator->(){ | |
return &listIt.operator->()->value; | |
} | |
friend bool operator==(const HashMapIterator& l, const HashMapIterator& r){ | |
if(l.listIt == r.listIt){ | |
return true; | |
} else { | |
return false; | |
} | |
} | |
friend bool operator!=(const HashMapIterator& l, const HashMapIterator& r){ | |
if(l.listIt != r.listIt){ | |
return true; | |
} else { | |
return false; | |
} | |
} | |
}; | |
HashMap(){ | |
buckets = new List<KeyValuePair>[bucketCount]; | |
lock = 0; | |
} | |
HashMap(unsigned bCount){ | |
bucketCount = bCount; | |
buckets = new List<KeyValuePair>[bucketCount]; | |
lock = 0; | |
} | |
void insert(K key, const T& value){ | |
auto& bucket = buckets[Hash(key) % bucketCount]; | |
({ unsigned i = 0; while (__sync_lock_test_and_set(&lock, 1) && ++i < 0xFFFFFFF) asm("pause"); if (i >= 0xFFFFFFF) { (void)((!"Deadlock!") || (KernelAssertionFailed("!\"Deadlock!\"", "../Kernel/include/Hash.h", 114), 0)); } }); | |
for(KeyValuePair& v : bucket){ | |
if(v.key == key){ | |
v.value = value; | |
itemCount++; | |
({ __sync_lock_release(&lock); });; | |
return; | |
} | |
} | |
bucket.add_back(KeyValuePair(key, value)); | |
({ __sync_lock_release(&lock); });; | |
} | |
T remove(K key){ | |
auto& bucket = buckets[Hash(key) % bucketCount]; | |
({ unsigned i = 0; while (__sync_lock_test_and_set(&lock, 1) && ++i < 0xFFFFFFF) asm("pause"); if (i >= 0xFFFFFFF) { (void)((!"Deadlock!") || (KernelAssertionFailed("!\"Deadlock!\"", "../Kernel/include/Hash.h", 133), 0)); } }); | |
for(unsigned i = 0; i < bucket.get_length(); i++){ | |
if(bucket[i].key == key){ | |
auto pair = bucket.remove_at(i); | |
itemCount--; | |
({ __sync_lock_release(&lock); });; | |
return pair.value; | |
} | |
} | |
({ __sync_lock_release(&lock); });; | |
return T(); | |
} | |
void removeValue(T value){ | |
({ unsigned i = 0; while (__sync_lock_test_and_set(&lock, 1) && ++i < 0xFFFFFFF) asm("pause"); if (i >= 0xFFFFFFF) { (void)((!"Deadlock!") || (KernelAssertionFailed("!\"Deadlock!\"", "../Kernel/include/Hash.h", 150), 0)); } }); | |
for(unsigned b = 0; b < bucketCount; b++){ | |
auto& bucket = buckets[b]; | |
for(unsigned i = 0; i < bucket.get_length(); i++){ | |
if(bucket[i].value == value){ | |
bucket.remove_at(i); | |
itemCount--; | |
({ __sync_lock_release(&lock); });; | |
return; | |
} | |
} | |
} | |
({ __sync_lock_release(&lock); });; | |
return; | |
} | |
int get(const K& key, T& value){ | |
auto& bucket = buckets[Hash(key) % bucketCount]; | |
({ unsigned i = 0; while (__sync_lock_test_and_set(&lock, 1) && ++i < 0xFFFFFFF) asm("pause"); if (i >= 0xFFFFFFF) { (void)((!"Deadlock!") || (KernelAssertionFailed("!\"Deadlock!\"", "../Kernel/include/Hash.h", 173), 0)); } }); | |
for(KeyValuePair& val : bucket){ | |
if(val.key == key){ | |
({ __sync_lock_release(&lock); });; | |
value = val.value; | |
return 1; | |
} | |
} | |
({ __sync_lock_release(&lock); });; | |
return 0; | |
} | |
int find(K key){ | |
auto& bucket = buckets[Hash(key) % bucketCount]; | |
for(KeyValuePair& val : bucket){ | |
if(val.key == key){ | |
return 1; | |
} | |
} | |
return 0; | |
} | |
unsigned get_length(){ | |
return itemCount; | |
} | |
HashMapIterator begin(){ | |
HashMapIterator it; | |
it.bucket = buckets[0]; | |
it.bucketIndex = 0; | |
it.map = this; | |
it.listIt = it.bucket->begin(); | |
return it; | |
} | |
HashMapIterator end(){ | |
HashMapIterator it; | |
it.bucket = buckets[bucketCount - 1]; | |
it.bucketIndex = bucketCount - 1; | |
it.map = this; | |
it.listIt = it.bucket->end(); | |
return it; | |
} | |
~HashMap(){ | |
delete[](buckets); | |
} | |
private: | |
List<KeyValuePair>* buckets; | |
unsigned bucketCount = 512; | |
unsigned itemCount = 0; | |
lock_t lock = 0; | |
}; | |
# 11 "../Kernel/include/Objects/Process.h" 2 | |
# 1 "../Kernel/include/MM/AddressSpace.h" 1 | |
# 1 "../Kernel/include/Pair.h" 1 | |
template <typename T1, typename T2> | |
class Pair{ | |
public: | |
T1 item1; | |
T2 item2; | |
Pair(const T1 one, const T2 two){ | |
item1 = one; | |
item2 = two; | |
} | |
Pair(){ | |
} | |
}; | |
# 6 "../Kernel/include/MM/AddressSpace.h" 2 | |
# 1 "../Kernel/include/MM/VMObject.h" 1 | |
# 1 "/home/kai/.local/share/lemon/sysroot/system/include/c++/v1/stddef.h" 1 3 | |
# 5 "../Kernel/include/MM/VMObject.h" 2 | |
class VMObject { | |
friend class AddressSpace; | |
friend void ::Memory::PageFaultHandler(void*, struct RegisterContext*); | |
public: | |
VMObject(size_t size, bool anonymous, bool shared); | |
virtual ~VMObject() = default; | |
virtual int Hit(uintptr_t base, uintptr_t offset, PageMap* pMap); | |
virtual void MapAllocatedBlocks(uintptr_t base, PageMap* pMap) = 0; | |
virtual VMObject* Clone() = 0; | |
virtual VMObject* Split(uintptr_t offset); | |
__attribute__(( always_inline )) inline size_t Size() const { return size; } | |
virtual size_t UsedPhysicalMemory() const { return 0; } | |
__attribute__(( always_inline )) inline bool IsAnonymous() const { return anonymous; } | |
__attribute__(( always_inline )) inline bool IsShared() const { return shared; } | |
__attribute__(( always_inline )) inline bool IsCopyOnWrite() const { return copyOnWrite; } | |
__attribute__(( always_inline )) inline bool IsReclaimable() const { return reclaimable; } | |
__attribute__(( always_inline )) inline virtual bool CanMunmap() const { return false; } | |
__attribute__(( always_inline )) inline size_t ReferenceCount() const { return refCount; } | |
protected: | |
size_t size; | |
size_t refCount = 0; | |
bool anonymous : 1 = true; | |
bool shared : 1 = false; | |
bool copyOnWrite : 1 = false; | |
bool reclaimable : 1 = false; | |
}; | |
class PhysicalVMObject : public VMObject { | |
public: | |
PhysicalVMObject(size_t size, bool anonymous, bool shared); | |
virtual ~PhysicalVMObject(); | |
int Hit(uintptr_t base, uintptr_t offset, PageMap* pMap) final; | |
void ForceAllocate(); | |
virtual void MapAllocatedBlocks(uintptr_t base, PageMap* pMap); | |
virtual VMObject* Clone(); | |
virtual size_t UsedPhysicalMemory() const; | |
protected: | |
uint32_t* physicalBlocks = nullptr; | |
}; | |
class ProcessImageVMObject final : public PhysicalVMObject { | |
public: | |
ProcessImageVMObject(uintptr_t base, size_t size, bool write); | |
void MapAllocatedBlocks(uintptr_t base, PageMap* pMap); | |
protected: | |
bool write : 1 = true; | |
uintptr_t base; | |
}; | |
class AnonymousVMObject : public PhysicalVMObject{ | |
AnonymousVMObject(size_t size); | |
VMObject* Split(uintptr_t offset) override; | |
__attribute__(( always_inline )) inline bool CanMunmap() const override { return true; } | |
}; | |
struct MappedRegion { | |
uintptr_t base; | |
size_t size; | |
FancyRefPtr<VMObject> vmObject; | |
ReadWriteLock lock; | |
__attribute__(( always_inline )) inline uintptr_t Base() const { return base; } | |
__attribute__(( always_inline )) inline uintptr_t Size() const { return size; } | |
__attribute__(( always_inline )) inline uintptr_t End() const { return base + size; } | |
MappedRegion() = delete; | |
__attribute__(( always_inline )) inline MappedRegion(uintptr_t base, size_t size) | |
: base(base), size(size), vmObject(nullptr) { | |
} | |
__attribute__(( always_inline )) inline MappedRegion(uintptr_t base, size_t size, FancyRefPtr<VMObject> vmObject) | |
: base(base), size(size), vmObject(vmObject) { | |
} | |
__attribute__(( always_inline )) inline MappedRegion(const MappedRegion& region){ | |
base = region.base; | |
size = region.size; | |
vmObject = region.vmObject; | |
lock = ReadWriteLock(); | |
} | |
__attribute__(( always_inline )) inline MappedRegion& operator=(const MappedRegion& region){ | |
base = region.base; | |
size = region.size; | |
vmObject = region.vmObject; | |
lock = ReadWriteLock(); | |
return *this; | |
} | |
__attribute__(( always_inline )) inline MappedRegion(MappedRegion&& region){ | |
base = region.base; | |
size = region.size; | |
vmObject = std::move(region.vmObject); | |
region.base = region.size = 0; | |
} | |
__attribute__(( always_inline )) inline MappedRegion& operator=(MappedRegion&& region){ | |
base = region.base; | |
size = region.size; | |
vmObject = std::move(region.vmObject); | |
region.base = region.size = 0; | |
return *this; | |
} | |
}; | |
# 10 "../Kernel/include/MM/AddressSpace.h" 2 | |
class AddressSpace final { | |
public: | |
AddressSpace(PageMap* pm); | |
~AddressSpace(); | |
__attribute__(( always_inline )) inline AddressSpace* Kernel(); | |
# 30 "../Kernel/include/MM/AddressSpace.h" | |
MappedRegion* AddressToRegionReadLock(uintptr_t address); | |
# 41 "../Kernel/include/MM/AddressSpace.h" | |
MappedRegion* AddressToRegionWriteLock(uintptr_t address); | |
# 51 "../Kernel/include/MM/AddressSpace.h" | |
bool RangeInRegion(uintptr_t base, size_t size); | |
# 60 "../Kernel/include/MM/AddressSpace.h" | |
long UnmapRegion(MappedRegion* region); | |
MappedRegion* MapVMO(FancyRefPtr<VMObject> obj, uintptr_t base, bool fixed); | |
MappedRegion* AllocateAnonymousVMObject(size_t size, uintptr_t base, bool fixed); | |
AddressSpace* Fork(); | |
long UnmapMemory(uintptr_t base, size_t size); | |
void UnmapAll(); | |
size_t UsedPhysicalMemory() const; | |
void DumpRegions(); | |
__attribute__((always_inline)) inline PageMap* GetPageMap() { return m_pageMap; } | |
protected: | |
MappedRegion* FindAvailableRegion(size_t size); | |
MappedRegion* AllocateRegionAt(uintptr_t base, size_t size); | |
__attribute__(( always_inline )) inline bool IsKernel() const { return this == m_kernel; } | |
AddressSpace* m_kernel; | |
uintptr_t m_startRegion = 0; | |
uintptr_t m_endRegion = 0xFFFFFFFF80000000ULL; | |
lock_t m_lock = 0; | |
PageMap* m_pageMap = nullptr; | |
List<MappedRegion> m_regions; | |
AddressSpace* m_parent = nullptr; | |
}; | |
# 13 "../Kernel/include/Objects/Process.h" 2 | |
# 1 "../Kernel/include/Objects/Handle.h" 1 | |
# 1 "../Kernel/include/Objects/KObject.h" 1 | |
# 13 "../Kernel/include/Objects/KObject.h" | |
typedef long kobject_id_t; | |
class KernelObjectWatcher; | |
class KernelObject { | |
protected: | |
int64_t oid = -1; | |
static int64_t nextOID; | |
public: | |
KernelObject() { oid = nextOID++; } | |
inline int64_t ObjectID() { return oid; } | |
virtual kobject_id_t InstanceTypeID() const = 0; | |
inline bool IsType(kobject_id_t id) { return InstanceTypeID() == id; } | |
virtual void Watch(KernelObjectWatcher& watcher, int events); | |
virtual void Unwatch(KernelObjectWatcher& watcher); | |
virtual void Destroy() = 0; | |
virtual ~KernelObject() = default; | |
}; | |
class KernelObjectWatcher : public Semaphore { | |
List<FancyRefPtr<KernelObject>> watching; | |
public: | |
KernelObjectWatcher() : Semaphore(0) {} | |
inline void WatchObject(FancyRefPtr<KernelObject> node, int events) { | |
node->Watch(*this, events); | |
watching.add_back(node); | |
} | |
~KernelObjectWatcher() { | |
for (auto& node : watching) { | |
node->Unwatch(*this); | |
} | |
watching.clear(); | |
} | |
}; | |
# 4 "../Kernel/include/Objects/Handle.h" 2 | |
typedef long long handle_id_t; | |
struct Handle { | |
handle_id_t id = 0; | |
FancyRefPtr<KernelObject> ko; | |
__attribute__(( always_inline )) inline operator bool(){ | |
return id && ko.get(); | |
} | |
}; | |
# 14 "../Kernel/include/Objects/Process.h" 2 | |
# 1 "../Kernel/include/TimerEvent.h" 1 | |
struct RegisterContext; | |
namespace Timer{ | |
using TimerCallback = void(*)(void*); | |
void Handler(void*, RegisterContext* r); | |
class TimerEvent final { | |
friend void Timer::Handler(void*, RegisterContext* r); | |
friend class ::FastList<TimerEvent*>; | |
protected: | |
long ticks = 0; | |
bool dispatched = false; | |
lock_t lock = 0; | |
TimerEvent* next = nullptr; | |
TimerEvent* prev = nullptr; | |
TimerCallback callback; | |
void* data = nullptr; | |
void Dispatch(); | |
public: | |
TimerEvent(long _us, TimerCallback _callback, void* data); | |
~TimerEvent(); | |
inline long GetTicks() const { return ticks; } | |
__attribute__((always_inline)) inline void Lock() { ({ unsigned i = 0; while (__sync_lock_test_and_set(&lock, 1) && ++i < 0xFFFFFFF) asm("pause"); if (i >= 0xFFFFFFF) { (void)((!"Deadlock!") || (KernelAssertionFailed("!\"Deadlock!\"", "../Kernel/include/TimerEvent.h", 34), 0)); } }); } | |
__attribute__((always_inline)) inline void Unlock() { ({ __sync_lock_release(&lock); });; } | |
}; | |
} | |
# 19 "../Kernel/include/Objects/Process.h" 2 | |
class Process : public KernelObject { | |
friend struct Thread; | |
friend void KernelProcess(); | |
friend long SysExecve(RegisterContext* r); | |
public: | |
enum { | |
Process_Running = 0, | |
Process_Dying = 1, | |
Process_Dead = 3, | |
}; | |
static FancyRefPtr<Process> CreateIdleProcess(const char* name); | |
static FancyRefPtr<Process> CreateKernelProcess(void* entry, const char* name, Process* parent); | |
static FancyRefPtr<Process> CreateELFProcess(void* elf, const Vector<String>& argv, const Vector<String>& envp, | |
const char* execPath, Process* parent); | |
__attribute__(( always_inline )) inline static Process* Current() { | |
CPU* cpu = GetCPULocal(); | |
Process* ret = nullptr; | |
if (cpu->currentThread) | |
ret = cpu->currentThread->parent; | |
return ret; | |
} | |
~Process(); | |
void Destroy() override; | |
# 68 "../Kernel/include/Objects/Process.h" | |
void Die(); | |
void Start(); | |
kobject_id_t InstanceTypeID() const override { return 5; } | |
# 85 "../Kernel/include/Objects/Process.h" | |
void Watch(KernelObjectWatcher& watcher, int events) override; | |
void Unwatch(KernelObjectWatcher& watcher) override; | |
# 96 "../Kernel/include/Objects/Process.h" | |
FancyRefPtr<Process> Fork(); | |
# 107 "../Kernel/include/Objects/Process.h" | |
uintptr_t LoadELF(uintptr_t* stackPointer, elf_info_t elfInfo, const Vector<String>& argv, | |
const Vector<String>& envp, const char* execPath); | |
__attribute__(( always_inline )) inline pid_t PID() const { return m_pid; } | |
__attribute__(( always_inline )) inline int State() const { return m_state; } | |
__attribute__(( always_inline )) inline int IsDead() const { return m_state == Process_Dead; } | |
__attribute__(( always_inline )) inline int IsCPUIdleProcess() const { return m_isIdleProcess; } | |
__attribute__(( always_inline )) inline const Process* Parent() const { return m_parent; } | |
# 138 "../Kernel/include/Objects/Process.h" | |
__attribute__(( always_inline )) inline FancyRefPtr<Thread> GetMainThread() { return m_mainThread; } | |
# 149 "../Kernel/include/Objects/Process.h" | |
__attribute__(( always_inline )) inline FancyRefPtr<Thread> GetThreadFromTID(pid_t tid) { | |
ScopedSpinLock acq(m_processLock); | |
return GetThreadFromTID_Unlocked(tid); | |
} | |
pid_t CreateChildThread(uintptr_t entry, uintptr_t stack, uint64_t cs, uint64_t ss); | |
const List<FancyRefPtr<Thread>>& Threads() { return m_threads; } | |
__attribute__(( always_inline )) inline PageMap* GetPageMap() { return addressSpace->GetPageMap(); } | |
int AllocateFileDescriptor(FancyRefPtr<UNIXFileDescriptor> fd); | |
__attribute__(( always_inline )) inline FancyRefPtr<UNIXFileDescriptor> GetFileDescriptor(int fd) { | |
ScopedSpinLock lockFds(m_fileDescriptorLock); | |
if (fd >= m_fileDescriptors.size()) { | |
return nullptr; | |
} | |
return m_fileDescriptors[fd]; | |
} | |
# 188 "../Kernel/include/Objects/Process.h" | |
__attribute__(( always_inline )) inline int DestroyFileDescriptor(int fd) { | |
ScopedSpinLock lockFds(m_fileDescriptorLock); | |
if (fd >= m_fileDescriptors.size()) { | |
return 1008; | |
} | |
m_fileDescriptors[fd] = nullptr; | |
return 0; | |
} | |
# 206 "../Kernel/include/Objects/Process.h" | |
__attribute__(( always_inline )) inline int ReplaceFileDescriptor(int fd, FancyRefPtr<UNIXFileDescriptor> newFd) { | |
ScopedSpinLock lockFds(m_fileDescriptorLock); | |
(void)((fd < m_fileDescriptors.size()) || (KernelAssertionFailed("fd < m_fileDescriptors.size()", "../Kernel/include/Objects/Process.h", 208), 0)); | |
m_fileDescriptors.at(fd) = newFd; | |
return 0; | |
} | |
__attribute__(( always_inline )) inline unsigned FileDescriptorCount() const { return m_fileDescriptors.size(); } | |
__attribute__(( always_inline )) inline Handle AllocateHandle(FancyRefPtr<KernelObject> ko) { | |
ScopedSpinLock lockHandles(m_handleLock); | |
Handle h; | |
h.ko = std::move(ko); | |
h.id = m_handles.get_length() + 1; | |
m_handles.add_back(h); | |
return h; | |
} | |
__attribute__(( always_inline )) inline Handle FindHandle(handle_id_t id) { | |
ScopedSpinLock lockFds(m_handleLock); | |
if (id < 1 || id > m_handles.size()) { | |
return {0, nullptr}; | |
} | |
return m_handles[id - 1]; | |
} | |
__attribute__(( always_inline )) inline int DestroyHandle(handle_id_t id) { | |
ScopedSpinLock lockFds(m_handleLock); | |
if (id > m_handles.size()) { | |
return 1008; | |
} | |
m_handles[id - 1] = {0, nullptr}; | |
return 0; | |
} | |
__attribute__(( always_inline )) inline FancyRefPtr<UNIXFileDescriptor> stdin() { return m_fileDescriptors[0]; }; | |
__attribute__(( always_inline )) inline FancyRefPtr<UNIXFileDescriptor> stdout() { return m_fileDescriptors[1]; }; | |
__attribute__(( always_inline )) inline FancyRefPtr<UNIXFileDescriptor> stderr() { return m_fileDescriptors[2]; }; | |
__attribute__(( always_inline )) inline void RegisterChildProcess(const FancyRefPtr<Process>& child) { | |
ScopedSpinLock lock(m_processLock); | |
m_children.add_back(child); | |
} | |
__attribute__(( always_inline )) inline FancyRefPtr<Process> FindChildByPID(pid_t pid) { | |
ScopedSpinLock lock(m_processLock); | |
for (auto& child : m_children) { | |
if (child->PID() == pid) { | |
return child; | |
} | |
} | |
return nullptr; | |
} | |
__attribute__(( always_inline )) inline FancyRefPtr<Process> RemoveDeadChild() { | |
ScopedSpinLock lock(m_processLock); | |
FancyRefPtr<Process> proc; | |
for (auto it = m_children.begin(); it != m_children.end(); it++) { | |
if ((*it)->State() == Process_Dead) { | |
proc = std::move(*it); | |
m_children.remove(it); | |
break; | |
} | |
} | |
if (proc.get()) { | |
ScopedSpinLock lockChild(proc->m_processLock); | |
proc->m_parent = nullptr; | |
return proc; | |
} | |
return nullptr; | |
} | |
__attribute__(( always_inline )) inline FancyRefPtr<Process> RemoveDeadChild(pid_t pid) { | |
ScopedSpinLock lock(m_processLock); | |
for (auto it = m_children.begin(); it != m_children.end(); it++) { | |
if ((*it)->PID() == pid) { | |
(void)(((*it)->IsDead()) || (KernelAssertionFailed("(*it)->IsDead()", "../Kernel/include/Objects/Process.h", 305), 0)); | |
({ unsigned i = 0; while (__sync_lock_test_and_set(&(*it)->m_processLock, 1) && ++i < 0xFFFFFFF) asm("pause"); if (i >= 0xFFFFFFF) { (void)((!"Deadlock!") || (KernelAssertionFailed("!\"Deadlock!\"", "../Kernel/include/Objects/Process.h", 307), 0)); } }); | |
FancyRefPtr<Process> proc = std::move(*it); | |
proc->m_parent = nullptr; | |
m_children.remove(it); | |
({ __sync_lock_release(&proc->m_processLock); });; | |
return proc; | |
} | |
} | |
(void)((!"Could not find process!") || (KernelAssertionFailed("!\"Could not find process!\"", "../Kernel/include/Objects/Process.h", 315), 0)); | |
} | |
__attribute__(( always_inline )) inline int WaitForChildToDie(FancyRefPtr<Process>& ptr) { | |
auto child = RemoveDeadChild(); | |
if (child.get()) { | |
ptr = std::move(child); | |
return 0; | |
} | |
retry: | |
({ unsigned i = 0; while (__sync_lock_test_and_set(&m_processLock, 1) && ++i < 0xFFFFFFF) asm("pause"); if (i >= 0xFFFFFFF) { (void)((!"Deadlock!") || (KernelAssertionFailed("!\"Deadlock!\"", "../Kernel/include/Objects/Process.h", 331), 0)); } }); | |
if (!m_children.get_length()) { | |
({ __sync_lock_release(&m_processLock); });; | |
return -1012; | |
} | |
KernelObjectWatcher watcher; | |
for (auto& child : m_children) { | |
watcher.WatchObject(static_pointer_cast<KernelObject>(child), 0); | |
} | |
({ __sync_lock_release(&m_processLock); });; | |
bool wasInterrupted = watcher.Wait(); | |
child = RemoveDeadChild(); | |
if (child.get()) { | |
ptr = std::move(child); | |
return 0; | |
} else if (wasInterrupted) { | |
return -1025; | |
} | |
goto retry; | |
} | |
__attribute__(( always_inline )) inline void SetAlarm(unsigned int seconds) { | |
ScopedSpinLock lockProcess(m_processLock); | |
if (seconds == 0) { | |
m_alarmEvent = nullptr; | |
return; | |
} | |
m_alarmEvent = new Timer::TimerEvent( | |
seconds * 1000000, | |
[](void* thread) { | |
Thread* t = reinterpret_cast<Thread*>(thread); | |
t->Signal(14); | |
}, | |
m_mainThread.get()); | |
} | |
char name[255 + 1]; | |
char workingDir[4096 + 1]; | |
int32_t euid = 0; | |
int32_t uid = 0; | |
int32_t egid = 0; | |
int32_t gid = 0; | |
SignalHandler signalHandlers[34]; | |
uint64_t usedMemoryBlocks = 0; | |
timeval creationTime; | |
uint64_t activeTicks = 0; | |
AddressSpace* addressSpace = nullptr; | |
HashMap<uintptr_t, List<FutexThreadBlocker*>*> futexWaitQueue = HashMap<uintptr_t, List<FutexThreadBlocker*>*>(8); | |
int exitCode = 0; | |
private: | |
Process(pid_t pid, const char* name, const char* workingDir, Process* parent); | |
FancyRefPtr<Thread> GetThreadFromTID_Unlocked(pid_t tid); | |
void MapSignalTrampoline(); | |
lock_t m_processLock = 0; | |
lock_t m_watchingLock = 0; | |
lock_t m_fileDescriptorLock = 0; | |
lock_t m_handleLock = 0; | |
pid_t m_pid; | |
bool m_started = false; | |
MappedRegion* m_signalTrampoline = nullptr; | |
int m_state = Process_Running; | |
bool m_isIdleProcess = false; | |
int64_t m_nextThreadID = 1; | |
FancyRefPtr<Thread> m_mainThread; | |
List<FancyRefPtr<Thread>> m_threads; | |
List<FancyRefPtr<Process>> m_children; | |
# 436 "../Kernel/include/Objects/Process.h" | |
Vector<Handle> m_handles; | |
Vector<FancyRefPtr<UNIXFileDescriptor>> m_fileDescriptors; | |
List<KernelObjectWatcher*> m_watching; | |
FancyRefPtr<Timer::TimerEvent> m_alarmEvent = nullptr; | |
Process* m_parent = nullptr; | |
}; | |
# 2 "../Kernel/src/Objects/Process.cpp" 2 | |
# 1 "../Kernel/include/Arch/x86_64/ABI.h" 1 | |
typedef struct{ | |
uint64_t a_type; | |
uint64_t a_val; | |
} auxv_t; | |
# 4 "../Kernel/src/Objects/Process.cpp" 2 | |
# 1 "../Kernel/include/Arch/x86_64/APIC.h" 1 | |
# 59 "../Kernel/include/Arch/x86_64/APIC.h" | |
namespace APIC{ | |
namespace Local{ | |
int Initialize(); | |
void Enable(); | |
uint32_t Read(uint32_t off); | |
void Write(uint32_t off, uint32_t val); | |
void SendIPI(uint8_t apicID, uint32_t dsh, uint32_t type, uint8_t vector); | |
} | |
namespace IO{ | |
int Initialize(); | |
void SetBase(uintptr_t newBase); | |
void MapLegacyIRQ(uint8_t irq); | |
} | |
int Initialize(); | |
} | |
extern "C" void LocalAPICEOI(); | |
# 5 "../Kernel/src/Objects/Process.cpp" 2 | |
# 1 "../Kernel/include/Arch/x86_64/IDT.h" 1 | |
# 11 "../Kernel/include/Arch/x86_64/IDT.h" | |
typedef struct { | |
uint16_t base_low; | |
uint16_t sel; | |
uint8_t ist; | |
uint8_t flags; | |
uint16_t base_med; | |
uint32_t base_high; | |
uint32_t null; | |
} __attribute__((packed)) idt_entry_t; | |
typedef struct { | |
uint16_t limit; | |
uint64_t base; | |
} __attribute__((packed)) idt_ptr_t; | |
typedef void(*isr_t)(void*, RegisterContext*); | |
extern "C" void idt_flush(); | |
namespace IDT{ | |
void Initialize(); | |
void RegisterInterruptHandler(uint8_t interrupt, isr_t handler, void* data = nullptr); | |
void DisablePIC(); | |
uint8_t ReserveUnusedInterrupt(); | |
int GetErrCode(); | |
} | |
# 9 "../Kernel/src/Objects/Process.cpp" 2 | |
# 1 "../Kernel/include/Arch/x86_64/SMP.h" 1 | |
namespace SMP{ | |
extern CPU* cpus[]; | |
extern unsigned processorCount; | |
void InitializeCPU(uint16_t id); | |
void Initialize(); | |
} | |
# 10 "../Kernel/src/Objects/Process.cpp" 2 | |
# 1 "../Kernel/include/Arch/x86_64/Scheduler.h" 1 | |
# 25 "../Kernel/include/Arch/x86_64/Scheduler.h" | |
namespace Scheduler { | |
class ProcessStateThreadBlocker; | |
} | |
namespace Scheduler { | |
extern lock_t destroyedProcessesLock; | |
extern List<FancyRefPtr<Process>>* destroyedProcesses; | |
void RegisterProcess(FancyRefPtr<Process> proc); | |
void MarkProcessForDestruction(Process* proc); | |
__attribute__(( always_inline )) inline static Process* GetCurrentProcess() { | |
CPU* cpu = GetCPULocal(); | |
Process* ret = nullptr; | |
if (cpu->currentThread) | |
ret = cpu->currentThread->parent; | |
return ret; | |
} | |
__attribute__(( always_inline )) inline static Thread* GetCurrentThread() { return GetCPULocal()->currentThread; } | |
template <typename T> | |
__attribute__(( always_inline )) inline bool CheckUsermodePointer(T* ptr, AddressSpace* addressSpace = GetCurrentProcess()->addressSpace) { | |
return addressSpace->RangeInRegion(reinterpret_cast<uintptr_t>(ptr), sizeof(T)); | |
} | |
void Yield(); | |
void Schedule(void* data, RegisterContext* r); | |
pid_t GetNextPID(); | |
FancyRefPtr<Process> FindProcessByPID(pid_t pid); | |
pid_t GetNextProcessPID(pid_t pid); | |
void InsertNewThreadIntoQueue(Thread* thread); | |
void Initialize(); | |
void Tick(RegisterContext* r); | |
} | |
# 11 "../Kernel/src/Objects/Process.cpp" 2 | |
# 1 "../Kernel/include/Panic.h" 1 | |
[[noreturn]] void KernelPanic(const char** reasons, int reasonCount); | |
template<typename... T> | |
[[noreturn]] void KernelPanic(T*... reasons){ | |
const char* list[] { reasons... }; | |
KernelPanic(list, sizeof...(reasons)); | |
} | |
# 13 "../Kernel/src/Objects/Process.cpp" 2 | |
extern uint8_t signalTrampolineStart[]; | |
extern uint8_t signalTrampolineEnd[]; | |
void IdleProcess(); | |
FancyRefPtr<Process> Process::CreateIdleProcess(const char* name){ | |
FancyRefPtr<Process> proc = new Process(Scheduler::GetNextPID(), name, "/", nullptr); | |
proc->m_mainThread->registers.rip = reinterpret_cast<uintptr_t>(IdleProcess); | |
proc->m_mainThread->timeSlice = 0; | |
proc->m_mainThread->timeSliceDefault = 0; | |
proc->m_mainThread->registers.rsp = reinterpret_cast<uintptr_t>(proc->m_mainThread->kernelStack); | |
proc->m_mainThread->registers.rbp = reinterpret_cast<uintptr_t>(proc->m_mainThread->kernelStack); | |
proc->m_isIdleProcess = true; | |
Scheduler::RegisterProcess(proc); | |
return proc; | |
} | |
FancyRefPtr<Process> Process::CreateKernelProcess(void* entry, const char* name, Process* parent){ | |
FancyRefPtr<Process> proc = new Process(Scheduler::GetNextPID(), name, "/", parent); | |
proc->m_mainThread->registers.rip = reinterpret_cast<uintptr_t>(entry); | |
proc->m_mainThread->registers.rsp = reinterpret_cast<uintptr_t>(proc->m_mainThread->kernelStack); | |
proc->m_mainThread->registers.rbp = reinterpret_cast<uintptr_t>(proc->m_mainThread->kernelStack); | |
Scheduler::RegisterProcess(proc); | |
return proc; | |
} | |
FancyRefPtr<Process> Process::CreateELFProcess(void* elf, const Vector<String>& argv, const Vector<String>& envp, const char* execPath, Process* parent){ | |
if (!VerifyELF(elf)) { | |
return nullptr; | |
} | |
const char* name = "unknown"; | |
if(argv.size() >= 1){ | |
name = argv[0].c_str(); | |
} | |
FancyRefPtr<Process> proc = new Process(Scheduler::GetNextPID(), name, "/", parent); | |
Thread* thread = proc->m_mainThread.get(); | |
thread->registers.cs = 0x1B; | |
thread->registers.ss = 0x23; | |
thread->timeSliceDefault = 10; | |
thread->timeSlice = thread->timeSliceDefault; | |
thread->priority = 4; | |
elf_info_t elfInfo = LoadELFSegments(proc.get(), elf, 0); | |
MappedRegion* stackRegion = proc->addressSpace->AllocateAnonymousVMObject(0x400000, 0, false); | |
thread->stack = reinterpret_cast<void*>(stackRegion->base); | |
thread->registers.rsp = (uintptr_t)thread->stack + 0x400000; | |
thread->registers.rbp = (uintptr_t)thread->stack + 0x400000; | |
stackRegion->vmObject->Hit(stackRegion->base, 0x400000 - 0x1000, proc->GetPageMap()); | |
stackRegion->vmObject->Hit(stackRegion->base, 0x400000 - 0x2000, proc->GetPageMap()); | |
stackRegion->vmObject->Hit(stackRegion->base, 0x400000 - 0x3000, proc->GetPageMap()); | |
thread->registers.rip = proc->LoadELF(&thread->registers.rsp, elfInfo, argv, envp, execPath); | |
if (!thread->registers.rip) { | |
proc->Die(); | |
delete proc->addressSpace; | |
proc->addressSpace = nullptr; | |
return nullptr; | |
} | |
(void)((!(thread->registers.rsp & 0xF)) || (KernelAssertionFailed("!(thread->registers.rsp & 0xF)", "../Kernel/src/Objects/Process.cpp", 86), 0)); | |
FsNode* nullDev = fs::ResolvePath("/dev/null"); | |
FsNode* logDev = fs::ResolvePath("/dev/kernellog"); | |
if (nullDev) { | |
proc->m_fileDescriptors[0] = (fs::Open(nullDev)); | |
} else { | |
Log::Warning("Failed to find /dev/null"); | |
} | |
if (logDev) { | |
proc->m_fileDescriptors[1] = (fs::Open(logDev)); | |
proc->m_fileDescriptors[2] = (fs::Open(logDev)); | |
} else { | |
Log::Warning("Failed to find /dev/kernellog"); | |
} | |
proc->MapSignalTrampoline(); | |
Scheduler::RegisterProcess(proc); | |
return proc; | |
} | |
Process::Process(pid_t pid, const char* _name, const char* _workingDir, Process* parent) | |
: m_pid(pid), m_parent(parent) { | |
if(_workingDir){ | |
strncpy(workingDir, _workingDir, 4096); | |
} else { | |
strcpy(workingDir, "/"); | |
} | |
strncpy(name, _name, 255); | |
addressSpace = new AddressSpace(Memory::CreatePageMap()); | |
for (unsigned i = 0; i < 34; i++) { | |
signalHandlers[i] = { | |
.action = SignalHandler::HandlerAction::Default, | |
.flags = 0, | |
.mask = 0, | |
.userHandler = nullptr, | |
}; | |
} | |
creationTime = Timer::GetSystemUptimeStruct(); | |
m_mainThread = new Thread(this, m_nextThreadID++); | |
m_threads.add_back(m_mainThread); | |
(void)((m_mainThread->parent == this) || (KernelAssertionFailed("m_mainThread->parent == this", "../Kernel/src/Objects/Process.cpp", 137), 0)); | |
m_fileDescriptors.add_back(nullptr); | |
m_fileDescriptors.add_back(nullptr); | |
m_fileDescriptors.add_back(nullptr); | |
} | |
uintptr_t Process::LoadELF(uintptr_t* stackPointer, elf_info_t elfInfo, const Vector<String>& argv, const Vector<String>& envp, const char* execPath) { | |
uintptr_t rip = elfInfo.entry; | |
if (elfInfo.linkerPath) { | |
uintptr_t linkerBaseAddress = 0x7FC0000000; | |
FsNode* node = fs::ResolvePath("/lib/ld.so"); | |
if (!node) { | |
KernelPanic("Failed to load dynamic linker!"); | |
} | |
void* linkerElf = kmalloc(node->size); | |
fs::Read(node, 0, node->size, (uint8_t*)linkerElf); | |
if (!VerifyELF(linkerElf)) { | |
Log::Warning("Invalid Dynamic Linker ELF"); | |
return 0; | |
} | |
elf_info_t linkerELFInfo = LoadELFSegments(this, linkerElf, linkerBaseAddress); | |
rip = linkerELFInfo.entry; | |
kfree(linkerElf); | |
} | |
char* tempArgv[argv.size()]; | |
char* tempEnvp[envp.size()]; | |
asm("cli"); | |
asm volatile("mov %%rax, %%cr3" ::"a"(this->GetPageMap()->pml4Phys)); | |
uint64_t* stack = (uint64_t*)(*stackPointer); | |
char* stackStr = (char*)stack; | |
for (int i = 0; i < argv.size(); i++) { | |
stackStr -= argv[i].Length() + 1; | |
tempArgv[i] = stackStr; | |
strcpy((char*)stackStr, argv[i].c_str()); | |
} | |
for (int i = 0; i < envp.size(); i++) { | |
stackStr -= envp[i].Length() + 1; | |
tempEnvp[i] = stackStr; | |
strcpy((char*)stackStr, envp[i].c_str()); | |
} | |
char* execPathValue = nullptr; | |
if (execPath) { | |
stackStr -= strlen(execPath) + 1; | |
strcpy((char*)stackStr, execPath); | |
execPathValue = stackStr; | |
} | |
stackStr -= (uintptr_t)stackStr & 0xf; | |
stack = (uint64_t*)stackStr; | |
stack -= ((argv.size() + envp.size()) % 2); | |
stack--; | |
*stack = 0; | |
stack -= sizeof(auxv_t) / sizeof(*stack); | |
*((auxv_t*)stack) = {.a_type = 3, .a_val = elfInfo.pHdrSegment}; | |
stack -= sizeof(auxv_t) / sizeof(*stack); | |
*((auxv_t*)stack) = {.a_type = 4, .a_val = elfInfo.phEntrySize}; | |
stack -= sizeof(auxv_t) / sizeof(*stack); | |
*((auxv_t*)stack) = {.a_type = 5, .a_val = elfInfo.phNum}; | |
stack -= sizeof(auxv_t) / sizeof(*stack); | |
*((auxv_t*)stack) = {.a_type = 9, .a_val = elfInfo.entry}; | |
if (execPath && execPathValue) { | |
stack -= sizeof(auxv_t) / sizeof(*stack); | |
*((auxv_t*)stack) = {.a_type = 15, .a_val = (uint64_t)execPathValue}; | |
} | |
stack--; | |
*stack = 0; | |
stack -= envp.size(); | |
for (int i = 0; i < envp.size(); i++) { | |
*(stack + i) = (uint64_t)tempEnvp[i]; | |
} | |
stack--; | |
*stack = 0; | |
stack -= argv.size(); | |
for (int i = 0; i < argv.size(); i++) { | |
*(stack + i) = (uint64_t)tempArgv[i]; | |
} | |
stack--; | |
*stack = argv.size(); | |
asm volatile("mov %%rax, %%cr3" ::"a"(Scheduler::GetCurrentProcess()->GetPageMap()->pml4Phys)); | |
asm("sti"); | |
*stackPointer = (uintptr_t)stack; | |
return rip; | |
} | |
Process::~Process() { | |
ScopedSpinLock lock(m_processLock); | |
(void)((m_state == Process_Dead) || (KernelAssertionFailed("m_state == Process_Dead", "../Kernel/src/Objects/Process.cpp", 255), 0)); | |
(void)((!m_parent) || (KernelAssertionFailed("!m_parent", "../Kernel/src/Objects/Process.cpp", 256), 0)); | |
if (addressSpace) { | |
delete addressSpace; | |
addressSpace = nullptr; | |
} | |
} | |
void Process::Destroy() { | |
if (m_state != Process_Dead) { | |
KernelObjectWatcher watcher; | |
Watch(watcher, 0); | |
m_mainThread->Signal(9); | |
bool interrupted = watcher.Wait(); | |
(void)((!interrupted) || (KernelAssertionFailed("!interrupted", "../Kernel/src/Objects/Process.cpp", 273), 0)); | |
(void)((m_state == Process_Dead) || (KernelAssertionFailed("m_state == Process_Dead", "../Kernel/src/Objects/Process.cpp", 274), 0)); | |
} | |
if (m_parent) { | |
ScopedSpinLock acq(m_parent->m_processLock); | |
for (auto it = m_parent->m_children.begin(); it != m_parent->m_children.end(); it++) { | |
if (it->get() == this) { | |
m_parent->m_children.remove(it); | |
break; | |
} | |
} | |
m_parent = nullptr; | |
} | |
} | |
void Process::Die() { | |
asm volatile("sti"); | |
CPU* cpu = GetCPULocal(); | |
m_state = Process_Dying; | |
Log::Debug(debugLevelScheduler, DebugLevelNormal, "Killing Process %s (PID %d)", name, m_pid); | |
(void)((({ int status; status = __sync_lock_test_and_set(&Scheduler::GetCurrentThread()->lock, 1); status; })) || (KernelAssertionFailed("acquireTestLock(&Scheduler::GetCurrentThread()->lock)", "../Kernel/src/Objects/Process.cpp", 299), 0)); | |
({ unsigned i = 0; while (__sync_lock_test_and_set(&m_processLock, 1) && ++i < 0xFFFFFFF) asm("pause"); if (i >= 0xFFFFFFF) { (void)((!"Deadlock!") || (KernelAssertionFailed("!\"Deadlock!\"", "../Kernel/src/Objects/Process.cpp", 301), 0)); } }); | |
List<FancyRefPtr<Thread>> runningThreads; | |
for (auto& thread : m_threads) { | |
asm("cli"); | |
if (thread != cpu->currentThread && thread) { | |
if (thread->blocker && thread->state == ThreadStateBlocked) { | |
thread->blocker->Interrupt(); | |
} | |
thread->state = ThreadStateZombie; | |
if (({ int status; status = __sync_lock_test_and_set(&thread->lock, 1); status; })) { | |
asm("sti"); | |
runningThreads.add_back(thread); | |
asm("cli"); | |
} else { | |
thread->state = | |
ThreadStateBlocked; | |
thread->timeSlice = thread->timeSliceDefault = 0; | |
} | |
} | |
} | |
asm("sti"); | |
while (m_children.get_length()) { | |
FancyRefPtr<Process> child = m_children.get_front(); | |
if (child->State() == Process_Running) { | |
child->GetMainThread()->Signal(9); | |
while(child->State() != Process_Dead); | |
} else if (child->State() == Process_Dying) { | |
KernelObjectWatcher w; | |
child->Watch(w, 0); | |
bool wasInterrupted = w.Wait(); | |
(void)((!wasInterrupted) || (KernelAssertionFailed("!wasInterrupted", "../Kernel/src/Objects/Process.cpp", 336), 0)); | |
} | |
child->m_parent = nullptr; | |
m_children.remove(child); | |
} | |
({ __sync_lock_release(&m_processLock); });; | |
asm("sti"); | |
while (runningThreads.get_length()) { | |
auto it = runningThreads.begin(); | |
while (it != runningThreads.end()) { | |
FancyRefPtr<Thread> thread = *it; | |
if (!({ int status; status = __sync_lock_test_and_set(&thread->lock, 1); status; })) { | |
runningThreads.remove(*(it++)); | |
thread->state = ThreadStateBlocked; | |
thread->timeSlice = thread->timeSliceDefault = 0; | |
} else { | |
it++; | |
} | |
} | |
Scheduler::GetCurrentThread()->Sleep(50000); | |
} | |
(void)((!runningThreads.get_length()) || (KernelAssertionFailed("!runningThreads.get_length()", "../Kernel/src/Objects/Process.cpp", 364), 0)); | |
({ unsigned i = 0; while (__sync_lock_test_and_set(&m_processLock, 1) && ++i < 0xFFFFFFF) asm("pause"); if (i >= 0xFFFFFFF) { (void)((!"Deadlock!") || (KernelAssertionFailed("!\"Deadlock!\"", "../Kernel/src/Objects/Process.cpp", 366), 0)); } }); | |
({ unsigned i = 0; while (__sync_lock_test_and_set(&cpu->runQueueLock, 1) && ++i < 0xFFFFFFF) asm("pause"); if (i >= 0xFFFFFFF) { (void)((!"Deadlock!") || (KernelAssertionFailed("!\"Deadlock!\"", "../Kernel/src/Objects/Process.cpp", 367), 0)); } }); | |
asm("cli"); | |
for (unsigned j = 0; j < cpu->runQueue->get_length(); j++) { | |
if (Thread* thread = cpu->runQueue->get_at(j); thread != cpu->currentThread && thread->parent == this) { | |
cpu->runQueue->remove_at(j); | |
} | |
} | |
({ __sync_lock_release(&cpu->runQueueLock); });; | |
asm("sti"); | |
for (unsigned i = 0; i < SMP::processorCount; i++) { | |
if (i == cpu->id) | |
continue; | |
CPU* other = SMP::cpus[i]; | |
asm("sti"); | |
({ unsigned i = 0; while (__sync_lock_test_and_set(&other->runQueueLock, 1) && ++i < 0xFFFFFFF) asm("pause"); if (i >= 0xFFFFFFF) { (void)((!"Deadlock!") || (KernelAssertionFailed("!\"Deadlock!\"", "../Kernel/src/Objects/Process.cpp", 385), 0)); } }); | |
asm("cli"); | |
(void)((!(other->currentThread && other->currentThread->parent == this)) || (KernelAssertionFailed("!(other->currentThread && other->currentThread->parent == this)", "../Kernel/src/Objects/Process.cpp", 388), 0)); | |
for (unsigned j = 0; j < other->runQueue->get_length(); j++) { | |
Thread* thread = other->runQueue->get_at(j); | |
(void)((thread) || (KernelAssertionFailed("thread", "../Kernel/src/Objects/Process.cpp", 393), 0)); | |
if (thread->parent == this) { | |
other->runQueue->remove(thread); | |
} | |
} | |
({ __sync_lock_release(&other->runQueueLock); });; | |
asm("sti"); | |
if (other->currentThread == nullptr) { | |
APIC::Local::SendIPI(i, (1 << 18), 0, 0xFD); | |
} | |
} | |
asm("sti"); | |
Log::Debug(debugLevelScheduler, DebugLevelVerbose, "[%d] Closing fds...", m_pid); | |
for (auto& fd : m_fileDescriptors) { | |
fd = nullptr; | |
} | |
m_fileDescriptors.clear(); | |
Log::Debug(debugLevelScheduler, DebugLevelVerbose, "[%d] Closing handles...", m_pid); | |
for (auto& handle : m_handles) { | |
if(handle.ko.get()){ | |
handle.ko->Destroy(); | |
} | |
handle.ko = nullptr; | |
} | |
m_handles.clear(); | |
Log::Debug(debugLevelScheduler, DebugLevelVerbose, "[%d] Signaling watchers...", m_pid); | |
for(auto* watcher : m_watching){ | |
watcher->Signal(); | |
} | |
m_watching.clear(); | |
m_state = Process_Dead; | |
if(m_parent && (m_parent->State() == Process_Running)){ | |
Log::Debug(debugLevelScheduler, DebugLevelVerbose, "[%d] Sending SIGCHILD to %s...", m_pid, m_parent->name); | |
m_parent->GetMainThread()->Signal(17); | |
} | |
Log::Debug(debugLevelScheduler, DebugLevelVerbose, "[%d] Marking process for destruction...", m_pid); | |
Scheduler::MarkProcessForDestruction(this); | |
bool isDyingProcess = (cpu->currentThread->parent == this); | |
if(isDyingProcess){ | |
Log::Debug(debugLevelScheduler, DebugLevelVerbose, "[%d] Rescheduling...", m_pid); | |
asm("cli"); | |
asm volatile("mov %%rax, %%cr3" ::"a"(((uint64_t)Memory::kernelPML4) - 0xFFFFFFFF80000000ULL)); | |
cpu->currentThread->state = ThreadStateDying; | |
cpu->currentThread->timeSlice = 0; | |
({ __sync_lock_release(&m_processLock); });; | |
asm volatile("sti; int $0xFD"); | |
(void)((!"We should not be here") || (KernelAssertionFailed("!\"We should not be here\"", "../Kernel/src/Objects/Process.cpp", 459), 0)); | |
} else { | |
({ __sync_lock_release(&m_processLock); });; | |
} | |
} | |
void Process::Start(){ | |
ScopedSpinLock acq(m_processLock); | |
(void)((!m_started) || (KernelAssertionFailed("!m_started", "../Kernel/src/Objects/Process.cpp", 467), 0)); | |
Scheduler::InsertNewThreadIntoQueue(m_mainThread.get()); | |
m_started = true; | |
} | |
void Process::Watch(KernelObjectWatcher& watcher, int events) { | |
ScopedSpinLock acq(m_watchingLock); | |
if (m_state == Process_Dead) { | |
watcher.Signal(); | |
return; | |
} | |
m_watching.add_back(&watcher); | |
} | |
void Process::Unwatch(KernelObjectWatcher& watcher) { | |
ScopedSpinLock acq(m_watchingLock); | |
if (m_state == Process_Dead) { | |
return; | |
} | |
m_watching.remove(&watcher); | |
} | |
FancyRefPtr<Process> Process::Fork() { | |
ScopedSpinLock lock(m_processLock); | |
FancyRefPtr<Process> newProcess = new Process(Scheduler::GetNextPID(), name, workingDir, this); | |
delete newProcess->addressSpace; | |
newProcess->addressSpace = addressSpace->Fork(); | |
newProcess->euid = euid; | |
newProcess->uid = uid; | |
newProcess->euid = egid; | |
newProcess->gid = gid; | |
newProcess->m_fileDescriptors.resize(m_fileDescriptors.size()); | |
for(unsigned i = 0; i < m_fileDescriptors.size(); i++){ | |
UNIXFileDescriptor* source = m_fileDescriptors[i].get(); | |
if(!source || !source->node){ | |
continue; | |
} | |
UNIXFileDescriptor* dest = fs::Open(source->node); | |
dest->mode = source->mode; | |
dest->pos = source->pos; | |
newProcess->m_fileDescriptors[i] = dest; | |
} | |
m_children.add_back(newProcess); | |
Scheduler::RegisterProcess(newProcess); | |
return newProcess; | |
} | |
pid_t Process::CreateChildThread(uintptr_t entry, uintptr_t stack, uint64_t cs, uint64_t ss){ | |
pid_t threadID = m_nextThreadID++; | |
Thread& thread = *m_threads.add_back(new Thread(this, threadID)); | |
thread.registers.rip = entry; | |
thread.registers.rsp = stack; | |
thread.registers.rbp = stack; | |
thread.state = ThreadStateRunning; | |
thread.stack = thread.stackLimit = reinterpret_cast<void*>(stack); | |
RegisterContext* registers = &thread.registers; | |
registers->rflags = 0x202; | |
thread.registers.cs = cs; | |
thread.registers.ss = ss; | |
thread.timeSliceDefault = 10; | |
thread.timeSlice = thread.timeSliceDefault; | |
thread.priority = 4; | |
Scheduler::InsertNewThreadIntoQueue(&thread); | |
return threadID; | |
} | |
int Process::AllocateFileDescriptor(FancyRefPtr<UNIXFileDescriptor> fd){ | |
ScopedSpinLock lockFDs(m_fileDescriptorLock); | |
int i = 0; | |
for(; i < static_cast<int>(m_fileDescriptors.get_length()); i++){ | |
if(m_fileDescriptors[i] == nullptr){ | |
m_fileDescriptors[i] = std::move(fd); | |
return i; | |
} | |
} | |
m_fileDescriptors.add_back(std::move(fd)); | |
return i; | |
} | |
FancyRefPtr<Thread> Process::GetThreadFromTID_Unlocked(pid_t tid) { | |
for (const FancyRefPtr<Thread>& t : m_threads) { | |
if (t->tid == tid) { | |
return t; | |
} | |
} | |
return nullptr; | |
} | |
void Process::MapSignalTrampoline(){ | |
m_signalTrampoline = addressSpace->AllocateAnonymousVMObject( | |
((signalTrampolineEnd - signalTrampolineStart) + 4096U - 1) & | |
~static_cast<unsigned>(4096U - 1), | |
0, false); | |
reinterpret_cast<PhysicalVMObject*>(m_signalTrampoline->vmObject.get()) | |
->ForceAllocate(); | |
m_signalTrampoline->vmObject->MapAllocatedBlocks(m_signalTrampoline->Base(), GetPageMap()); | |
asm volatile("cli; mov %%rax, %%cr3" ::"a"(GetPageMap()->pml4Phys)); | |
memcpy(reinterpret_cast<void*>(m_signalTrampoline->Base()), signalTrampolineStart, | |
signalTrampolineEnd - signalTrampolineStart); | |
asm volatile("mov %%rax, %%cr3; sti" ::"a"(Scheduler::GetCurrentProcess()->GetPageMap()->pml4Phys)); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment