diff --git a/.clang-tidy b/.clang-tidy index 877871de..7fb5078b 100644 --- a/.clang-tidy +++ b/.clang-tidy @@ -14,5 +14,7 @@ Checks: > -llvm-header-guard, -bugprone-reserved-identifier, -bugprone-easily-swappable-parameters, - -clang-analyzer-security.insecureAPI.DeprecatedOrUnsafeBufferHandling + -clang-analyzer-security.insecureAPI.DeprecatedOrUnsafeBufferHandling, + -llvmlibc-* --- + diff --git a/assets/Limine/EFI/Boot/bootx64.efi b/assets/Limine/EFI/Boot/bootx64.efi index 2d0497a6..fa69cc87 100644 Binary files a/assets/Limine/EFI/Boot/bootx64.efi and b/assets/Limine/EFI/Boot/bootx64.efi differ diff --git a/assets/Limine/Limine/limine-bios-cd.bin b/assets/Limine/Limine/limine-bios-cd.bin index 97d2ba75..4bbeb02e 100644 Binary files a/assets/Limine/Limine/limine-bios-cd.bin and b/assets/Limine/Limine/limine-bios-cd.bin differ diff --git a/assets/Limine/Limine/limine-bios.sys b/assets/Limine/Limine/limine-bios.sys index 4453fd20..693483d0 100644 Binary files a/assets/Limine/Limine/limine-bios.sys and b/assets/Limine/Limine/limine-bios.sys differ diff --git a/assets/Limine/Limine/limine-uefi-cd.bin b/assets/Limine/Limine/limine-uefi-cd.bin index aad80a2b..b09c09fc 100644 Binary files a/assets/Limine/Limine/limine-uefi-cd.bin and b/assets/Limine/Limine/limine-uefi-cd.bin differ diff --git a/fs/vfs.c b/fs/vfs.c index 4a9b6cea..b342abbb 100644 --- a/fs/vfs.c +++ b/fs/vfs.c @@ -94,7 +94,7 @@ vfs_node_t vfs_node_alloc(vfs_node_t parent, const char *name) node->root = parent ? parent->root : node; node->dev = parent ? parent->dev : 0; node->refcount = 0; - node->blksz = PAGE_SIZE; + node->blksz = PAGE_4K_SIZE; node->mode = 0777; node->linkto = NULL; diff --git a/include/interrupt.h b/include/interrupt.h index fb4adb8e..aca80a48 100644 --- a/include/interrupt.h +++ b/include/interrupt.h @@ -16,8 +16,8 @@ #include "stdint.h" #if defined(__clang__) -# define INTERRUPT_BEGIN \ - _Pragma("clang diagnostic push") _Pragma("clang diagnostic ignored \"-Winterrupt-service-routine\"") \ +# define INTERRUPT_BEGIN \ + _Pragma("clang diagnostic push") _Pragma("clang diagnostic ignored \"-Wexcessive-regsave\"") \ __attribute__((interrupt, target("general-regs-only"))) # define INTERRUPT_END _Pragma("clang diagnostic pop") #elif defined(__GNUC__) diff --git a/include/limine.h b/include/limine.h index b393a7ac..b2e9b197 100644 --- a/include/limine.h +++ b/include/limine.h @@ -1,20 +1,29 @@ -/* - * - * limine.h - * Limine boot protocol header file +/* BSD Zero Clause License */ + +/* Copyright (C) 2022-2025 Mintsuki and contributors. * - * 2025/2/15 By MicroFish - * Based on Apache 2.0 open source license. - * Copyright © 2020 ViudiraTech, based on the Apache 2.0 license. + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted. * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#ifndef INCLUDE_LIMINE_H_ -#define INCLUDE_LIMINE_H_ +#ifndef LIMINE_H +#define LIMINE_H 1 + +#ifdef __cplusplus +extern "C" { +#endif -#include "stdint.h" +#include -/* Miscellaneous */ + /* Misc */ #ifdef LIMINE_NO_POINTERS # define LIMINE_PTR(TYPE) uint64_t @@ -22,6 +31,14 @@ # define LIMINE_PTR(TYPE) TYPE #endif +#ifndef LIMINE_API_REVISION +# define LIMINE_API_REVISION 0 +#endif + +#if LIMINE_API_REVISION > 4 +# error "limine.h API revision unsupported" +#endif + #ifdef __GNUC__ # define LIMINE_DEPRECATED __attribute__((__deprecated__)) # define LIMINE_DEPRECATED_IGNORE_START _Pragma("GCC diagnostic push") _Pragma("GCC diagnostic ignored \"-Wdeprecated-declarations\"") @@ -34,178 +51,186 @@ #define LIMINE_REQUESTS_START_MARKER \ uint64_t limine_requests_start_marker[4] = {0xf6b8f4b39de7d1ae, 0xfab91a6940fcb9cf, 0x785c6ed015d3e316, 0x181e920a7852b9d9}; - #define LIMINE_REQUESTS_END_MARKER uint64_t limine_requests_end_marker[2] = {0xadc0e0531bb10d03, 0x9572709f31764c62}; +#define LIMINE_REQUESTS_DELIMITER LIMINE_REQUESTS_END_MARKER + #define LIMINE_BASE_REVISION(N) uint64_t limine_base_revision[3] = {0xf9562b2d5c95a6c8, 0x6a7b384944536bdc, (N)}; -#define LIMINE_REQUESTS_DELIMITER LIMINE_REQUESTS_END_MARKER #define LIMINE_BASE_REVISION_SUPPORTED (limine_base_revision[2] == 0) -#define LIMINE_LOADED_BASE_REV_VALID (limine_base_revision[1] != 0x6a7b384944536bdc) -#define LIMINE_LOADED_BASE_REVISION (limine_base_revision[1]) -#define LIMINE_COMMON_MAGIC 0xc7b1dd30df4c8b88, 0x0a82e883a194f07b - -struct limine_uuid { - uint32_t a; - uint16_t b; - uint16_t c; - uint8_t d[8]; -}; + +#define LIMINE_LOADED_BASE_REV_VALID (limine_base_revision[1] != 0x6a7b384944536bdc) +#define LIMINE_LOADED_BASE_REVISION (limine_base_revision[1]) + +#define LIMINE_COMMON_MAGIC 0xc7b1dd30df4c8b88, 0x0a82e883a194f07b + + struct limine_uuid { + uint32_t a; + uint16_t b; + uint16_t c; + uint8_t d[8]; + }; #define LIMINE_MEDIA_TYPE_GENERIC 0 #define LIMINE_MEDIA_TYPE_OPTICAL 1 #define LIMINE_MEDIA_TYPE_TFTP 2 -struct limine_file { - uint64_t revision; - LIMINE_PTR(void *) - address; - uint64_t size; - LIMINE_PTR(char *) - path; - LIMINE_PTR(char *) - cmdline; - uint32_t media_type; - uint32_t unused; - uint32_t tftp_ip; - uint32_t tftp_port; - uint32_t partition_index; - uint32_t mbr_disk_id; - struct limine_uuid gpt_disk_uuid; - struct limine_uuid gpt_part_uuid; - struct limine_uuid part_uuid; -}; - -/* Startup Information */ + struct limine_file { + uint64_t revision; + LIMINE_PTR(void *) address; + uint64_t size; + LIMINE_PTR(char *) path; +#if LIMINE_API_REVISION >= 3 + LIMINE_PTR(char *) string; +#else + LIMINE_PTR(char *) cmdline; +#endif + uint32_t media_type; + uint32_t unused; + uint32_t tftp_ip; + uint32_t tftp_port; + uint32_t partition_index; + uint32_t mbr_disk_id; + struct limine_uuid gpt_disk_uuid; + struct limine_uuid gpt_part_uuid; + struct limine_uuid part_uuid; + }; + + /* Boot info */ #define LIMINE_BOOTLOADER_INFO_REQUEST {LIMINE_COMMON_MAGIC, 0xf55038d8e2a1202f, 0x279426fcf5f59740} -struct limine_bootloader_info_response { - uint64_t revision; - LIMINE_PTR(char *) - name; - LIMINE_PTR(char *) - version; -}; + struct limine_bootloader_info_response { + uint64_t revision; + LIMINE_PTR(char *) name; + LIMINE_PTR(char *) version; + }; -struct limine_bootloader_info_request { - uint64_t id[4]; - uint64_t revision; - LIMINE_PTR(struct limine_bootloader_info_response *) - response; -}; + struct limine_bootloader_info_request { + uint64_t id[4]; + uint64_t revision; + LIMINE_PTR(struct limine_bootloader_info_response *) response; + }; -/* Firmware Type */ + /* Executable command line */ + +#define LIMINE_EXECUTABLE_CMDLINE_REQUEST {LIMINE_COMMON_MAGIC, 0x4b161536e598651e, 0xb390ad4a2f1f303a} + + struct limine_executable_cmdline_response { + uint64_t revision; + LIMINE_PTR(char *) cmdline; + }; + + struct limine_executable_cmdline_request { + uint64_t id[4]; + uint64_t revision; + LIMINE_PTR(struct limine_executable_cmdline_response *) response; + }; + + /* Firmware type */ #define LIMINE_FIRMWARE_TYPE_REQUEST {LIMINE_COMMON_MAGIC, 0x8c2f75d90bef28a8, 0x7045a4688eac00c3} #define LIMINE_FIRMWARE_TYPE_X86BIOS 0 #define LIMINE_FIRMWARE_TYPE_UEFI32 1 #define LIMINE_FIRMWARE_TYPE_UEFI64 2 +#define LIMINE_FIRMWARE_TYPE_SBI 3 -struct limine_firmware_type_response { - uint64_t revision; - uint64_t firmware_type; -}; + struct limine_firmware_type_response { + uint64_t revision; + uint64_t firmware_type; + }; -struct limine_firmware_type_request { - uint64_t id[4]; - uint64_t revision; - LIMINE_PTR(struct limine_firmware_type_response *) - response; -}; + struct limine_firmware_type_request { + uint64_t id[4]; + uint64_t revision; + LIMINE_PTR(struct limine_firmware_type_response *) response; + }; -/* Stack size */ + /* Stack size */ #define LIMINE_STACK_SIZE_REQUEST {LIMINE_COMMON_MAGIC, 0x224ef0460a8e8926, 0xe1cb0fc25f46ea3d} -struct limine_stack_size_response { - uint64_t revision; -}; + struct limine_stack_size_response { + uint64_t revision; + }; -struct limine_stack_size_request { - uint64_t id[4]; - uint64_t revision; - LIMINE_PTR(struct limine_stack_size_response *) - response; - uint64_t stack_size; -}; + struct limine_stack_size_request { + uint64_t id[4]; + uint64_t revision; + LIMINE_PTR(struct limine_stack_size_response *) response; + uint64_t stack_size; + }; -/* High-level data mapping */ + /* HHDM */ #define LIMINE_HHDM_REQUEST {LIMINE_COMMON_MAGIC, 0x48dcf1cb8ad2b852, 0x63984e959a98244b} -struct limine_hhdm_response { - uint64_t revision; - uint64_t offset; -}; + struct limine_hhdm_response { + uint64_t revision; + uint64_t offset; + }; -struct limine_hhdm_request { - uint64_t id[4]; - uint64_t revision; - LIMINE_PTR(struct limine_hhdm_response *) - response; -}; + struct limine_hhdm_request { + uint64_t id[4]; + uint64_t revision; + LIMINE_PTR(struct limine_hhdm_response *) response; + }; -/* Frame Buffer */ + /* Framebuffer */ #define LIMINE_FRAMEBUFFER_REQUEST {LIMINE_COMMON_MAGIC, 0x9d5827dcd881dd75, 0xa3148604f6fab11b} -#define LIMINE_FRAMEBUFFER_RGB 1 - -struct limine_video_mode { - uint64_t pitch; - uint64_t width; - uint64_t height; - uint16_t bpp; - uint8_t memory_model; - uint8_t red_mask_size; - uint8_t red_mask_shift; - uint8_t green_mask_size; - uint8_t green_mask_shift; - uint8_t blue_mask_size; - uint8_t blue_mask_shift; -}; - -struct limine_framebuffer { - LIMINE_PTR(void *) - address; - uint64_t width; - uint64_t height; - uint64_t pitch; - uint16_t bpp; - uint8_t memory_model; - uint8_t red_mask_size; - uint8_t red_mask_shift; - uint8_t green_mask_size; - uint8_t green_mask_shift; - uint8_t blue_mask_size; - uint8_t blue_mask_shift; - uint8_t unused[7]; - uint64_t edid_size; - LIMINE_PTR(void *) - edid; - - /* Response to Revision 1 */ - uint64_t mode_count; - LIMINE_PTR(struct limine_video_mode **) - modes; -}; - -struct limine_framebuffer_response { - uint64_t revision; - uint64_t framebuffer_count; - LIMINE_PTR(struct limine_framebuffer **) - framebuffers; -}; -struct limine_framebuffer_request { - uint64_t id[4]; - uint64_t revision; - LIMINE_PTR(struct limine_framebuffer_response *) - response; -}; - -/* terminal */ +#define LIMINE_FRAMEBUFFER_RGB 1 + + struct limine_video_mode { + uint64_t pitch; + uint64_t width; + uint64_t height; + uint16_t bpp; + uint8_t memory_model; + uint8_t red_mask_size; + uint8_t red_mask_shift; + uint8_t green_mask_size; + uint8_t green_mask_shift; + uint8_t blue_mask_size; + uint8_t blue_mask_shift; + }; + + struct limine_framebuffer { + LIMINE_PTR(void *) address; + uint64_t width; + uint64_t height; + uint64_t pitch; + uint16_t bpp; + uint8_t memory_model; + uint8_t red_mask_size; + uint8_t red_mask_shift; + uint8_t green_mask_size; + uint8_t green_mask_shift; + uint8_t blue_mask_size; + uint8_t blue_mask_shift; + uint8_t unused[7]; + uint64_t edid_size; + LIMINE_PTR(void *) edid; + /* Response revision 1 */ + uint64_t mode_count; + LIMINE_PTR(struct limine_video_mode **) modes; + }; + + struct limine_framebuffer_response { + uint64_t revision; + uint64_t framebuffer_count; + LIMINE_PTR(struct limine_framebuffer **) framebuffers; + }; + + struct limine_framebuffer_request { + uint64_t id[4]; + uint64_t revision; + LIMINE_PTR(struct limine_framebuffer_response *) response; + }; + + /* Terminal */ #define LIMINE_TERMINAL_REQUEST {LIMINE_COMMON_MAGIC, 0xc8ac59310c2b0844, 0xa68d0c7265d38878} @@ -223,7 +248,7 @@ struct limine_framebuffer_request { #define LIMINE_TERMINAL_CTX_RESTORE ((uint64_t)(-3)) #define LIMINE_TERMINAL_FULL_REFRESH ((uint64_t)(-4)) -/* Response to Revision 1 */ +/* Response revision 1 */ #define LIMINE_TERMINAL_OOB_OUTPUT_GET ((uint64_t)(-10)) #define LIMINE_TERMINAL_OOB_OUTPUT_SET ((uint64_t)(-11)) @@ -236,203 +261,193 @@ struct limine_framebuffer_request { #define LIMINE_TERMINAL_OOB_OUTPUT_ONOCR (1 << 6) #define LIMINE_TERMINAL_OOB_OUTPUT_OPOST (1 << 7) -LIMINE_DEPRECATED_IGNORE_START + LIMINE_DEPRECATED_IGNORE_START -struct LIMINE_DEPRECATED limine_terminal; -typedef void (*limine_terminal_write)(struct limine_terminal *, const char *, uint64_t); -typedef void (*limine_terminal_callback)(struct limine_terminal *, uint64_t, uint64_t, uint64_t, uint64_t); + struct LIMINE_DEPRECATED limine_terminal; -struct LIMINE_DEPRECATED limine_terminal { - uint64_t columns; - uint64_t rows; - LIMINE_PTR(struct limine_framebuffer *) - framebuffer; -}; + typedef void (*limine_terminal_write)(struct limine_terminal *, const char *, uint64_t); + typedef void (*limine_terminal_callback)(struct limine_terminal *, uint64_t, uint64_t, uint64_t, uint64_t); -struct LIMINE_DEPRECATED limine_terminal_response { - uint64_t revision; - uint64_t terminal_count; - LIMINE_PTR(struct limine_terminal **) - terminals; - LIMINE_PTR(limine_terminal_write) - write; -}; + struct LIMINE_DEPRECATED limine_terminal { + uint64_t columns; + uint64_t rows; + LIMINE_PTR(struct limine_framebuffer *) framebuffer; + }; -struct LIMINE_DEPRECATED limine_terminal_request { - uint64_t id[4]; - uint64_t revision; - LIMINE_PTR(struct limine_terminal_response *) - response; - LIMINE_PTR(limine_terminal_callback) - callback; -}; + struct LIMINE_DEPRECATED limine_terminal_response { + uint64_t revision; + uint64_t terminal_count; + LIMINE_PTR(struct limine_terminal **) terminals; + LIMINE_PTR(limine_terminal_write) write; + }; + + struct LIMINE_DEPRECATED limine_terminal_request { + uint64_t id[4]; + uint64_t revision; + LIMINE_PTR(struct limine_terminal_response *) response; + LIMINE_PTR(limine_terminal_callback) callback; + }; -LIMINE_DEPRECATED_IGNORE_END + LIMINE_DEPRECATED_IGNORE_END -/* Paging Mode */ + /* Paging mode */ #define LIMINE_PAGING_MODE_REQUEST {LIMINE_COMMON_MAGIC, 0x95c1a0edab0944cb, 0xa4e5cb3842f7488a} #if defined(__x86_64__) || defined(__i386__) - # define LIMINE_PAGING_MODE_X86_64_4LVL 0 # define LIMINE_PAGING_MODE_X86_64_5LVL 1 # define LIMINE_PAGING_MODE_MIN LIMINE_PAGING_MODE_X86_64_4LVL # define LIMINE_PAGING_MODE_DEFAULT LIMINE_PAGING_MODE_X86_64_4LVL - #elif defined(__aarch64__) - # define LIMINE_PAGING_MODE_AARCH64_4LVL 0 # define LIMINE_PAGING_MODE_AARCH64_5LVL 1 # define LIMINE_PAGING_MODE_MIN LIMINE_PAGING_MODE_AARCH64_4LVL # define LIMINE_PAGING_MODE_DEFAULT LIMINE_PAGING_MODE_AARCH64_4LVL - #elif defined(__riscv) && (__riscv_xlen == 64) - # define LIMINE_PAGING_MODE_RISCV_SV39 0 # define LIMINE_PAGING_MODE_RISCV_SV48 1 # define LIMINE_PAGING_MODE_RISCV_SV57 2 # define LIMINE_PAGING_MODE_MIN LIMINE_PAGING_MODE_RISCV_SV39 # define LIMINE_PAGING_MODE_DEFAULT LIMINE_PAGING_MODE_RISCV_SV48 - #elif defined(__loongarch__) && (__loongarch_grlen == 64) - # define LIMINE_PAGING_MODE_LOONGARCH64_4LVL 0 # define LIMINE_PAGING_MODE_MIN LIMINE_PAGING_MODE_LOONGARCH64_4LVL # define LIMINE_PAGING_MODE_DEFAULT LIMINE_PAGING_MODE_LOONGARCH64_4LVL - #else # error Unknown architecture #endif -struct limine_paging_mode_response { - uint64_t revision; - uint64_t mode; -}; + struct limine_paging_mode_response { + uint64_t revision; + uint64_t mode; + }; -struct limine_paging_mode_request { - uint64_t id[4]; - uint64_t revision; - LIMINE_PTR(struct limine_paging_mode_response *) - response; - uint64_t mode; - uint64_t max_mode; - uint64_t min_mode; -}; + struct limine_paging_mode_request { + uint64_t id[4]; + uint64_t revision; + LIMINE_PTR(struct limine_paging_mode_response *) response; + uint64_t mode; + uint64_t max_mode; + uint64_t min_mode; + }; -/* Five-level paging */ + /* 5-level paging */ #define LIMINE_5_LEVEL_PAGING_REQUEST {LIMINE_COMMON_MAGIC, 0x94469551da9b3192, 0xebe5e86db7382888} -LIMINE_DEPRECATED_IGNORE_START + LIMINE_DEPRECATED_IGNORE_START -struct LIMINE_DEPRECATED limine_5_level_paging_response { - uint64_t revision; -}; + struct LIMINE_DEPRECATED limine_5_level_paging_response { + uint64_t revision; + }; -struct LIMINE_DEPRECATED limine_5_level_paging_request { - uint64_t id[4]; - uint64_t revision; - LIMINE_PTR(struct limine_5_level_paging_response *) - response; -}; + struct LIMINE_DEPRECATED limine_5_level_paging_request { + uint64_t id[4]; + uint64_t revision; + LIMINE_PTR(struct limine_5_level_paging_response *) response; + }; -LIMINE_DEPRECATED_IGNORE_END + LIMINE_DEPRECATED_IGNORE_END -/* Symmetric Multiprocessing */ + /* MP */ -#define LIMINE_SMP_REQUEST {LIMINE_COMMON_MAGIC, 0x95a67b819a1b857e, 0xa0b61b723b6a73e0} +#if LIMINE_API_REVISION >= 1 +# define LIMINE_MP_REQUEST {LIMINE_COMMON_MAGIC, 0x95a67b819a1b857e, 0xa0b61b723b6a73e0} +# define LIMINE_MP(TEXT) limine_mp_##TEXT +#else +# define LIMINE_SMP_REQUEST {LIMINE_COMMON_MAGIC, 0x95a67b819a1b857e, 0xa0b61b723b6a73e0} +# define LIMINE_MP(TEXT) limine_smp_##TEXT +#endif -struct limine_smp_info; -typedef void (*limine_goto_address)(struct limine_smp_info *); + struct LIMINE_MP(info); -#if defined(__x86_64__) || defined(__i386__) -# define LIMINE_SMP_X2APIC (1 << 0) + typedef void (*limine_goto_address)(struct LIMINE_MP(info) *); -struct limine_smp_info { - uint32_t processor_id; - uint32_t lapic_id; - uint64_t reserved; - LIMINE_PTR(limine_goto_address) - goto_address; - uint64_t extra_argument; -}; +#if defined(__x86_64__) || defined(__i386__) -struct limine_smp_response { - uint64_t revision; - uint32_t flags; - uint32_t bsp_lapic_id; - uint64_t cpu_count; - LIMINE_PTR(struct limine_smp_info **) - cpus; -}; +# if LIMINE_API_REVISION >= 1 +# define LIMINE_MP_X2APIC (1 << 0) +# else +# define LIMINE_SMP_X2APIC (1 << 0) +# endif + + struct LIMINE_MP(info) { + uint32_t processor_id; + uint32_t lapic_id; + uint64_t reserved; + LIMINE_PTR(limine_goto_address) goto_address; + uint64_t extra_argument; + }; + + struct LIMINE_MP(response) { + uint64_t revision; + uint32_t flags; + uint32_t bsp_lapic_id; + uint64_t cpu_count; + LIMINE_PTR(struct LIMINE_MP(info) **) cpus; + }; #elif defined(__aarch64__) -struct limine_smp_info { +struct LIMINE_MP(info) { uint32_t processor_id; uint32_t reserved1; uint64_t mpidr; uint64_t reserved; - LIMINE_PTR(limine_goto_address) - goto_address; + LIMINE_PTR(limine_goto_address) goto_address; uint64_t extra_argument; }; -struct limine_smp_response { +struct LIMINE_MP(response) { uint64_t revision; uint64_t flags; uint64_t bsp_mpidr; uint64_t cpu_count; - LIMINE_PTR(struct limine_smp_info **) - cpus; + LIMINE_PTR(struct LIMINE_MP(info) **) cpus; }; #elif defined(__riscv) && (__riscv_xlen == 64) -struct limine_smp_info { +struct LIMINE_MP(info) { uint64_t processor_id; uint64_t hartid; uint64_t reserved; - LIMINE_PTR(limine_goto_address) - goto_address; + LIMINE_PTR(limine_goto_address) goto_address; uint64_t extra_argument; }; -struct limine_smp_response { +struct LIMINE_MP(response) { uint64_t revision; uint64_t flags; uint64_t bsp_hartid; uint64_t cpu_count; - LIMINE_PTR(struct limine_smp_info **) - cpus; + LIMINE_PTR(struct LIMINE_MP(info) **) cpus; }; #elif defined(__loongarch__) && (__loongarch_grlen == 64) -struct limine_smp_info { +struct LIMINE_MP(info) { uint64_t reserved; }; -struct limine_smp_response { +struct LIMINE_MP(response) { uint64_t cpu_count; - LIMINE_PTR(struct limine_smp_info **) - cpus; + LIMINE_PTR(struct LIMINE_MP(info) **) cpus; }; #else # error Unknown architecture #endif -struct limine_smp_request { - uint64_t id[4]; - uint64_t revision; - LIMINE_PTR(struct limine_smp_response *) - response; - uint64_t flags; -}; + struct LIMINE_MP(request) { + uint64_t id[4]; + uint64_t revision; + LIMINE_PTR(struct LIMINE_MP(response) *) response; + uint64_t flags; + }; -/* Memory Map */ + /* Memory map */ #define LIMINE_MEMMAP_REQUEST {LIMINE_COMMON_MAGIC, 0x67cf3d9d378a806f, 0xe304acdfc50c3c62} @@ -442,220 +457,310 @@ struct limine_smp_request { #define LIMINE_MEMMAP_ACPI_NVS 3 #define LIMINE_MEMMAP_BAD_MEMORY 4 #define LIMINE_MEMMAP_BOOTLOADER_RECLAIMABLE 5 -#define LIMINE_MEMMAP_KERNEL_AND_MODULES 6 -#define LIMINE_MEMMAP_FRAMEBUFFER 7 +#if LIMINE_API_REVISION >= 2 +# define LIMINE_MEMMAP_EXECUTABLE_AND_MODULES 6 +#else +# 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; - uint64_t length; - uint64_t type; -}; + struct limine_memmap_entry { + uint64_t base; + uint64_t length; + uint64_t type; + }; -struct limine_memmap_response { - uint64_t revision; - uint64_t entry_count; - LIMINE_PTR(struct limine_memmap_entry **) - entries; -}; + struct limine_memmap_response { + uint64_t revision; + uint64_t entry_count; + LIMINE_PTR(struct limine_memmap_entry **) entries; + }; -struct limine_memmap_request { - uint64_t id[4]; - uint64_t revision; - LIMINE_PTR(struct limine_memmap_response *) - response; -}; + struct limine_memmap_request { + uint64_t id[4]; + uint64_t revision; + LIMINE_PTR(struct limine_memmap_response *) response; + }; -/* Entry Point */ + /* Entry point */ #define LIMINE_ENTRY_POINT_REQUEST {LIMINE_COMMON_MAGIC, 0x13d86c035a1cd3e1, 0x2b0caa89d8f3026a} -typedef void (*limine_entry_point)(void); + typedef void (*limine_entry_point)(void); -struct limine_entry_point_response { - uint64_t revision; -}; + struct limine_entry_point_response { + uint64_t revision; + }; -struct limine_entry_point_request { - uint64_t id[4]; - uint64_t revision; - LIMINE_PTR(struct limine_entry_point_response *) - response; - LIMINE_PTR(limine_entry_point) - entry; -}; + struct limine_entry_point_request { + uint64_t id[4]; + uint64_t revision; + LIMINE_PTR(struct limine_entry_point_response *) response; + LIMINE_PTR(limine_entry_point) entry; + }; -/* Kernel Files */ + /* Executable File */ -#define LIMINE_KERNEL_FILE_REQUEST {LIMINE_COMMON_MAGIC, 0xad97e90e83f1ed67, 0x31eb5d1c5ff23b69} +#if LIMINE_API_REVISION >= 2 +# define LIMINE_EXECUTABLE_FILE_REQUEST {LIMINE_COMMON_MAGIC, 0xad97e90e83f1ed67, 0x31eb5d1c5ff23b69} +#else +# define LIMINE_KERNEL_FILE_REQUEST {LIMINE_COMMON_MAGIC, 0xad97e90e83f1ed67, 0x31eb5d1c5ff23b69} +#endif +#if LIMINE_API_REVISION >= 2 + struct limine_executable_file_response { +#else struct limine_kernel_file_response { - uint64_t revision; - LIMINE_PTR(struct limine_file *) - kernel_file; -}; +#endif + uint64_t revision; +#if LIMINE_API_REVISION >= 2 + LIMINE_PTR(struct limine_file *) executable_file; +#else + LIMINE_PTR(struct limine_file *) kernel_file; +#endif + }; +#if LIMINE_API_REVISION >= 2 + struct limine_executable_file_request { +#else struct limine_kernel_file_request { - uint64_t id[4]; - uint64_t revision; - LIMINE_PTR(struct limine_kernel_file_response *) - response; -}; +#endif + uint64_t id[4]; + uint64_t revision; +#if LIMINE_API_REVISION >= 2 + LIMINE_PTR(struct limine_executable_file_response *) response; +#else + LIMINE_PTR(struct limine_kernel_file_response *) response; +#endif + }; -/* Modules */ + /* Module */ #define LIMINE_MODULE_REQUEST {LIMINE_COMMON_MAGIC, 0x3e7e279702be32af, 0xca1c4f3bd1280cee} #define LIMINE_INTERNAL_MODULE_REQUIRED (1 << 0) #define LIMINE_INTERNAL_MODULE_COMPRESSED (1 << 1) -struct limine_internal_module { - LIMINE_PTR(const char *) - path; - LIMINE_PTR(const char *) - cmdline; - uint64_t flags; -}; + struct limine_internal_module { + LIMINE_PTR(const char *) path; +#if LIMINE_API_REVISION >= 3 + LIMINE_PTR(const char *) string; +#else + LIMINE_PTR(const char *) cmdline; +#endif + uint64_t flags; + }; -struct limine_module_response { - uint64_t revision; - uint64_t module_count; - LIMINE_PTR(struct limine_file **) - modules; -}; + struct limine_module_response { + uint64_t revision; + uint64_t module_count; + LIMINE_PTR(struct limine_file **) modules; + }; -struct limine_module_request { - uint64_t id[4]; - uint64_t revision; - LIMINE_PTR(struct limine_module_response *) - response; + struct limine_module_request { + uint64_t id[4]; + uint64_t revision; + LIMINE_PTR(struct limine_module_response *) response; - /* Request Revision 1 */ - uint64_t internal_module_count; - LIMINE_PTR(struct limine_internal_module **) - internal_modules; -}; + /* Request revision 1 */ + uint64_t internal_module_count; + LIMINE_PTR(struct limine_internal_module **) internal_modules; + }; -/* Root System Description Pointer */ + /* RSDP */ #define LIMINE_RSDP_REQUEST {LIMINE_COMMON_MAGIC, 0xc5e77b6b397e7b43, 0x27637845accdcf3c} -struct limine_rsdp_response { - uint64_t revision; - LIMINE_PTR(void *) - address; -}; + struct limine_rsdp_response { + uint64_t revision; +#if LIMINE_API_REVISION >= 1 && LIMINE_API_REVISION <= 3 + uint64_t address; +#else + LIMINE_PTR(void *) address; +#endif + }; -struct limine_rsdp_request { - uint64_t id[4]; - uint64_t revision; - LIMINE_PTR(struct limine_rsdp_response *) - response; -}; + struct limine_rsdp_request { + uint64_t id[4]; + uint64_t revision; + LIMINE_PTR(struct limine_rsdp_response *) response; + }; -/* System Management BIOS */ + /* SMBIOS */ #define LIMINE_SMBIOS_REQUEST {LIMINE_COMMON_MAGIC, 0x9e9046f11e095391, 0xaa4a520fefbde5ee} -struct limine_smbios_response { - uint64_t revision; - LIMINE_PTR(void *) - entry_32; - LIMINE_PTR(void *) - entry_64; -}; + struct limine_smbios_response { + uint64_t revision; +#if LIMINE_API_REVISION >= 1 + uint64_t entry_32; + uint64_t entry_64; +#else + LIMINE_PTR(void *) entry_32; + LIMINE_PTR(void *) entry_64; +#endif + }; -struct limine_smbios_request { - uint64_t id[4]; - uint64_t revision; - LIMINE_PTR(struct limine_smbios_response *) - response; -}; + struct limine_smbios_request { + uint64_t id[4]; + uint64_t revision; + LIMINE_PTR(struct limine_smbios_response *) response; + }; -/* EFI System Table */ + /* EFI system table */ #define LIMINE_EFI_SYSTEM_TABLE_REQUEST {LIMINE_COMMON_MAGIC, 0x5ceba5163eaaf6d6, 0x0a6981610cf65fcc} -struct limine_efi_system_table_response { - uint64_t revision; - LIMINE_PTR(void *) - address; -}; + struct limine_efi_system_table_response { + uint64_t revision; +#if LIMINE_API_REVISION >= 1 + uint64_t address; +#else + LIMINE_PTR(void *) address; +#endif + }; -struct limine_efi_system_table_request { - uint64_t id[4]; - uint64_t revision; - LIMINE_PTR(struct limine_efi_system_table_response *) - response; -}; + struct limine_efi_system_table_request { + uint64_t id[4]; + uint64_t revision; + LIMINE_PTR(struct limine_efi_system_table_response *) response; + }; -/* EFI Memory Map */ + /* EFI memory map */ #define LIMINE_EFI_MEMMAP_REQUEST {LIMINE_COMMON_MAGIC, 0x7df62a431d6872d5, 0xa4fcdfb3e57306c8} -struct limine_efi_memmap_response { - uint64_t revision; - LIMINE_PTR(void *) - memmap; - uint64_t memmap_size; - uint64_t desc_size; - uint64_t desc_version; -}; + struct limine_efi_memmap_response { + uint64_t revision; + LIMINE_PTR(void *) memmap; + uint64_t memmap_size; + uint64_t desc_size; + uint64_t desc_version; + }; -struct limine_efi_memmap_request { - uint64_t id[4]; - uint64_t revision; - LIMINE_PTR(struct limine_efi_memmap_response *) - response; -}; + struct limine_efi_memmap_request { + uint64_t id[4]; + uint64_t revision; + LIMINE_PTR(struct limine_efi_memmap_response *) response; + }; -/* Startup time */ + /* Date at boot */ -#define LIMINE_BOOT_TIME_REQUEST {LIMINE_COMMON_MAGIC, 0x502746e184c088aa, 0xfbc5ec83e6327893} +#if LIMINE_API_REVISION >= 3 +# define LIMINE_DATE_AT_BOOT_REQUEST {LIMINE_COMMON_MAGIC, 0x502746e184c088aa, 0xfbc5ec83e6327893} +#else +# define LIMINE_BOOT_TIME_REQUEST {LIMINE_COMMON_MAGIC, 0x502746e184c088aa, 0xfbc5ec83e6327893} +#endif +#if LIMINE_API_REVISION >= 3 + struct limine_date_at_boot_response { +#else struct limine_boot_time_response { - uint64_t revision; - int64_t boot_time; -}; +#endif + uint64_t revision; +#if LIMINE_API_REVISION >= 3 + int64_t timestamp; +#else + int64_t boot_time; +#endif + }; +#if LIMINE_API_REVISION >= 3 + struct limine_date_at_boot_request { +#else struct limine_boot_time_request { - uint64_t id[4]; - uint64_t revision; - LIMINE_PTR(struct limine_boot_time_response *) - response; -}; +#endif + uint64_t id[4]; + uint64_t revision; +#if LIMINE_API_REVISION >= 3 + LIMINE_PTR(struct limine_date_at_boot_response *) response; +#else + LIMINE_PTR(struct limine_boot_time_response *) response; +#endif + }; -/* Kernel Address */ + /* Executable address */ -#define LIMINE_KERNEL_ADDRESS_REQUEST {LIMINE_COMMON_MAGIC, 0x71ba76863cc55f63, 0xb2644a48c516a487} +#if LIMINE_API_REVISION >= 2 +# define LIMINE_EXECUTABLE_ADDRESS_REQUEST {LIMINE_COMMON_MAGIC, 0x71ba76863cc55f63, 0xb2644a48c516a487} +#else +# define LIMINE_KERNEL_ADDRESS_REQUEST {LIMINE_COMMON_MAGIC, 0x71ba76863cc55f63, 0xb2644a48c516a487} +#endif +#if LIMINE_API_REVISION >= 2 + struct limine_executable_address_response { +#else struct limine_kernel_address_response { - uint64_t revision; - uint64_t physical_base; - uint64_t virtual_base; -}; +#endif + uint64_t revision; + uint64_t physical_base; + uint64_t virtual_base; + }; +#if LIMINE_API_REVISION >= 2 + struct limine_executable_address_request { +#else struct limine_kernel_address_request { - uint64_t id[4]; - uint64_t revision; - LIMINE_PTR(struct limine_kernel_address_response *) - response; -}; +#endif + uint64_t id[4]; + uint64_t revision; +#if LIMINE_API_REVISION >= 2 + LIMINE_PTR(struct limine_executable_address_response *) response; +#else + LIMINE_PTR(struct limine_kernel_address_response *) response; +#endif + }; -/* Device Tree Binaries */ + /* Device Tree Blob */ #define LIMINE_DTB_REQUEST {LIMINE_COMMON_MAGIC, 0xb40ddb48fb54bac7, 0x545081493f81ffb7} -struct limine_dtb_response { - uint64_t revision; - LIMINE_PTR(void *) - dtb_ptr; -}; + struct limine_dtb_response { + uint64_t revision; + LIMINE_PTR(void *) dtb_ptr; + }; -struct limine_dtb_request { - uint64_t id[4]; - uint64_t revision; - LIMINE_PTR(struct limine_dtb_response *) - response; -}; + struct limine_dtb_request { + uint64_t id[4]; + uint64_t revision; + LIMINE_PTR(struct limine_dtb_response *) response; + }; -#endif // INCLUDE_LIMINE_H_ + /* RISC-V Boot Hart ID */ + +#define LIMINE_RISCV_BSP_HARTID_REQUEST {LIMINE_COMMON_MAGIC, 0x1369359f025525f9, 0x2ff2a56178391bb6} + + struct limine_riscv_bsp_hartid_response { + uint64_t revision; + uint64_t bsp_hartid; + }; + + struct limine_riscv_bsp_hartid_request { + uint64_t id[4]; + uint64_t revision; + LIMINE_PTR(struct limine_riscv_bsp_hartid_response *) response; + }; + + /* Bootloader Performance */ + +#define LIMINE_BOOTLOADER_PERFORMANCE_REQUEST {LIMINE_COMMON_MAGIC, 0x6b50ad9bf36d13ad, 0xdc4c7e88fc759e17} + + struct limine_bootloader_performance_response { + uint64_t revision; + uint64_t reset_usec; + uint64_t init_usec; + uint64_t exec_usec; + }; + + struct limine_bootloader_performance_request { + uint64_t id[4]; + uint64_t revision; + LIMINE_PTR(struct limine_bootloader_performance_response *) response; + }; + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/include/page.h b/include/page.h index 0c828db7..077a28e3 100644 --- a/include/page.h +++ b/include/page.h @@ -24,12 +24,15 @@ #define PTE_NO_EXECUTE (((uint64_t)0x1) << 63) #define KERNEL_PTE_FLAGS (PTE_PRESENT | PTE_WRITEABLE | PTE_NO_EXECUTE) -#define PAGE_SIZE 0x1000ULL -#define PAGE_FLAGS_MASK 0x000ffffffffff000ULL -#define HUGE_2M_SIZE 0x200000ULL -#define HUGE_PAGE_2M_MASK 0x000fffffffe00000ULL -#define HUGE_1G_SIZE 0x40000000ULL -#define HUGE_PAGE_1G_MASK 0x000fffffc0000000ULL +/* Page size constants */ +#define PAGE_4K_SIZE 0x1000ULL // (1ULL << 12) +#define PAGE_2M_SIZE 0x200000ULL // (1ULL << 21) +#define PAGE_1G_SIZE 0x40000000ULL // (1ULL << 30) + +/* Page size masks */ +#define PAGE_4K_MASK 0x000ffffffffff000ULL // ((PAGE_4K_SIZE - 1) ^ ((1ULL << 52) - 1)) +#define PAGE_2M_MASK 0x000fffffffe00000ULL // (~(PAGE_2M_SIZE - 1) & PAGE_4K_MASK) +#define PAGE_1G_MASK 0x000fffffc0000000ULL // (~(PAGE_1G_SIZE - 1) & PAGE_4K_MASK) typedef struct { uint64_t value; diff --git a/include/page_walker.h b/include/page_walker.h index 0c4336e0..3697f247 100644 --- a/include/page_walker.h +++ b/include/page_walker.h @@ -45,11 +45,51 @@ typedef struct { page_table_t *l1_table; /* Status flags */ - uint8_t is_valid : 1; - uint8_t is_huge : 1; - uint8_t reserved : 6; + uint8_t is_valid : 1; + uint8_t is_huge : 1; + uint8_t page_size : 2; /* 0=4K, 1=2M, 2=1G */ + uint8_t reserved : 4; } page_walk_state_t; +/* Get page size from walk state */ +static inline size_t get_page_size_from_state(const page_walk_state_t *state) +{ + if (!state->is_valid) return PAGE_4K_SIZE; + + switch (state->page_size) { + case 2 : + return PAGE_1G_SIZE; /* 1GB page */ + case 1 : + return PAGE_2M_SIZE; /* 2MB page */ + default : + return PAGE_4K_SIZE; /* 4KB page */ + } +} + +/* Check if address is aligned to specific page size */ +static inline uint8_t is_page_aligned(uintptr_t addr, size_t page_size) +{ + return (addr & (page_size - 1)) == 0; +} + +/* Align address down to specific page size */ +static inline uintptr_t align_down_to_page(uintptr_t addr, size_t page_size) +{ + return addr & ~(page_size - 1); +} + +/* Align address up to specific page size */ +static inline uintptr_t align_up_to_page(uintptr_t addr, size_t page_size) +{ + return (addr + page_size - 1) & ~(page_size - 1); +} + +/* Get next aligned address for specific page size */ +static inline uintptr_t get_next_aligned_addr(uintptr_t addr, size_t page_size) +{ + return align_up_to_page(addr, page_size); +} + /* Init page_walk_state */ void page_walk_init(page_walk_state_t *state, page_directory_t *directory, uintptr_t virtual_addr); @@ -62,13 +102,10 @@ uintptr_t walk_page_tables(page_directory_t *directory, uintptr_t virtual_addr); /* Efficiently update state to next page */ void update_walk_state_for_next_page(page_walk_state_t *state, uintptr_t next_virtual); -/* Fast range free checker with large page */ -size_t check_range_free_fast(page_directory_t *directory, uintptr_t start, size_t length); - -/* Check range free with state */ -size_t check_range_free_with_state(page_walk_state_t *state, uintptr_t start, size_t length); +/* Check range free with state - supports multiple page sizes */ +size_t check_range_free_with_state(page_walk_state_t *state, uintptr_t start, size_t length, size_t desired_size); -/* Find a free virtual memory range of specified length */ -uintptr_t walk_page_tables_find_free(page_directory_t *directory, uintptr_t start, size_t length); +/* Find a free virtual memory range of specified length with preferred page size */ +uintptr_t walk_page_tables_find_free(page_directory_t *directory, uintptr_t start, size_t length, size_t preferred_size); #endif // PAGE_WALKER_H_ diff --git a/kernel/cpu/smp.c b/kernel/cpu/smp.c index b79d81e1..ffec70fb 100644 --- a/kernel/cpu/smp.c +++ b/kernel/cpu/smp.c @@ -103,7 +103,7 @@ void flush_tlb_all(void) /* Flushing TLB by address range */ void flush_tlb_range(uint64_t start, uint64_t end) { - for (uint64_t addr = start; addr < end; addr += PAGE_SIZE) flush_tlb(addr); + for (uint64_t addr = start; addr < end; addr += PAGE_4K_SIZE) flush_tlb(addr); } /* Get the number of CPUs */ diff --git a/mem/frame.c b/mem/frame.c index 2e6d4e24..c442f2b7 100644 --- a/mem/frame.c +++ b/mem/frame.c @@ -33,7 +33,7 @@ void init_frame(void) break; } } - size_t bitmap_size = (memory_size / PAGE_SIZE + 7) / 8; + size_t bitmap_size = (memory_size / PAGE_4K_SIZE + 7) / 8; uint64_t bitmap_address = 0; for (uint64_t i = 0; i < memory_map->entry_count; i++) { diff --git a/mem/heap.c b/mem/heap.c index bbb1dd6f..d9748241 100644 --- a/mem/heap.c +++ b/mem/heap.c @@ -11,24 +11,30 @@ #include "heap.h" #include "alloc.h" -#include "cpuid.h" #include "frame.h" #include "hhdm.h" +#include "limine.h" #include "page.h" +#include "page_walker.h" #include "stddef.h" #include "stdint.h" #include "stdlib.h" #include "string.h" +#include "uinxed.h" -uint64_t KERNEL_HEAP_START = 0xffff900000000000; -uint64_t KERNEL_HEAP_SIZE = 0x6400000; +uint64_t KERNEL_HEAP_START = 0; +uint64_t KERNEL_HEAP_SIZE = 0; /* Initialize the memory heap */ void init_heap(void) { - if (!KERNEL_HEAP_START) KERNEL_HEAP_START = (1ULL << (get_cpu_phys_bits() + 1)) + get_physical_memory_offset(); - if (!KERNEL_HEAP_SIZE) KERNEL_HEAP_SIZE = frame_allocator.usable_frames / 2 * PAGE_SIZE; // 1/2 of usable memory + struct limine_memmap_response *memmap_response = memmap_request.response; + struct limine_memmap_entry *last_entry = memmap_response->entries[memmap_response->entry_count - 1]; + if (!KERNEL_HEAP_START) KERNEL_HEAP_START = (last_entry->base + last_entry->length) + get_physical_memory_offset(); + if (!KERNEL_HEAP_SIZE) KERNEL_HEAP_SIZE = frame_allocator.usable_frames / 2 * PAGE_4K_SIZE; // 1/2 of usable memory + KERNEL_HEAP_START = ALIGN_UP(KERNEL_HEAP_START, PAGE_1G_SIZE); + KERNEL_HEAP_START = walk_page_tables_find_free(get_kernel_pagedir(), KERNEL_HEAP_START, KERNEL_HEAP_SIZE, PAGE_1G_SIZE); page_map_range_to_random(get_kernel_pagedir(), KERNEL_HEAP_START, KERNEL_HEAP_SIZE, KERNEL_PTE_FLAGS); pointer_cast_t cast; cast.val = KERNEL_HEAP_START; diff --git a/mem/page.c b/mem/page.c index 22b63ef8..aca89729 100644 --- a/mem/page.c +++ b/mem/page.c @@ -109,11 +109,11 @@ page_table_t *page_table_create(page_table_entry_t *entry) if (entry->value == 0) { uint64_t frame = alloc_frames(1); entry->value = frame | PTE_PRESENT | PTE_WRITEABLE | PTE_USER; - page_table_t *table = (page_table_t *)phys_to_virt(entry->value & PAGE_FLAGS_MASK); + page_table_t *table = (page_table_t *)phys_to_virt(entry->value & PAGE_4K_MASK); page_table_clear(table); return table; } - page_table_t *table = (page_table_t *)phys_to_virt(entry->value & PAGE_FLAGS_MASK); + page_table_t *table = (page_table_t *)phys_to_virt(entry->value & PAGE_4K_MASK); return table; } @@ -141,7 +141,7 @@ void copy_page_table_recursive(page_table_t *source_table, page_table_t *new_tab new_table->entries[i].value = 0; continue; } - page_table_t *source_next_level = (page_table_t *)phys_to_virt(source_table->entries[i].value & PAGE_FLAGS_MASK); + page_table_t *source_next_level = (page_table_t *)phys_to_virt(source_table->entries[i].value & PAGE_4K_MASK); page_table_t *new_next_level = page_table_create(&(new_table->entries[i])); new_table->entries[i].value = (uint64_t)new_next_level | (source_table->entries[i].value & 0xfff); copy_page_table_recursive(source_next_level, new_next_level, level - 1); @@ -155,7 +155,7 @@ void free_page_table_recursive(page_table_t *table, int level) uint64_t physical_address = (uint64_t)virt_to_phys(virtual_address); if (level == 0) { - free_frame(physical_address & PAGE_FLAGS_MASK); + free_frame(physical_address & PAGE_4K_MASK); return; } for (int i = 0; i < 512; i++) { @@ -163,13 +163,13 @@ void free_page_table_recursive(page_table_t *table, int level) if (entry->value == 0 || is_huge_page(entry)) continue; if (level == 1) { if (entry->value & PTE_PRESENT && entry->value & PTE_WRITEABLE && entry->value & PTE_USER) { - free_frame(entry->value & PAGE_FLAGS_MASK); + free_frame(entry->value & PAGE_4K_MASK); } } else { - free_page_table_recursive(phys_to_virt(entry->value & PAGE_FLAGS_MASK), level - 1); + free_page_table_recursive(phys_to_virt(entry->value & PAGE_4K_MASK), level - 1); } } - free_frame(physical_address & PAGE_FLAGS_MASK); + free_frame(physical_address & PAGE_4K_MASK); } /* Clone a page directory */ @@ -208,7 +208,7 @@ void page_map_to(page_directory_t *directory, uint64_t addr, uint64_t frame, uin page_table_t *l2_table = page_table_create(&(l3_table->entries[l3_index])); page_table_t *l1_table = page_table_create(&(l2_table->entries[l2_index])); - l1_table->entries[l1_index].value = (frame & PAGE_FLAGS_MASK) | flags; + l1_table->entries[l1_index].value = (frame & PAGE_4K_MASK) | flags; flush_tlb(addr); } @@ -223,7 +223,7 @@ void page_map_to_2M(page_directory_t *directory, uint64_t addr, uint64_t frame, page_table_t *l3_table = page_table_create(&l4_table->entries[l4_index]); page_table_t *l2_table = page_table_create(&l3_table->entries[l3_index]); - l2_table->entries[l2_index].value = (frame & HUGE_PAGE_2M_MASK) | flags | PTE_HUGE; + l2_table->entries[l2_index].value = (frame & PAGE_2M_MASK) | flags | PTE_HUGE; flush_tlb(addr); } @@ -237,7 +237,7 @@ void page_map_to_1G(page_directory_t *directory, uint64_t addr, uint64_t frame, page_table_t *l4_table = directory->table; page_table_t *l3_table = page_table_create(&l4_table->entries[l4_index]); - l3_table->entries[l3_index].value = (frame & HUGE_PAGE_1G_MASK) | flags | PTE_HUGE; + l3_table->entries[l3_index].value = (frame & PAGE_1G_MASK) | flags | PTE_HUGE; flush_tlb(addr); } @@ -268,7 +268,7 @@ void page_map_range_to_random_4K(page_directory_t *directory, uint64_t addr, uin if (length == 0) return; uint64_t frame = 0; - for (uint64_t i = 0; i < length; i += PAGE_SIZE) { + for (uint64_t i = 0; i < length; i += PAGE_4K_SIZE) { frame = alloc_frames(1); if (frame != 0) { page_map_to(directory, addr + i, frame, flags); } } @@ -280,14 +280,14 @@ void page_map_range_to_random_2M(page_directory_t *directory, uint64_t addr, uin if (length == 0) return; // Check align - uint64_t aligned_addr = ALIGN_DOWN(addr, HUGE_2M_SIZE); - uint64_t end_addr = ALIGN_UP(addr + length, HUGE_2M_SIZE); + uint64_t aligned_addr = ALIGN_DOWN(addr, PAGE_2M_SIZE); + uint64_t end_addr = ALIGN_UP(addr + length, PAGE_2M_SIZE); uint64_t aligned_length = end_addr - aligned_addr; - uint64_t blocks = aligned_length / HUGE_2M_SIZE; + uint64_t blocks = aligned_length / PAGE_2M_SIZE; for (uint64_t i = 0; i < blocks; i++) { - uint64_t block_addr = aligned_addr + i * HUGE_2M_SIZE; + uint64_t block_addr = aligned_addr + i * PAGE_2M_SIZE; // Try 2M uint64_t frame_2m = alloc_frames_2M(1); @@ -295,7 +295,7 @@ void page_map_range_to_random_2M(page_directory_t *directory, uint64_t addr, uin page_map_to_2M(directory, block_addr, frame_2m, flags); } else { // Fallback to 4K - page_map_range_to_random_4K(directory, block_addr, HUGE_2M_SIZE, flags); + page_map_range_to_random_4K(directory, block_addr, PAGE_2M_SIZE, flags); } } } @@ -306,14 +306,14 @@ void page_map_range_to_random_1G(page_directory_t *directory, uint64_t addr, uin if (length == 0) return; // Check align - uint64_t aligned_addr = ALIGN_DOWN(addr, HUGE_1G_SIZE); - uint64_t end_addr = ALIGN_UP(addr + length, HUGE_1G_SIZE); + uint64_t aligned_addr = ALIGN_DOWN(addr, PAGE_1G_SIZE); + uint64_t end_addr = ALIGN_UP(addr + length, PAGE_1G_SIZE); uint64_t aligned_length = end_addr - aligned_addr; - uint64_t blocks = aligned_length / HUGE_1G_SIZE; + uint64_t blocks = aligned_length / PAGE_1G_SIZE; for (uint64_t i = 0; i < blocks; i++) { - uint64_t block_addr = aligned_addr + i * HUGE_1G_SIZE; + uint64_t block_addr = aligned_addr + i * PAGE_1G_SIZE; // Try 1G uint64_t frame_1g = alloc_frames_1G(1); @@ -321,7 +321,7 @@ void page_map_range_to_random_1G(page_directory_t *directory, uint64_t addr, uin page_map_to_1G(directory, block_addr, frame_1g, flags); } else { // Fallback to 2M - page_map_range_to_random_2M(directory, block_addr, HUGE_1G_SIZE, flags); + page_map_range_to_random_2M(directory, block_addr, PAGE_1G_SIZE, flags); } } } @@ -330,8 +330,8 @@ void page_map_range_to_random_1G(page_directory_t *directory, uint64_t addr, uin static void map_unaligned_region(page_directory_t *directory, uint64_t start_addr, uint64_t end_addr, uint64_t flags) { // Try 2M pages for aligned sub-regions - const uint64_t aligned_2m_start = ALIGN_UP(start_addr, HUGE_2M_SIZE); - const uint64_t aligned_2m_end = ALIGN_DOWN(end_addr, HUGE_2M_SIZE); + const uint64_t aligned_2m_start = ALIGN_UP(start_addr, PAGE_2M_SIZE); + const uint64_t aligned_2m_end = ALIGN_DOWN(end_addr, PAGE_2M_SIZE); // Map aligned middle region with 2M pages if (aligned_2m_start < aligned_2m_end) { @@ -357,8 +357,8 @@ void page_map_range_to_random(page_directory_t *directory, uint64_t addr, uint64 const uint64_t end_addr = addr + length; // Try to map 1G-aligned regions with 1G pages - const uint64_t aligned_1g_start = ALIGN_UP(start_addr, HUGE_1G_SIZE); - const uint64_t aligned_1g_end = ALIGN_DOWN(end_addr, HUGE_1G_SIZE); + const uint64_t aligned_1g_start = ALIGN_UP(start_addr, PAGE_1G_SIZE); + const uint64_t aligned_1g_end = ALIGN_DOWN(end_addr, PAGE_1G_SIZE); if (aligned_1g_start < aligned_1g_end) { // We have a fully 1G-aligned region in the middle diff --git a/mem/page_walker.c b/mem/page_walker.c index e14fa878..64a450ed 100644 --- a/mem/page_walker.c +++ b/mem/page_walker.c @@ -40,23 +40,22 @@ void page_walk_init(page_walk_state_t *state, page_directory_t *directory, uintp /* Reset status */ state->is_valid = 0; state->is_huge = 0; + state->page_size = 0; state->physical_addr = 0; } /* Fast page table lookup helper */ static inline uint8_t page_table_lookup(page_table_t *table, uint16_t index, page_table_t **next_table, uint64_t *entry_value) { - if (next_table && *next_table && entry_value) { - *entry_value = (uintptr_t)virt_to_phys((uintptr_t)*next_table); - return 1; - } - if (!table || index >= 512) return 0; + uint64_t entry = table->entries[index].value; if (!(entry & PTE_PRESENT)) return 0; + if (entry_value) *entry_value = entry; - if (next_table && !is_huge_page(&table->entries[index])) *next_table = (page_table_t *)phys_to_virt(entry & 0x000fffffffff000); + + if (next_table && !is_huge_page(&table->entries[index])) { *next_table = (page_table_t *)phys_to_virt(entry & PAGE_4K_MASK); } return 1; } @@ -84,9 +83,10 @@ uint8_t page_walk_execute(page_walk_state_t *state) } if (is_huge_page(&state->l3_table->entries[state->l3_index])) { - state->physical_addr = (l3_entry & HUGE_PAGE_1G_MASK) | (state->virtual_addr & ((1 << 30) - 1)); + state->physical_addr = (l3_entry & PAGE_1G_MASK) | (state->virtual_addr & (PAGE_1G_SIZE - 1)); state->is_valid = 1; state->is_huge = 1; + state->page_size = 2; /* 1GB page */ return 1; } @@ -98,9 +98,10 @@ uint8_t page_walk_execute(page_walk_state_t *state) } if (is_huge_page(&state->l2_table->entries[state->l2_index])) { - state->physical_addr = (l2_entry & HUGE_PAGE_2M_MASK) | (state->virtual_addr & ((1 << 21) - 1)); + state->physical_addr = (l2_entry & PAGE_2M_MASK) | (state->virtual_addr & (PAGE_2M_SIZE - 1)); state->is_valid = 1; state->is_huge = 1; + state->page_size = 1; /* 2MB page */ return 1; } @@ -111,9 +112,10 @@ uint8_t page_walk_execute(page_walk_state_t *state) return 0; } - state->physical_addr = (l1_entry & 0x000fffffffff000) | state->offset; + state->physical_addr = (l1_entry & PAGE_4K_MASK) | state->offset; state->is_valid = 1; state->is_huge = 0; + state->page_size = 0; /* 4KB page */ return 1; } @@ -159,71 +161,91 @@ void update_walk_state_for_next_page(page_walk_state_t *state, uintptr_t next_vi } } -/* Check range free with state */ -size_t check_range_free_with_state(page_walk_state_t *state, uintptr_t start, size_t length) +/* Check range free with state - supports multiple page sizes */ +size_t check_range_free_with_state(page_walk_state_t *state, uintptr_t start, size_t length, size_t desired_size) { if (!state || length == 0) return 0; size_t free_bytes = 0; - uintptr_t current = ALIGN_UP(start, PAGE_SIZE); + uintptr_t current = start; - /* Reinitialize state for start address */ + /* Initialize state for start address */ page_walk_init(state, state->directory, current); while (free_bytes < length) { - if (page_walk_execute(state)) break; // Page is mapped - free_bytes += PAGE_SIZE; - current += PAGE_SIZE; + if (page_walk_execute(state)) { + /* Page is mapped - get its size and skip accordingly */ + size_t page_size = get_page_size_from_state(state); + current = align_up_to_page(current + 1, page_size); + free_bytes = 0; /* Reset free bytes count - not contiguous */ + + /* Reinitialize state for new address */ + page_walk_init(state, state->directory, current); + continue; + } + + /* Page is free - determine how much we can advance */ + size_t current_free = PAGE_4K_SIZE; /* At least 4K is free */ + + /* Check if we can use larger pages */ + if (desired_size >= PAGE_2M_SIZE && state->is_huge && state->page_size == 1) { + /* Check if we have enough space for 2MB page */ + if (length - free_bytes >= PAGE_2M_SIZE) { current_free = PAGE_2M_SIZE; } + } else if (desired_size >= PAGE_1G_SIZE && state->is_huge && state->page_size == 2) { + /* Check if we have enough space for 1GB page */ + if (length - free_bytes >= PAGE_1G_SIZE) { current_free = PAGE_1G_SIZE; } + } + + free_bytes += current_free; + current += current_free; - /* Efficiently update state for next page */ + /* Update state for next check */ update_walk_state_for_next_page(state, current); } + return free_bytes; } -/* Fast range free checker with large page */ -size_t check_range_free_fast(page_directory_t *directory, uintptr_t start, size_t length) +/* Find a free virtual memory range of specified length with preferred page size */ +uintptr_t walk_page_tables_find_free(page_directory_t *directory, uintptr_t start, size_t length, size_t preferred_size) { if (!directory || length == 0) return 0; - page_walk_state_t state; - uintptr_t current = ALIGN_UP(start, 1 << 21); // 2MB alignment - size_t checked = 0; - - page_walk_init(&state, directory, current); - while (checked < length) { - update_walk_state_for_next_page(&state, current); - if (page_walk_execute(&state)) break; // Page is mapped - checked += (1 << 21); // Check 2MB at a time - current += (1 << 21); - } - return checked > length ? length : checked; -} - -/* Find a free virtual memory range of specified length */ -uintptr_t walk_page_tables_find_free(page_directory_t *directory, uintptr_t start, size_t length) -{ - if (!directory || length == 0) return 0; + /* Validate preferred page size */ + if (preferred_size != PAGE_4K_SIZE && preferred_size != PAGE_2M_SIZE && preferred_size != PAGE_1G_SIZE) { preferred_size = PAGE_4K_SIZE; } - uintptr_t candidate = ALIGN_UP(start, PAGE_SIZE); + uintptr_t candidate = align_up_to_page(start, preferred_size); page_walk_state_t state; - /* Align length to page boundary */ - size_t aligned_length = ALIGN_UP(length, PAGE_SIZE); + /* Ensure length is aligned to preferred page size */ + size_t aligned_length = align_up_to_page(length, preferred_size); while (1) { + /* Check if candidate is properly aligned */ + if (!is_page_aligned(candidate, preferred_size)) { + candidate = align_up_to_page(candidate, preferred_size); + continue; + } + /* Initialize walk state */ page_walk_init(&state, directory, candidate); /* Check candidate region */ - size_t free_length = check_range_free_with_state(&state, candidate, aligned_length); + size_t free_length = check_range_free_with_state(&state, candidate, aligned_length, preferred_size); - if (free_length >= aligned_length) return candidate; + if (free_length >= aligned_length) { return candidate; } - /* Jump to next candidate (aligned to next potential boundary) */ - candidate += ALIGN_UP(free_length + PAGE_SIZE, PAGE_SIZE); + /* Move to next potential candidate */ + if (free_length > 0) { + candidate += free_length; + } else { + /* No free space at all, move to next aligned address */ + candidate += preferred_size; + } - /* Prevent infinite loop with sanity check */ - if (candidate < start) return 0; // Overflow detection + /* Overflow detection */ + if (candidate < start) { return 0; } } -} + + return 0; /* No suitable range found */ +} \ No newline at end of file