From 93ef197e589774e5c5e9cf312a4f726567ab54ac Mon Sep 17 00:00:00 2001 From: Tom-on64 Date: Fri, 20 Mar 2026 18:18:15 +0100 Subject: [PATCH] Wrote physical memory manager --- .clang-format | 297 ++++++++++++++++++++++++++++++++++++ kernel/include/bootloader.h | 2 +- kernel/include/limine.h | 1 + kernel/include/paging.h | 43 +++--- kernel/include/pmm.h | 7 +- kernel/src/bootloader.c | 19 ++- kernel/src/pmm.c | 88 +++-------- 7 files changed, 358 insertions(+), 99 deletions(-) create mode 100644 .clang-format diff --git a/.clang-format b/.clang-format new file mode 100644 index 0000000..e9ca3f7 --- /dev/null +++ b/.clang-format @@ -0,0 +1,297 @@ +--- +Language: Cpp +AccessModifierOffset: -2 +AlignAfterOpenBracket: Align +AlignArrayOfStructures: None +AlignConsecutiveAssignments: + Enabled: false + AcrossEmptyLines: false + AcrossComments: false + AlignCompound: false + AlignFunctionDeclarations: false + AlignFunctionPointers: false + PadOperators: true +AlignConsecutiveBitFields: + Enabled: false + AcrossEmptyLines: false + AcrossComments: false + AlignCompound: false + AlignFunctionDeclarations: false + AlignFunctionPointers: false + PadOperators: false +AlignConsecutiveDeclarations: + Enabled: false + AcrossEmptyLines: false + AcrossComments: false + AlignCompound: false + AlignFunctionDeclarations: true + AlignFunctionPointers: false + PadOperators: false +AlignConsecutiveMacros: + Enabled: false + AcrossEmptyLines: false + AcrossComments: false + AlignCompound: false + AlignFunctionDeclarations: false + AlignFunctionPointers: false + PadOperators: false +AlignConsecutiveShortCaseStatements: + Enabled: false + AcrossEmptyLines: false + AcrossComments: false + AlignCaseArrows: false + AlignCaseColons: false +AlignConsecutiveTableGenBreakingDAGArgColons: + Enabled: false + AcrossEmptyLines: false + AcrossComments: false + AlignCompound: false + AlignFunctionDeclarations: false + AlignFunctionPointers: false + PadOperators: false +AlignConsecutiveTableGenCondOperatorColons: + Enabled: false + AcrossEmptyLines: false + AcrossComments: false + AlignCompound: false + AlignFunctionDeclarations: false + AlignFunctionPointers: false + PadOperators: false +AlignConsecutiveTableGenDefinitionColons: + Enabled: false + AcrossEmptyLines: false + AcrossComments: false + AlignCompound: false + AlignFunctionDeclarations: false + AlignFunctionPointers: false + PadOperators: false +AlignEscapedNewlines: Right +AlignOperands: Align +AlignTrailingComments: + Kind: Always + OverEmptyLines: 0 +AllowAllArgumentsOnNextLine: true +AllowAllParametersOfDeclarationOnNextLine: true +AllowBreakBeforeNoexceptSpecifier: Never +AllowShortBlocksOnASingleLine: Never +AllowShortCaseExpressionOnASingleLine: true +AllowShortCaseLabelsOnASingleLine: false +AllowShortCompoundRequirementOnASingleLine: true +AllowShortEnumsOnASingleLine: true +AllowShortFunctionsOnASingleLine: All +AllowShortIfStatementsOnASingleLine: Never +AllowShortLambdasOnASingleLine: All +AllowShortLoopsOnASingleLine: false +AllowShortNamespacesOnASingleLine: false +AlwaysBreakAfterDefinitionReturnType: None +AlwaysBreakBeforeMultilineStrings: false +AttributeMacros: + - __capability +BinPackArguments: true +BinPackLongBracedList: true +BinPackParameters: BinPack +BitFieldColonSpacing: Both +BracedInitializerIndentWidth: -1 +BraceWrapping: + AfterCaseLabel: false + AfterClass: false + AfterControlStatement: Never + AfterEnum: false + AfterExternBlock: false + AfterFunction: false + AfterNamespace: false + AfterObjCDeclaration: false + AfterStruct: false + AfterUnion: false + BeforeCatch: false + BeforeElse: false + BeforeLambdaBody: false + BeforeWhile: false + IndentBraces: false + SplitEmptyFunction: true + SplitEmptyRecord: true + SplitEmptyNamespace: true +BreakAdjacentStringLiterals: true +BreakAfterAttributes: Leave +BreakAfterJavaFieldAnnotations: false +BreakAfterReturnType: None +BreakArrays: true +BreakBeforeBinaryOperators: None +BreakBeforeConceptDeclarations: Always +BreakBeforeBraces: Attach +BreakBeforeInlineASMColon: OnlyMultiline +BreakBeforeTemplateCloser: false +BreakBeforeTernaryOperators: true +BreakBinaryOperations: Never +BreakConstructorInitializers: BeforeColon +BreakFunctionDefinitionParameters: false +BreakInheritanceList: BeforeColon +BreakStringLiterals: true +BreakTemplateDeclarations: MultiLine +ColumnLimit: 80 +CommentPragmas: '^ IWYU pragma:' +CompactNamespaces: false +ConstructorInitializerIndentWidth: 4 +ContinuationIndentWidth: 4 +Cpp11BracedListStyle: true +DerivePointerAlignment: false +DisableFormat: false +EmptyLineAfterAccessModifier: Never +EmptyLineBeforeAccessModifier: LogicalBlock +EnumTrailingComma: Leave +ExperimentalAutoDetectBinPacking: false +FixNamespaceComments: true +ForEachMacros: + - foreach + - Q_FOREACH + - BOOST_FOREACH +IfMacros: + - KJ_IF_MAYBE +IncludeBlocks: Preserve +IncludeCategories: + - Regex: '^"(llvm|llvm-c|clang|clang-c)/' + Priority: 2 + SortPriority: 0 + CaseSensitive: false + - Regex: '^(<|"(gtest|gmock|isl|json)/)' + Priority: 3 + SortPriority: 0 + CaseSensitive: false + - Regex: '.*' + Priority: 1 + SortPriority: 0 + CaseSensitive: false +IncludeIsMainRegex: '(Test)?$' +IncludeIsMainSourceRegex: '' +IndentAccessModifiers: false +IndentCaseBlocks: false +IndentCaseLabels: false +IndentExportBlock: true +IndentExternBlock: AfterExternBlock +IndentGotoLabels: true +IndentPPDirectives: None +IndentRequiresClause: true +IndentWidth: 2 +IndentWrappedFunctionNames: false +InsertBraces: false +InsertNewlineAtEOF: false +InsertTrailingCommas: None +IntegerLiteralSeparator: + Binary: 0 + BinaryMinDigits: 0 + Decimal: 0 + DecimalMinDigits: 0 + Hex: 0 + HexMinDigits: 0 +JavaScriptQuotes: Leave +JavaScriptWrapImports: true +KeepEmptyLines: + AtEndOfFile: false + AtStartOfBlock: true + AtStartOfFile: true +KeepFormFeed: false +LambdaBodyIndentation: Signature +LineEnding: DeriveLF +MacroBlockBegin: '' +MacroBlockEnd: '' +MainIncludeChar: Quote +MaxEmptyLinesToKeep: 1 +NamespaceIndentation: None +ObjCBinPackProtocolList: Auto +ObjCBlockIndentWidth: 2 +ObjCBreakBeforeNestedBlockParam: true +ObjCSpaceAfterProperty: false +ObjCSpaceBeforeProtocolList: true +OneLineFormatOffRegex: '' +PackConstructorInitializers: BinPack +PenaltyBreakAssignment: 2 +PenaltyBreakBeforeFirstCallParameter: 19 +PenaltyBreakBeforeMemberAccess: 150 +PenaltyBreakComment: 300 +PenaltyBreakFirstLessLess: 120 +PenaltyBreakOpenParenthesis: 0 +PenaltyBreakScopeResolution: 500 +PenaltyBreakString: 1000 +PenaltyBreakTemplateDeclaration: 10 +PenaltyExcessCharacter: 1000000 +PenaltyIndentedWhitespace: 0 +PenaltyReturnTypeOnItsOwnLine: 60 +PointerAlignment: Right +PPIndentWidth: -1 +QualifierAlignment: Leave +ReferenceAlignment: Pointer +ReflowComments: Always +RemoveBracesLLVM: false +RemoveEmptyLinesInUnwrappedLines: false +RemoveParentheses: Leave +RemoveSemicolon: false +RequiresClausePosition: OwnLine +RequiresExpressionIndentation: OuterScope +SeparateDefinitionBlocks: Leave +ShortNamespaceLines: 1 +SkipMacroDefinitionBody: false +SortIncludes: + Enabled: true + IgnoreCase: false +SortJavaStaticImport: Before +SortUsingDeclarations: LexicographicNumeric +SpaceAfterCStyleCast: false +SpaceAfterLogicalNot: false +SpaceAfterOperatorKeyword: false +SpaceAfterTemplateKeyword: true +SpaceAroundPointerQualifiers: Default +SpaceBeforeAssignmentOperators: true +SpaceBeforeCaseColon: false +SpaceBeforeCpp11BracedList: false +SpaceBeforeCtorInitializerColon: true +SpaceBeforeInheritanceColon: true +SpaceBeforeJsonColon: false +SpaceBeforeParens: ControlStatements +SpaceBeforeParensOptions: + AfterControlStatements: true + AfterForeachMacros: true + AfterFunctionDefinitionName: false + AfterFunctionDeclarationName: false + AfterIfMacros: true + AfterNot: false + AfterOverloadedOperator: false + AfterPlacementOperator: true + AfterRequiresInClause: false + AfterRequiresInExpression: false + BeforeNonEmptyParentheses: false +SpaceBeforeRangeBasedForLoopColon: true +SpaceBeforeSquareBrackets: false +SpaceInEmptyBlock: false +SpacesBeforeTrailingComments: 1 +SpacesInAngles: Never +SpacesInContainerLiterals: true +SpacesInLineCommentPrefix: + Minimum: 1 + Maximum: -1 +SpacesInParens: Never +SpacesInParensOptions: + ExceptDoubleParentheses: false + InCStyleCasts: false + InConditionalStatements: false + InEmptyParentheses: false + Other: false +SpacesInSquareBrackets: false +Standard: Latest +StatementAttributeLikeMacros: + - Q_EMIT +StatementMacros: + - Q_UNUSED + - QT_REQUIRE_VERSION +TableGenBreakInsideDAGArg: DontBreak +TabWidth: 8 +UseTab: Never +VerilogBreakBetweenInstancePorts: true +WhitespaceSensitiveMacros: + - BOOST_PP_STRINGIZE + - CF_SWIFT_NAME + - NS_SWIFT_NAME + - PP_STRINGIZE + - STRINGIZE +WrapNamespaceBodyWithEmptyLines: Leave +... + diff --git a/kernel/include/bootloader.h b/kernel/include/bootloader.h index 885bfdc..40cff73 100644 --- a/kernel/include/bootloader.h +++ b/kernel/include/bootloader.h @@ -8,7 +8,7 @@ struct bootloader { size_t hhdm_offset; size_t kernel_virt_base; size_t kernel_phys_base; - size_t mm_total; + size_t mm_total_memory; uint64_t mm_entry_count; LIMINE_PTR(struct limine_memmap_entry**) mm_entries; uint64_t fb_entry_count; diff --git a/kernel/include/limine.h b/kernel/include/limine.h index f3313ef..0a3d4dc 100644 --- a/kernel/include/limine.h +++ b/kernel/include/limine.h @@ -469,6 +469,7 @@ struct LIMINE_MP(request) { # define LIMINE_MEMMAP_KERNEL_AND_MODULES 6 #endif #define LIMINE_MEMMAP_FRAMEBUFFER 7 +#define LIMINE_MEMMAP_ACPI_TABLES 8 struct limine_memmap_entry { uint64_t base; diff --git a/kernel/include/paging.h b/kernel/include/paging.h index 66b1870..0cbd04e 100644 --- a/kernel/include/paging.h +++ b/kernel/include/paging.h @@ -3,34 +3,35 @@ #include -#define PAGE_FLAG_PRESENT (1 << 0) // Page is present in the table -#define PAGE_FLAG_WRITE (1 << 1) // Read-write -#define PAGE_FLAG_USER (1 << 2) // User-mode (DPL3) access allowed -#define PAGE_FLAG_PWT (1 << 3) // Page write-thru -#define PAGE_FLAG_NOCACHE (1 << 4) // Cache disable -#define PAGE_FLAG_ACCESSED (1 << 5) // Indicates whether page was accessed -#define PAGE_FLAG_DIRTY (1 << 6) // Page size (valid for PD and PDPT only) -#define PAGE_FLAG_PAT (1 << 7) // Page Attribute Table (valid for PT only) -#define PAGE_FLAG_GLOBAL (1 << 8) // Indicates the page is globally cached -#define PAGE_FLAG_SHARED (1 << 9) // Userland page is shared +#define PTE_FLAG_PRESENT (1ULL << 0) // Page is present in the table +#define PTE_FLAG_WRITE (1ULL << 1) // Read-write +#define PTE_FLAG_USER (1ULL << 2) // User-mode (DPL3) access allowed +#define PTE_FLAG_PWT (1ULL << 3) // Page write-thru +#define PTE_FLAG_NOCACHE (1ULL << 4) // Cache disable +#define PTE_FLAG_ACCESSED (1ULL << 5) // Indicates whether page was accessed +#define PTE_FLAG_DIRTY (1ULL << 6) // Page size (valid for PD and PDPT only) +#define PTE_FLAG_PAT (1ULL << 7) // Page Attribute Table (valid for PT only) +#define PTE_FLAG_GLOBAL (1ULL << 8) // Indicates the page is globally cached +#define PTE_FLAG_SHARED (1ULL << 9) // Userland page is shared +#define PTE_FLAG_NOEXEC (1ULL << 63) // No execute // Region caching according to the Limine protocol -#define PAGE_FLAG_CACHE (PAGE_FLAG_PWT | PAGE_FLAG_PAT) +#define PTE_FLAG_CACHE (PTE_FLAG_PWT | PTE_FLAG_PAT) + +#define PTE_ADDR_MASK 0x000FFFFFFFFFFFFFF000ULL +#define PTE_ADDR(_pte) ((_pte) & PAGE_ADDR_MASK) #define PAGE_SIZE 0x1000 #define PAGE_SIZE_LARGE 0x200000 #define PAGE_SIZE_HUGE 0x40000000 -#define PHYS_ADDR(_x) ((_x) & ~0xFFF) +// From the Linux kernel source +// WARN: This will only invalidate on one core +static inline void pag_invalidate(size_t vaddr) { __asm__ volatile("invlpg (%0)" :: "r" (vaddr) : "memory"); } int pag_init(void); -void pag_map(size_t vaddr, size_t paddr, size_t flags); -size_t pag_umap(size_t vaddr); -size_t pag_virt_to_phys(size_t vaddr); -size_t* pag_get_pagedir(); -size_t* pag_get_task_pagedir(void* task); -void pag_set_pagedir(size_t* pagedir); -size_t* pag_alloc_pagedir(); -void pag_free_pagedir(size_t* pagedir); -void pag_invalidate(size_t vaddr); +void pag_map(uint64_t* pml4, void* vaddr, void* paddr, uint64_t flags); +void pag_unmap(uint64_t* pml4, void* vaddr); +void pag_switch(uint64_t* pml4); +uint64_t* pag_new_pml(void); #endif diff --git a/kernel/include/pmm.h b/kernel/include/pmm.h index 5729e22..d08bead 100644 --- a/kernel/include/pmm.h +++ b/kernel/include/pmm.h @@ -1,13 +1,10 @@ #ifndef _PMM_H #define _PMM_H -#include #include -extern bitmap_t pmm_bitmap; - int pmm_init(void); -size_t pmm_alloc(void); -void pmm_free(size_t page); +void* pmm_alloc(void); +void pmm_free(void*); #endif diff --git a/kernel/src/bootloader.c b/kernel/src/bootloader.c index 5179b37..7da5ff3 100644 --- a/kernel/src/bootloader.c +++ b/kernel/src/bootloader.c @@ -2,13 +2,16 @@ #include #include +/* + * This defines our expected Limine version + */ +static volatile LIMINE_BASE_REVISION(4); + struct bootloader bootloader = { 0 }; -static struct limine_paging_mode_request lim_paging_req = { - .id = LIMINE_PAGING_MODE_REQUEST, - .revision = 4, - .mode = LIMINE_PAGING_MODE_X86_64_4LVL, -}; +static struct limine_paging_mode_request lim_paging_req = + { .id = LIMINE_PAGING_MODE_REQUEST, .revision = 4, + .mode = LIMINE_PAGING_MODE_X86_64_4LVL, }; static struct limine_kernel_address_request lim_kaddr_req = { .id = LIMINE_KERNEL_ADDRESS_REQUEST, .revision = 4 }; @@ -23,6 +26,8 @@ static struct limine_framebuffer_request lim_fbuf_req = { .id = LIMINE_FRAMEBUFFER_REQUEST, .revision = 0 }; int boot_init(void) { + if (LIMINE_BASE_REVISION_SUPPORTED == false) panic("Unsupported Limine base revision."); + struct limine_paging_mode_response* lim_paging_res = lim_paging_req.response; struct limine_kernel_address_response* lim_kaddr_res = lim_kaddr_req.response; struct limine_hhdm_response* lim_hhdm_res = lim_hhdm_req.response; @@ -36,10 +41,10 @@ int boot_init(void) { bootloader.mm_entries = lim_memmap_res->entries; bootloader.mm_entry_count = lim_memmap_res->entry_count; - bootloader.mm_total = 0; + bootloader.mm_total_memory = 0; for (size_t i = 0; i < bootloader.mm_entry_count; i++) { struct limine_memmap_entry* entry = bootloader.mm_entries[i]; - if (entry->type != LIMINE_MEMMAP_USABLE) bootloader.mm_total += entry->length; + if (entry->type == LIMINE_MEMMAP_USABLE) bootloader.mm_total_memory += entry->length; } bootloader.fb_entries = lim_fbuf_res->framebuffers; diff --git a/kernel/src/pmm.c b/kernel/src/pmm.c index ede321b..8aafb60 100644 --- a/kernel/src/pmm.c +++ b/kernel/src/pmm.c @@ -1,86 +1,44 @@ -#include "bitmap.h" #include #include +#include #include -#include +#include + #include -// Bitmap -bitmap_t pmm_bitmap; +uint64_t* pmm_head = NULL; int pmm_init(void) { - pmm_bitmap.blocks = dceil(bootloader.mm_total, BLOCK_SIZE); - pmm_bitmap.bytes = dceil(pmm_bitmap.blocks, 8); - - // # of pagetabs required to map the bitmap - size_t ptcount = dceil(dceil(pmm_bitmap.bytes, PAGE_SIZE), 1024); - - // Find enough space for the bitmap - struct limine_memmap_entry* mm = NULL; + debugf("[pmm] Physical memory map:\n"); // We're gonna use the loop to also print the memmap for (size_t i = 0; i < bootloader.mm_entry_count; i++) { struct limine_memmap_entry* entry = bootloader.mm_entries[i]; + + debugf( + "\t0x%x - 0x%x (%d bytes), type %d\n", + entry->base, entry->base + entry->length, entry->length, entry->type + ); - if (entry->type != LIMINE_MEMMAP_USABLE || entry->length < pmm_bitmap.bytes) continue; - mm = entry; - } + if (entry->type != LIMINE_MEMMAP_USABLE) continue; - if (!mm) { - debugf("[pmm] Not enough memory! Needs %d bytes.\n", pmm_bitmap.bytes); - return 1; - } - - size_t bitmap_start_phys = mm->base; - pmm_bitmap.map = (void*)(bitmap_start_phys + bootloader.hhdm_offset); - - // Set all blocks as used - bmap_set_all(&pmm_bitmap, 1); - - debugf("[pmm] Memory map:\n"); // Use the loop to also print the memmap - for (size_t i = 0; i < bootloader.mm_entry_count; i++) { - struct limine_memmap_entry* entry = bootloader.mm_entries[i]; - if (entry->length == 0) continue; // Ignore dummy entries - - if (entry->type == LIMINE_MEMMAP_USABLE) { - bmap_set_area(&pmm_bitmap, entry->base, entry->length, 0); + for (offset_t offset = 0; offset < entry->length; offset += PAGE_SIZE) { + uint64_t* addr = (uint64_t*)(entry->base + offset + bootloader.hhdm_offset); + *addr = (uint64_t)pmm_head; + pmm_head = addr; } - - // Print entry - debugf("\tRegion %2d: 0x%08x - 0x%08x (%d bytes) %s\n", - i + 1, entry->base, entry->base + entry->length - 1, entry->length, - (entry->type == LIMINE_MEMMAP_USABLE) ? "AVAILABLE" : "RESERVED"); } - bmap_set_area(&pmm_bitmap, bitmap_start_phys, pmm_bitmap.bytes, 1); - pmm_bitmap.used = 0; - // Beatiful print statement :) - debugf( - "[pmm] Physical memory manager initialized.\n" - "\tAvailable memory: %d blocks free (%d bytes)\n" - "\tBitmap at 0x%08x in physical memory\n" - "\tBitmap is %d bytes contained in %d pages\n", - pmm_bitmap.blocks - pmm_bitmap.used, - (pmm_bitmap.blocks - pmm_bitmap.used) * BLOCK_SIZE, - bitmap_start_phys, pmm_bitmap.bytes - ); - - pmm_bitmap.ready = 1; return 0; } -size_t pmm_alloc(void) { - if (pmm_bitmap.blocks - pmm_bitmap.used == 0) return 0; - - size_t base = bmap_get_area(&pmm_bitmap, 1, 0); - if (base == BMAP_NOT_FOUND) return 0; - - bmap_set(&pmm_bitmap, base, 1); - - return (size_t)bmap_ptr(&pmm_bitmap, base); +void* pmm_alloc() { + uint64_t* addr = pmm_head; + pmm_head = (uint64_t*)(*addr); + return addr - bootloader.hhdm_offset; } -void pmm_free(size_t page) { - size_t base = page / BLOCK_SIZE; - bmap_set_area(&pmm_bitmap, base, 1, 0); - bmap_set(&pmm_bitmap, 0, 1); +void pmm_free(void* page) { + uint64_t* addr = (uint64_t*)(page - bootloader.hhdm_offset); + *addr = (uint64_t)pmm_head; + pmm_head = addr; }