First commit, Vystem v0.1

This commit is contained in:
2026-03-31 22:15:00 +02:00
commit e15daed8c0
462 changed files with 134655 additions and 0 deletions

View File

@@ -0,0 +1,26 @@
// SPDX-License-Identifier: MPL-2.0
#ifndef SH_LIB_ASM_H
#define SH_LIB_ASM_H
#include "std/type.h"
#include "std/status.h"
// inb instruction wrapper
static inline sh_uint8 sh_asm_inb(sh_uint16 port) {
sh_uint8 val;
__asm__ volatile ("inb %1, %0":"=a"(val):"Nd"(port));
return val;
}
// outb instruction wrapper
static inline void sh_asm_outb(sh_uint16 port,sh_uint8 val) {
__asm__ volatile ("outb %0, %1"::"a"(val),"Nd"(port));
}
// rdtsc instruction wrapper
static inline sh_uint64 sh_asm_rdtsc() {
sh_uint32 lo,hi;
__asm__ volatile ("rdtsc":"=a"(lo),"=d"(hi));
return ((sh_uint64)hi<<32)|lo;
}
// invlpg instruction wrapper
static inline void sh_asm_invlpg(void *addr) {
__asm__ volatile ("invlpg (%0)"::"r"(addr):"memory");
}
#endif

View File

@@ -0,0 +1,11 @@
// SPDX-License-Identifier: MPL-2.0
#ifndef SH_LIB_SERIAL_H
#define SH_LIB_SERIAL_H
#include "std/type.h"
#include "std/status.h"
#define SH_SERIAL_PORT_COM1 0x3F8
// Load serial port setting
void sh_serial_load_serial_port_setting(sh_bool is_disabled);
// Send safely (wait for (SH_SERIAL_PORT_COM1+5) & 0x20 to be at 1) a byte
void sh_serial_send_byte(sh_uint8 b);
#endif

View File

@@ -0,0 +1,18 @@
// SPDX-License-Identifier: MPL-2.0
#ifndef SH_LIB_TSC_H
#define SH_LIB_TSC_H
#include "std/type.h"
#include "std/status.h"
#include "cpu/asm.h"
typedef sh_uint64 sh_tsc_TSC_VALUE;
// Reas TSC register.
static inline sh_tsc_TSC_VALUE sh_tsc_read_tsc() {
return sh_asm_rdtsc();
}
// Init kernel start tsc. Intended for single use only.
SH_STATUS sh_tsc_init_tsc();
// Return kernel start tsc.
sh_tsc_TSC_VALUE sh_tsc_get_kernel_init_tsc();
// Return kernel current tsc.
sh_tsc_TSC_VALUE sh_tsc_get_kernel_current_tsc();
#endif

View File

@@ -0,0 +1,25 @@
// SPDX-License-Identifier: MPL-2.0
#ifndef SH_LIB_CONF_H
#define SH_LIB_CONF_H
#include "std/type.h"
#include "std/status.h"
#include "memory/page.h"
#include "memory/vmem_layout.h"
#define SH_CONF_BOOT_CONFIG_VA SH_VMEM_LAYOUT_BOOT_CONFIG_VA
// Boot config structure.
typedef struct __attribute__((aligned(8))) {
sh_uint8 sig_start[8];
sh_uint8 log_level;
sh_uint16 page_table_allocator_level;
sh_page_PHYSICAL_ADDRESS page_table_pool_pa;
sh_page_VIRTUAL_ADDRESS page_table_pool_va;
sh_bool test_benchmark;
sh_uint64 bench_iterations;
sh_bool log_disable_serial_port;
sh_bool disable_serial_port;
sh_uint16 log_ring_size;
sh_uint8 sig_end[8];
} sh_conf_BOOT_CONFIG;
// Check and create boot config structure.
SH_STATUS sh_conf_get_boot_config(sh_conf_BOOT_CONFIG **config);
#endif

View File

@@ -0,0 +1,146 @@
// SPDX-License-Identifier: MPL-2.0
#ifndef SH_LIB_LOG_H
#define SH_LIB_LOG_H
#include "std/type.h"
#include "std/status.h"
#include "cpu/tsc.h"
typedef sh_uint8 sh_log_OUTPUT_TYPE;
#define SH_LOG_DEBUG ((sh_log_OUTPUT_TYPE)0)
#define SH_LOG_LOG ((sh_log_OUTPUT_TYPE)1)
#define SH_LOG_WARNING ((sh_log_OUTPUT_TYPE)2)
#define SH_LOG_ERROR ((sh_log_OUTPUT_TYPE)3)
#define SH_LOG_CRITICAL ((sh_log_OUTPUT_TYPE)4)
#define SH_LOG_FATAL ((sh_log_OUTPUT_TYPE)5)
#define SH_LOG_TEST ((sh_log_OUTPUT_TYPE)6)
typedef sh_uint16 sh_log_OUTPUT_SOURCE;
#define SH_LOG_SOURCE_MAIN ((sh_log_OUTPUT_SOURCE)0)
#define SH_LOG_SOURCE_CONF ((sh_log_OUTPUT_SOURCE)1)
#define SH_LOG_SOURCE_PAGE ((sh_log_OUTPUT_SOURCE)2)
#define SH_LOG_SOURCE_SLAB ((sh_log_OUTPUT_SOURCE)3)
#define SH_LOG_SOURCE_TEST ((sh_log_OUTPUT_SOURCE)4)
#define SH_LOG_SOURCE_PEZ ((sh_log_OUTPUT_SOURCE)5)
#define SH_LOG_SOURCE_PBA ((sh_log_OUTPUT_SOURCE)6)
#define SH_LOG_SOURCE_HEAP ((sh_log_OUTPUT_SOURCE)7)
#define SH_LOG_SOURCE_STD ((sh_log_OUTPUT_SOURCE)8)
typedef struct {
sh_log_OUTPUT_TYPE output_type;
sh_log_OUTPUT_SOURCE output_source;
sh_tsc_TSC_VALUE tsc_value;
const char* message_pointer;
} sh_log_OUTPUT_PAYLOAD;
// Return SH_TRUE if provided output type is valid.
static inline sh_bool sh_log_output_type_valid(sh_log_OUTPUT_TYPE t) {
return t<=SH_LOG_TEST;
}
// Return SH_TRUE if provided source type is valid.
static inline sh_bool sh_log_output_source_valid(sh_log_OUTPUT_SOURCE s) {
return s<=SH_LOG_SOURCE_STD;
}
// Load serial logging setting
void sh_log_load_serial_setting(sh_bool is_disabled);
// Return current serial logging setting
sh_bool sh_log_get_serial_setting();
// Load logging ring size in pages
void sh_log_load_logging_ring_size(sh_uint16 pages_count);
// Return logging ring size in bytes
sh_uint32 sh_log_get_logging_ring_size();
// Return total bytes written to the ring buffer
sh_uint64 sh_log_get_total_bytes_written();
// Log a byte
void sh_log_byte(sh_uint8 byte);
// Log a string
SH_STATUS sh_log_string(const char* str);
// Log an sh_int8 encoded in decimal
SH_STATUS sh_log_int8(sh_int8 n);
// Log an sh_int16 encoded in decimal
SH_STATUS sh_log_int16(sh_int16 n);
// Log an sh_int32 encoded in decimal
SH_STATUS sh_log_int32(sh_int32 n);
// Log an sh_int64 encoded in decimal
SH_STATUS sh_log_int64(sh_int64 n);
// Log an sh_uint8 encoded in decimal
SH_STATUS sh_log_uint8(sh_uint8 n);
// Log an sh_uint16 encoded in decimal
SH_STATUS sh_log_uint16(sh_uint16 n);
// Log an sh_uint32 encoded in decimal
SH_STATUS sh_log_uint32(sh_uint32 n);
// Log an sh_uint64 encoded in decimal
SH_STATUS sh_log_uint64(sh_uint64 n);
// Log an sh_uint8 encoded in hexadecimal
SH_STATUS sh_log_uint8_hex(sh_uint8 n);
// Log an sh_uint16 encoded in hexadecimal
SH_STATUS sh_log_uint16_hex(sh_uint16 n);
// Log an sh_uint32 encoded in hexadecimal
SH_STATUS sh_log_uint32_hex(sh_uint32 n);
// Log an sh_uint64 encoded in hexadecimal
SH_STATUS sh_log_uint64_hex(sh_uint64 n);
// Log an sh_uint64 encoded in hexadecimal without trimming useless zeros
SH_STATUS sh_log_uint64_hex_fixed(sh_uint64 n);
// Log a double encoded in decimal
SH_STATUS sh_log_double(double value);
// Format a string using the following format string
SH_STATUS sh_log_format(const char* format,va_list args);
// All logs functions starting below take into account log_level.
// Send an output payload to logging system.
SH_STATUS sh_log_payload(sh_log_OUTPUT_PAYLOAD *payload);
// Send an output payload to logging system, format it before sending it.
SH_STATUS sh_log_payload_format(sh_log_OUTPUT_PAYLOAD *payload,va_list args);
// Change log level. Intended for single use only.
SH_STATUS sh_log_load_log_level(sh_uint8 log_level);
// Return log level.
sh_uint8 sh_log_get_log_level();
// Print a string to test channel.
SH_STATUS sh_log_test(const char* str);
// Print a string to debug channel, from provided source.
SH_STATUS sh_log_debug(const char* str,sh_log_OUTPUT_SOURCE source);
// Print a string to log channel, from provided source.
SH_STATUS sh_log_log(const char* str,sh_log_OUTPUT_SOURCE source);
// Print a string to warning channel, from provided source.
SH_STATUS sh_log_warning(const char* str,sh_log_OUTPUT_SOURCE source);
// Print a string to error channel, from provided source.
SH_STATUS sh_log_error(const char* str,sh_log_OUTPUT_SOURCE source);
// Print a string to critical channel, from provided source.
SH_STATUS sh_log_critical(const char* str,sh_log_OUTPUT_SOURCE source);
// Print a string to fatal channel, from provided source.
SH_STATUS sh_log_fatal(const char* str,sh_log_OUTPUT_SOURCE source);
// Print a string to test channel. Doesn't include the new line caracter.
SH_STATUS sh_log_ltest(const char* str);
// Print a string to debug channel, from provided source. Doesn't include the new line caracter.
SH_STATUS sh_log_ldebug(const char* str,sh_log_OUTPUT_SOURCE source);
// Print a string to log channel, from provided source. Doesn't include the new line caracter.
SH_STATUS sh_log_llog(const char* str,sh_log_OUTPUT_SOURCE source);
// Print a string to warning channel, from provided source. Doesn't include the new line caracter.
SH_STATUS sh_log_lwarning(const char* str,sh_log_OUTPUT_SOURCE source);
// Print a string to error channel, from provided source. Doesn't include the new line caracter.
SH_STATUS sh_log_lerror(const char* str,sh_log_OUTPUT_SOURCE source);
// Print a string to critical channel, from provided source. Doesn't include the new line caracter.
SH_STATUS sh_log_lcritical(const char* str,sh_log_OUTPUT_SOURCE source);
// Print a string to fatal channel, from provided source. Doesn't include the new line caracter.
SH_STATUS sh_log_lfatal(const char* str,sh_log_OUTPUT_SOURCE source);
// The following functions format the output before logging it. The syntax is as follow:
// - %s : char*
// - %d : double
// - %x : sh_uint64 outputed in hexadecimal without trimming useless zeros
// - %c : char
// - %% : just insert a %
// The syntax for formating integers is as follow : %[1|2|4|8][u|s|U] :
// - the number indicate the size in bytes of the integer
// - the letter indicate the formatting mode : u for unsigned, s for signed, U for hexadecimal unsigned
// Somes examples for integers : %1s (8 bits signed integer), %4u (32 bits unsigned integers), %8U (64 bits hexadecimal unsigned)
// Print a string to test channel. Format it before hand
SH_STATUS sh_log_ftest(const char* format,...);
// Print a string to debug channel, from provided source. Format it before hand
SH_STATUS sh_log_fdebug(const sh_log_OUTPUT_SOURCE source,const char* format,...);
// Print a string to log channel, from provided source. Format it before hand
SH_STATUS sh_log_flog(const sh_log_OUTPUT_SOURCE source,const char* format,...);
// Print a string to warning channel, from provided source. Format it before hand
SH_STATUS sh_log_fwarning(const sh_log_OUTPUT_SOURCE source,const char* format,...);
// Print a string to error channel, from provided source. Format it before hand
SH_STATUS sh_log_ferror(const sh_log_OUTPUT_SOURCE source,const char* format,...);
// Print a string to critical channel, from provided source. Format it before hand
SH_STATUS sh_log_fcritical(const sh_log_OUTPUT_SOURCE source,const char* format,...);
// Print a string to fatal channel, from provided source. Format it before hand
SH_STATUS sh_log_ffatal(const sh_log_OUTPUT_SOURCE source,const char* format,...);
// Print every information about memory statictics. Require log level to be 1 or 0
SH_STATUS sh_log_mem_stats(sh_log_OUTPUT_SOURCE source);
#endif

View File

@@ -0,0 +1,7 @@
// SPDX-License-Identifier: MPL-2.0
// This file serve the purpose of including all types of tests
#include "kernel/tests/test_slabs.h"
#include "kernel/tests/test_radix.h"
#include "kernel/tests/test_pez.h"
#include "kernel/tests/test_malloc.h"
#include "kernel/tests/test_utils.h"

View File

@@ -0,0 +1,9 @@
// SPDX-License-Identifier: MPL-2.0
#ifndef SH_LIB_TEST_MALLOC_H
#define SH_LIB_TEST_MALLOC_H
#include "std/type.h"
#include "std/status.h"
#include "cpu/tsc.h"
// Test and benchmark malloc subsystem
SH_STATUS sh_test_malloc_benchmark();
#endif

View File

@@ -0,0 +1,11 @@
// SPDX-License-Identifier: MPL-2.0
#ifndef SH_LIB_TEST_PEZ_H
#define SH_LIB_TEST_PEZ_H
#include "std/type.h"
#include "std/status.h"
#include "memory/pez/pez.h"
#include "cpu/tsc.h"
#define SH_TEST_PEZ_TOTAL_TSC_TIME_COUNT 4000
// Test and benchmark pez subsystem
SH_STATUS sh_test_pez_benchmark_physical(sh_pez_PHYSICAL_PLANE *phys_plane);
#endif

View File

@@ -0,0 +1,14 @@
// SPDX-License-Identifier: MPL-2.0
#ifndef SH_LIB_TEST_RADIX_H
#define SH_LIB_TEST_RADIX_H
#include "std/type.h"
#include "std/status.h"
#include "memory/page.h"
#include "memory/slab.h"
#include "memory/pez/radix.h"
#include "cpu/tsc.h"
// Load the number of iterations for benchmakrs for radix test.
void sh_test_radix_load_iterations_count(sh_uint64 iterations_num);
// Test and benchmark radix trees subsystem
SH_STATUS sh_test_radix_benchmark(struct sh_slab_radix_node_SLAB_ALLOCATOR *alloc,sh_page_PAGE_TABLE_POOL *ptp);
#endif

View File

@@ -0,0 +1,19 @@
// SPDX-License-Identifier: MPL-2.0
#ifndef SH_LIB_TEST_SLABS_H
#define SH_LIB_TEST_SLABS_H
#include "std/type.h"
#include "std/status.h"
#include "memory/page.h"
#include "memory/slab.h"
#include "cpu/tsc.h"
// Load the number of iterations for benchmakrs for slabs test.
void sh_test_slabs_load_iterations_count(sh_uint64 iterations_num);
// Test and benchmark physical region objects slab allocator
SH_STATUS sh_test_slabs_benchmark_region_physical(sh_slab_reg_phys_SLAB_ALLOCATOR *alloc,sh_page_PAGE_TABLE_POOL *ptp);
// Test and benchmark virtual region objects slab allocator
SH_STATUS sh_test_slabs_benchmark_region_virtual(sh_slab_reg_virt_SLAB_ALLOCATOR *alloc,sh_page_PAGE_TABLE_POOL *ptp);
// Test and benchmark radix nodes objects slab allocator
SH_STATUS sh_test_slabs_benchmark_radix_node(struct sh_slab_radix_node_SLAB_ALLOCATOR *alloc,sh_page_PAGE_TABLE_POOL *ptp);
// Test and benchmark all slab allocators
SH_STATUS sh_test_slabs_benchmark(sh_slab_reg_phys_SLAB_ALLOCATOR *alloc_reg_phys,sh_slab_reg_virt_SLAB_ALLOCATOR *alloc_reg_virt,struct sh_slab_radix_node_SLAB_ALLOCATOR *alloc_radix_node,sh_page_PAGE_TABLE_POOL *ptp);
#endif

View File

@@ -0,0 +1,13 @@
// SPDX-License-Identifier: MPL-2.0
#ifndef SH_LIB_TEST_UTILS_H
#define SH_LIB_TEST_UTILS_H
#include "std/type.h"
#include "std/status.h"
#include "cpu/tsc.h"
// Compute and print time stats based on provided list of TSC values.
SH_STATUS sh_test_compute_print_stats(char* benchname,sh_tsc_TSC_VALUE *tsc_value_array,sh_uint64 array_size);
// Return pointer to TSC values buffer
sh_tsc_TSC_VALUE* sh_test_get_tsc_values_buffer_ptr();
// Load the number of iterations for benchmarks.
void sh_test_load_iterations_count(sh_uint64 iterations_num);
#endif

View File

@@ -0,0 +1,34 @@
// SPDX-License-Identifier: MPL-2.0
#ifndef SH_LIB_HEAP_H
#define SH_LIB_HEAP_H
#include "memory/page.h"
#include "memory/pba.h"
#include "memory/pez/pez.h"
#include "memory/pez/radix.h"
#include "memory/slabs/slab_generic.h"
#include "std/status.h"
#include "std/type.h"
// Heap structure
typedef struct {
sh_pez_PHYSICAL_PLANE *phys_plane;
sh_pez_VIRTUAL_PLANE *virt_plane;
sh_page_PAGE_TABLE_POOL *kernel_ptp;
struct sh_slab_generic_SLAB_ALLOCATOR slabs_allocator[8];
sh_pba_PAGE_BLOCK_ALLOCATOR pba[8];
sh_radix_TREE alloc_size_tree;
} sh_heap_KERNEL_HEAP;
// Return default kernel heap
sh_heap_KERNEL_HEAP *sh_heap_get_default_heap();
// Load default kernel heap
void sh_heap_load_default_heap(sh_heap_KERNEL_HEAP *heap);
// Initialize heap structure, calling entity need to input manually all slabs allocator.
SH_STATUS sh_heap_init_heap(sh_pez_PHYSICAL_PLANE *phys_plane,sh_pez_VIRTUAL_PLANE *virt_plane,sh_page_PAGE_TABLE_POOL *kernel_ptp,sh_heap_KERNEL_HEAP *kernel_heap);
// Allocate a certain amount of pages from Pez physical backend
SH_STATUS sh_heap_allocate_pages(sh_uint32 pages_count,sh_page_VIRTUAL_ADDRESS *address);
// Free a allocated region of pages from the heap
SH_STATUS sh_heap_free_pages(sh_page_VIRTUAL_ADDRESS va);
// Allocate a certain object based on his size
SH_STATUS sh_heap_allocate_object(sh_uint32 size_bytes,sh_page_VIRTUAL_ADDRESS *address);
// Free a certain object based on his size
SH_STATUS sh_heap_free_object(sh_page_VIRTUAL_ADDRESS va);
#endif

View File

@@ -0,0 +1,159 @@
// SPDX-License-Identifier: MPL-2.0
#ifndef SH_LIB_PAGE_H
#define SH_LIB_PAGE_H
#include "std/type.h"
#include "std/status.h"
#include "memory/vmem_layout.h"
#define SH_PAGE_KERNEL_PERM_VA_BASE SH_VMEM_LAYOUT_KERNEL_ALLOC_SPACE_VA
#define SH_PAGE_KERNEL_PERM_VA_END SH_VMEM_LAYOUT_KERNEL_ALLOC_SPACE_VA_END
#define SH_PAGE_MEMORY_MAP_VA SH_VMEM_LAYOUT_MEMORY_MAP_VA
#define SH_PAGE_SIZE 4096
#define SH_PAGE_MAX_MEM_COUNT 16ULL*1024*1024*1024*1024
#define SH_PAGE_MAX_PAGES_COUNT (SH_PAGE_MAX_MEM_COUNT/SH_PAGE_SIZE)
#define SH_PAGE_PTP_ALLOCATOR_PAGES_COUNT 4096
#define SH_PAGE_PTP_ALLOCATOR_BITMAP_UINT64 SH_PAGE_PTP_ALLOCATOR_PAGES_COUNT/64
typedef sh_uint32 sh_page_MEMORY_TYPE;
#define SH_PAGE_RESERVED_MEMORY_TYPE (sh_page_MEMORY_TYPE)0
#define SH_PAGE_LOADER_CODE (sh_page_MEMORY_TYPE)1
#define SH_PAGE_LOADER_DATA (sh_page_MEMORY_TYPE)2
#define SH_PAGE_BOOT_SERVICES_CODE (sh_page_MEMORY_TYPE)3
#define SH_PAGE_BOOT_SERVICES_DATA (sh_page_MEMORY_TYPE)4
#define SH_PAGE_RUNTIME_SERVICES_CODE (sh_page_MEMORY_TYPE)5
#define SH_PAGE_RUNTIME_SERVICES_DATA (sh_page_MEMORY_TYPE)6
#define SH_PAGE_CONVENTIONAL_MEMORY (sh_page_MEMORY_TYPE)7
#define SH_PAGE_UNUSABLE_MEMORY (sh_page_MEMORY_TYPE)8
#define SH_PAGE_ACPI_RECLAIM_MEMORY (sh_page_MEMORY_TYPE)9
#define SH_PAGE_ACPI_MEMORY_NVS (sh_page_MEMORY_TYPE)10
#define SH_PAGE_MEMORY_MAPPED_IO (sh_page_MEMORY_TYPE)11
#define SH_PAGE_MEMORY_MAPPED_IO_PORT_SPACE (sh_page_MEMORY_TYPE)12
#define SH_PAGE_PAL_CODE (sh_page_MEMORY_TYPE)13
#define SH_PAGE_PERSISTENT_MEMORY (sh_page_MEMORY_TYPE)14
#define SH_PAGE_RESERVED (sh_page_MEMORY_TYPE)15
typedef sh_uint64 sh_page_PHYSICAL_ADDRESS;
typedef sh_uint64 sh_page_VIRTUAL_ADDRESS;
#define SH_PAGE_NULL_PA (sh_page_PHYSICAL_ADDRESS)0
#define SH_PAGE_NULL_VA (sh_page_VIRTUAL_ADDRESS)0
#define SH_PAGE_PRESENT (1ULL<<0)
#define SH_PAGE_TABLE_FLAGS (1ULL<<1)
#define SH_PAGE_RW (1ULL<<1)
#define SH_PAGE_US (1ULL<<2)
#define SH_PAGE_PWT (1ULL<<3)
#define SH_PAGE_PCD (1ULL<<4)
#define SH_PAGE_ACCESSED (1ULL<<5)
#define SH_PAGE_DIRTY (1ULL<<6)
#define SH_PAGE_PS (1ULL<<7)
#define SH_PAGE_GLOBAL (1ULL<<8)
#define SH_PAGE_NX (1ULL<<63)
// Memory map entry structure.
#pragma pack(1)
typedef struct {
sh_uint32 type;
sh_uint64 physical_start;
sh_uint64 pages_count;
sh_uint64 attributes;
} sh_page_MEMORY_MAP_ENTRY;
#pragma pack()
// Memory map header structure.
#pragma pack(1)
typedef struct {
sh_uint8 sig_start[8];
sh_uint64 entry_count;
sh_uint64 entry_size;
sh_uint8 mmap_syntax_version;
} sh_page_MEMORY_MAP_HEADER;
#pragma pack()
// Page table pool structure.
#pragma pack(1)
typedef struct {
sh_page_PHYSICAL_ADDRESS page_table_pa;
sh_page_VIRTUAL_ADDRESS page_table_va;
sh_uint64 ptp_alloc_bitmap[SH_PAGE_PTP_ALLOCATOR_BITMAP_UINT64];
sh_uint64 ptp_pages_count;
sh_uint64 ptp_alloc_bitmap_uint64_count;
} sh_page_PAGE_TABLE_POOL;
#pragma pack()
// Memory statistics structure
typedef struct {
sh_uint64 memory_total_pages; // memory_total is the size of the addressable physical space
sh_uint64 memory_total_bytes;
sh_uint64 memory_installed_pages; // memory_installed is the sum of the size of all free regions at kernel boot
sh_uint64 memory_installed_bytes;
sh_uint64 free_pages;
sh_uint64 used_pages;
double free_ratio;
double used_ratio;
sh_uint64 largest_free_block;
sh_uint64 largest_used_block;
sh_uint64 free_blocks_count;
sh_uint64 used_blocks_count;
sh_uint64 physical_bitmap_size_pages;
sh_uint64 physical_bitmap_size_bytes;
} sh_page_MEM_STATS;
// Load boot PTP VA. Intended for one usage only.
SH_STATUS sh_page_load_boot_ptp_va(sh_page_VIRTUAL_ADDRESS pt_pool_va);
// Return boot PTP VA.
sh_page_VIRTUAL_ADDRESS sh_page_get_boot_ptp_va();
// Copy memory map provided bootloader into dedicated buffer. Intended for one usage only.
SH_STATUS sh_page_copy_memory_map();
// Check for memory map signatures and read memory map header.
SH_STATUS sh_page_check_memory_map();
// Return the amount of physical memory in pages
sh_uint64 sh_page_get_physical_memory_amount_pages();
// Return the amount of physical memory in bytes
sh_uint64 sh_page_get_physical_memory_amount_bytes();
// Return the first available physical page in physical bitmap.
sh_uint64 sh_page_get_one_page_na();
// Set pages ranges into provided bitmap.
SH_STATUS sh_page_set_pages_range_bitmap(sh_uint8 *bitmap,sh_uint64 page_count_in_bitmap,sh_uint64 page_index,sh_uint64 page_count,sh_bool state);
// Return the status of a page inside the provided bitmap.
static inline sh_bool sh_page_is_allocated(sh_uint8 *bitmap,sh_uint64 page_index) {
sh_uint64 byte_index=page_index/8;
sh_uint8 bit_index=page_index%8;
return (bitmap[byte_index] & (1u<<bit_index))!=0;
}
// Initialize PTP structure.
SH_STATUS sh_page_init_ptp(sh_page_PHYSICAL_ADDRESS ptp_pa,sh_page_VIRTUAL_ADDRESS ptp_va,sh_uint64 initial_fill_level,sh_page_PAGE_TABLE_POOL *page_table_pool);
// Dump provided PTP bitmap, intented for debug.
SH_STATUS sh_page_dump_ptp_bitmap(sh_page_PAGE_TABLE_POOL *ptp);
// Allocate one page from a PTP internal bitmap.
sh_page_PHYSICAL_ADDRESS sh_page_ptp_alloc_one_page(sh_page_PAGE_TABLE_POOL *pt_pool);
// Convert a PA provided by any layer of the PTP into a valid VA. Return 0 if PA isn't in expected range.
static inline sh_uint64 *sh_page_ptp_pa_to_va(sh_page_PAGE_TABLE_POOL *ptp,sh_uint64 pa) {
sh_uint64 base=ptp->page_table_pa;
sh_uint64 size=ptp->ptp_pages_count*4096;
if (pa<base || pa>=base+size) return 0;
return (sh_uint64 *)(ptp->page_table_va+(pa-base));
}
// Map one physical page to VA to provided PTP.
SH_STATUS sh_page_map_one_page_ptp(sh_page_PAGE_TABLE_POOL *ptp,sh_page_VIRTUAL_ADDRESS va,sh_page_PHYSICAL_ADDRESS pa,sh_uint64 flags);
// Return according SH_STATUS if provided VA is mapped inside provided PTP.
SH_STATUS sh_page_is_va_mapped_ptp(sh_page_PAGE_TABLE_POOL *ptp,sh_page_VIRTUAL_ADDRESS va);
// Return according SH_STATUS if provided VA is mapped inside provided PTP for all the range provided
SH_STATUS sh_page_is_va_range_mapped_ptp(sh_page_PAGE_TABLE_POOL *ptp,sh_page_VIRTUAL_ADDRESS va,sh_uint64 size_bytes);
// Search for an available amount of virtual memory inside provided range with the provided size
SH_STATUS sh_page_search_available_va_range(sh_page_PAGE_TABLE_POOL *ptp,sh_page_VIRTUAL_ADDRESS range_base,sh_page_VIRTUAL_ADDRESS range_size_bytes,sh_uint64 size_bytes,sh_page_VIRTUAL_ADDRESS *address_found);
// Map a range of pages from PA to VA. Both virtual and physic area has to be continuous. VAs availability is checked, not physical pages availability.
SH_STATUS sh_page_map_contiguous_pages_range_ptp(sh_page_PAGE_TABLE_POOL *ptp,sh_page_VIRTUAL_ADDRESS va,sh_page_PHYSICAL_ADDRESS pa,sh_uint64 flags,sh_uint64 size_bytes);
// Search for an available amount of pages inside physical bitmap
SH_STATUS sh_page_search_physical_contiguous_block_na(sh_uint64 pages_needed,sh_page_PHYSICAL_ADDRESS *pa);
// Allocate the corresponding amount of pages to size_bytes.
SH_STATUS sh_page_alloc_contiguous(sh_page_PAGE_TABLE_POOL *ptp,sh_uint64 size_bytes,sh_page_VIRTUAL_ADDRESS* va);
// Allocate the corresponding amount of pages to size_bytes. Provide support for custom flags and VA range search.
SH_STATUS sh_page_alloc_contiguous_extended(sh_page_PAGE_TABLE_POOL *ptp,sh_uint64 size_bytes,sh_page_VIRTUAL_ADDRESS* va,DEFAULT sh_uint64 flags,DEFAULT sh_page_VIRTUAL_ADDRESS va_range_start,DEFAULT sh_uint64 va_range_size_bytes);
// Unmap one page from a PTP, assume VA is mapped. Does not unallocate associed physical page
SH_STATUS sh_page_unmap_one_page_ptp(sh_page_PAGE_TABLE_POOL *ptp,sh_page_VIRTUAL_ADDRESS va);
// Map a range of pages to VA. Both virtual and physic area has to be continuous. VAs mapping is checked, not physical pages occupation.
SH_STATUS sh_page_unmap_contiguous_pages_range_ptp(sh_page_PAGE_TABLE_POOL *ptp,sh_page_VIRTUAL_ADDRESS va,sh_uint64 size_bytes);
// Convert a VA allocated in a PTP into his equivalent PA by searching inside the PTP
SH_STATUS sh_page_ptp_va_to_pa(sh_page_PAGE_TABLE_POOL *ptp,sh_page_VIRTUAL_ADDRESS va,sh_page_PHYSICAL_ADDRESS *pa);
// Unalloc one page from a VA. Check if VA is mapped or not. PA is calculted trough searching in PTP
SH_STATUS sh_page_unalloc_one_page(sh_page_PAGE_TABLE_POOL *ptp,sh_page_VIRTUAL_ADDRESS va);
// Unalloc a range of virtually contiguous pages. Check if the entire range is allocated before unallocating anything.
SH_STATUS sh_page_unalloc_contiguous(sh_page_PAGE_TABLE_POOL *ptp,sh_page_VIRTUAL_ADDRESS va,sh_uint64 size_bytes);
// Parse memory map, set all non usable pages into physical bitmap and compute available amount of physical memory. Intended for one usage only.
SH_STATUS sh_page_analyse_memory_map(sh_page_PAGE_TABLE_POOL *ptp);
// Return physical bitmap pointer
sh_page_VIRTUAL_ADDRESS sh_page_get_physical_bitmap_ptr();
// Get physical memory statistics
SH_STATUS sh_page_get_memory_stats(sh_page_MEM_STATS *mem_stats);
#endif

View File

@@ -0,0 +1,20 @@
// SPDX-License-Identifier: MPL-2.0
#ifndef SH_LIB_PBA_H
#define SH_LIB_PBA_H
#include "std/type.h"
#include "std/status.h"
#include "memory/page.h"
#include "memory/pez/pez.h"
// Page block allocator
typedef struct {
sh_page_VIRTUAL_ADDRESS start_va;
sh_uint64 total_pages;
sh_uint64 block_pages;
sh_uint64 block_count;
sh_uint64 max_blocks;
} sh_pba_PAGE_BLOCK_ALLOCATOR;
// Initialize a page block allocator
SH_STATUS sh_pba_init(sh_pba_PAGE_BLOCK_ALLOCATOR *pba,sh_page_VIRTUAL_ADDRESS start_va,sh_uint64 area_pages_amount,sh_uint64 block_pages);
// Allocate a block and return corresponding pointer
SH_STATUS sh_pba_alloc(sh_pba_PAGE_BLOCK_ALLOCATOR *pba,sh_page_PAGE_TABLE_POOL *ptp,sh_page_VIRTUAL_ADDRESS *ptr);
#endif

View File

@@ -0,0 +1,71 @@
// SPDX-License-Identifier: MPL-2.0
#ifndef SH_LIB_PEZ_H
#define SH_LIB_PEZ_H
#include "std/type.h"
#include "std/status.h"
#include "memory/slabs/slab_reg_phys.h"
#include "memory/slabs/slab_reg_virt.h"
#include "memory/pez/radix.h"
#define SH_PEZ_REGION_OBJECT_INDEX_SIZE_BYTES 3
// Physical region object
#pragma pack(1)
typedef struct {
sh_uint32 start_page_index;
sh_uint32 region_size_pages;
sh_uint8 next_region_index[3];
sh_uint8 flags;
} sh_pez_REGION_PHYSICAL_OBJECT;
#pragma pack()
// Virtual region object
#pragma pack(1)
typedef struct {
sh_uint32 start_page_index;
sh_uint32 region_size_pages;
sh_uint32 next_region_index;
} sh_pez_REGION_VIRTUAL_OBJECT;
#pragma pack()
// Physical plane structure
typedef struct {
sh_uint32 free_pages;
sh_uint32 used_pages;
sh_radix_TREE region_radix_tree;
sh_radix_TREE boundary_radix_tree;
sh_slab_reg_phys_SLAB_ALLOCATOR *slab_reg_phys;
struct sh_slab_radix_node_SLAB_ALLOCATOR *slab_radix_node;
sh_page_PAGE_TABLE_POOL *kernel_ptp;
sh_uint8 *physical_bitmap;
sh_uint64 physical_page_count;
} sh_pez_PHYSICAL_PLANE;
// Virtual plane structure
typedef struct {
sh_uint32 free_pages;
sh_uint32 used_pages;
sh_radix_TREE region_radix_tree;
sh_radix_TREE boundary_radix_tree;
sh_slab_reg_virt_SLAB_ALLOCATOR *slab_reg_virt;
struct sh_slab_radix_node_SLAB_ALLOCATOR *slab_radix_node;
sh_page_PAGE_TABLE_POOL *kernel_ptp;
sh_page_PAGE_TABLE_POOL *reference_ptp;
sh_page_VIRTUAL_ADDRESS plane_offset;
} sh_pez_VIRTUAL_PLANE;
// Set Pez state to true
void sh_pez_set_available();
// Return current state of Pez
sh_bool sh_pez_is_available();
// Return reference Pez physical plane
sh_pez_PHYSICAL_PLANE* sh_pez_get_reference_phys_plane();
// Initialize a physical plane
SH_STATUS sh_pez_init_physical_plane(sh_uint8 *physical_bitmap,sh_uint64 physical_page_count,sh_slab_reg_phys_SLAB_ALLOCATOR *slab_reg_phys,struct sh_slab_radix_node_SLAB_ALLOCATOR *slab_radix_node,sh_page_PAGE_TABLE_POOL *kernel_ptp,sh_pez_PHYSICAL_PLANE *phys_plane);
// Allocate physical pages from the physical plane
SH_STATUS sh_pez_alloc_physical_pages(sh_pez_PHYSICAL_PLANE *phys_plane,sh_uint32 pages_count,sh_page_PHYSICAL_ADDRESS *address);
// Free physical pages from the physical plane
SH_STATUS sh_pez_free_physical_pages(sh_pez_PHYSICAL_PLANE *phys_plane,sh_page_PHYSICAL_ADDRESS *address,sh_uint32 pages_count);
// Debug Pez Physical
SH_STATUS sh_pez_debug_physical(sh_pez_PHYSICAL_PLANE *phys_plane);
// Initialize a virtual plane
SH_STATUS sh_pez_init_virtual_plane(sh_page_VIRTUAL_ADDRESS plane_offset,sh_slab_reg_virt_SLAB_ALLOCATOR *slab_reg_virt,struct sh_slab_radix_node_SLAB_ALLOCATOR *slab_radix_node,sh_page_PAGE_TABLE_POOL *kernel_ptp,sh_page_PAGE_TABLE_POOL *reference_ptp,sh_pez_VIRTUAL_PLANE *virt_plane);
// Allocate virtual space from the virtual plane
SH_STATUS sh_pez_alloc_virtual_pages(sh_pez_VIRTUAL_PLANE *virt_plane,sh_uint32 pages_count,sh_page_VIRTUAL_ADDRESS *address);
// Free virtual space from the virtual plane
SH_STATUS sh_pez_free_virtual_pages(sh_pez_VIRTUAL_PLANE *virt_plane,sh_page_VIRTUAL_ADDRESS *address,sh_uint32 pages_count);
#endif

View File

@@ -0,0 +1,103 @@
// SPDX-License-Identifier: MPL-2.0
#ifndef SH_LIB_PEZ_DEBUG_H
#define SH_LIB_PEZ_DEBUG_H
#include "std/type.h"
#include "std/status.h"
#define SH_PEZ_DEBUG_ALLOC_HEADER 0
#define SH_PEZ_DEBUG_FREE_HEADER 1
#define SH_PEZ_DEBUG_SIZE_LIST_HEADER 2
#define SH_PEZ_DEBUG_BOUNDARY_RADIX_HEADER 3
#define SH_PEZ_DEBUG_BITMAP_REGIONS_HEADER 4
#define SH_PEZ_DEBUG_SIZE_LIST_BLOCK_HEADER 5
// Struct for Pez alloc
#pragma pack(1)
typedef struct {
sh_uint32 size_asked;
sh_uint32 found_region_start_index;
sh_uint32 found_region_size;
sh_bool is_exact_fit;
sh_uint32 remaining_size;
sh_uint32 new_start;
sh_uint32 reg_idx;
} sh_pez_debug_ALLOC;
#pragma pack()
// Struct for Pez free
#pragma pack(1)
typedef struct {
sh_uint32 region_start_freeed;
sh_uint32 size_freeed;
sh_uint32 left_region_idx;
sh_uint32 right_region_idx;
sh_uint32 left_region_size;
sh_uint32 right_region_size;
sh_uint32 left_region_start;
sh_uint32 right_region_start;
sh_uint32 final_inserted_region_idx;
sh_uint32 final_inserted_region_start;
sh_uint32 final_inserted_region_size;
sh_bool was_right_region_object_freeed;
sh_bool was_new_region_object_allocated;
sh_uint32 new_reg_obj_start;
sh_uint32 new_reg_obj_size;
} sh_pez_debug_FREE;
#pragma pack()
// Struct for Pez regions from size list
#pragma pack(1)
typedef struct {
sh_uint32 start;
sh_uint32 size;
sh_uint32 idx;
sh_uint32 next_idx;
} sh_pez_debug_REGION_SIZE_LIST;
#pragma pack()
// Struct for Pez size list
#pragma pack(1)
typedef struct {
sh_uint32 size;
sh_uint32 count;
sh_pez_debug_REGION_SIZE_LIST regions[512];
} sh_pez_debug_SIZE_LIST;
#pragma pack()
// Struct for Pez region from boundary
#pragma pack(1)
typedef struct {
sh_uint32 pos_start;
sh_uint32 idx_start;
sh_uint32 prev_start;
sh_uint32 pos_end;
sh_uint32 idx_end;
sh_uint32 prev_end;
} sh_pez_debug_REGION_BOUNDARY;
#pragma pack()
// Struct for Pez boundary radix
#pragma pack(1)
typedef struct {
sh_uint32 count;
sh_pez_debug_REGION_BOUNDARY regions[512];
} sh_pez_debug_BOUNDARY_RADIX;
#pragma pack()
// Struct for Pez regions from bitmap
#pragma pack(1)
typedef struct {
sh_uint32 start;
sh_uint32 size;
} sh_pez_debug_REGION_BITMAP;
#pragma pack()
// Struct for Pez bitmap
#pragma pack(1)
typedef struct {
sh_uint32 count;
sh_pez_debug_REGION_BITMAP regions[512];
} sh_pez_debug_BITMAP;
#pragma pack()
#endif
// Send an alloc payload
SH_STATUS sh_pez_debug_send_alloc(sh_pez_debug_ALLOC *alloc);
// Send a free payload
SH_STATUS sh_pez_debug_send_free(sh_pez_debug_FREE *free);
// Send a size list payload. Sending size list radix header must be done prior to any size list being send. It consist of SH_PEZ_DEBUG_SIZE_LIST_BLOCK_HEADER and the count of sizes list
SH_STATUS sh_pez_debug_send_size_list(sh_pez_debug_SIZE_LIST *size_list);
// Send a boundary radix payload
SH_STATUS sh_pez_debug_send_boundary_radix(sh_pez_debug_BOUNDARY_RADIX *boundary_radix);
// Send a bitmap payload
SH_STATUS sh_pez_debug_send_bitmap(sh_pez_debug_BITMAP *bitmap);

View File

@@ -0,0 +1,31 @@
// SPDX-License-Identifier: MPL-2.0
#ifndef SH_LIB_RADIX_H
#define SH_LIB_RADIX_H
#include "std/type.h"
#include "memory/page.h"
struct sh_slab_radix_node_SLAB_ALLOCATOR;
#define SH_RADIX_NODE_SIZE_BYTES 128
// Radix node structure
typedef struct {
sh_page_VIRTUAL_ADDRESS ptr[16];
} sh_radix_NODE;
// Radix tree structure
typedef struct {
sh_radix_NODE *root_node;
sh_uint8 depth;
} sh_radix_TREE;
// Return the value at the indicated index. Return SH_STATUS_NOT_FOUND if index indicate an empty ptr. Automatically fill the 16 higher bits in the returned value if index=0, no matter that provided node is a intermediary node or a leaf
SH_STATUS sh_radix_node_read_value(sh_radix_NODE *node,sh_uint8 index,sh_page_VIRTUAL_ADDRESS* value);
// Modify the value at the indicated index. Update the bitmap accordingly, all non-zero value corresponding to 1 in the bitmap, otherwise 0.
SH_STATUS sh_radix_node_set_value(struct sh_slab_radix_node_SLAB_ALLOCATOR *alloc,sh_radix_NODE *node,sh_uint8 index,sh_page_VIRTUAL_ADDRESS value);
// Initialize a radix tree. Fail if depth is greater than 16
SH_STATUS sh_radix_tree_init(struct sh_slab_radix_node_SLAB_ALLOCATOR *alloc,sh_page_PAGE_TABLE_POOL *ptp,sh_radix_TREE *tree,sh_uint8 depth);
// Search in a straight line for a key inside the tree. Stop and return SH_STATUS_NOT_FOUND as soon as it hit a empty ptr where there should be one
SH_STATUS sh_radix_tree_get_value(sh_radix_TREE *tree,sh_uint64 key,sh_page_VIRTUAL_ADDRESS *value);
// Insert a value inside the tree. Can allocate new nodes if necessary. Will overwrite previous value if there was one already inserted. Automatically update bitmap on his path
SH_STATUS sh_radix_tree_insert_value(struct sh_slab_radix_node_SLAB_ALLOCATOR *alloc,sh_page_PAGE_TABLE_POOL *ptp,sh_radix_TREE *tree,sh_uint64 key,sh_page_VIRTUAL_ADDRESS value);
// Delete a value and deallocates all nodes (including leaf) that form a path to it if this deletion make them empty
SH_STATUS sh_radix_tree_delete_value(struct sh_slab_radix_node_SLAB_ALLOCATOR *alloc,sh_radix_TREE *tree,sh_uint64 key);
// Return the value that has the smallest key equal or greater than the provided key. Can't allocate new nodes.
SH_STATUS sh_radix_tree_search_smallest_min_bound(struct sh_slab_radix_node_SLAB_ALLOCATOR *alloc,sh_radix_TREE *tree,sh_uint64 lower_bound_key,sh_page_VIRTUAL_ADDRESS *value);
#endif

View File

@@ -0,0 +1,18 @@
// SPDX-License-Identifier: MPL-2.0
#ifndef SH_LIB_RING_H
#define SH_LIB_RING_H
#include "std/type.h"
#include "std/status.h"
// Ring buffer header structure
typedef struct {
sh_uint32 head;
sh_uint32 tail;
sh_uint32 buffer_bytes_size;
sh_uint8* data_start;
sh_uint64 total_bytes_written;
} sh_ring_RING_BUFFER_HEADER;
// Write a byte into the provided ring buffer
SH_STATUS sh_ring_write_byte(sh_ring_RING_BUFFER_HEADER *ring_buffer,sh_uint8 byte);
// Write a null terminated string into the provided ring buffer
SH_STATUS sh_ring_write_string(sh_ring_RING_BUFFER_HEADER *ring_buffer,char *string);
#endif

View File

@@ -0,0 +1,6 @@
// SPDX-License-Identifier: MPL-2.0
// This file serve the purpose of including all types of slabs allocators
#include "memory/slabs/slab_reg_phys.h"
#include "memory/slabs/slab_reg_virt.h"
#include "memory/slabs/slab_radix_node.h"
#include "memory/slabs/slab_generic.h"

View File

@@ -0,0 +1,60 @@
// SPDX-License-Identifier: MPL-2.0
// This is the implementation for the slab allocator for generic sizes
#ifndef SH_LIB_SLAB_GENERIC_H
#define SH_LIB_SLAB_GENERIC_H
#include "memory/page.h"
#include "std/status.h"
#include "std/type.h"
#include "memory/pba.h"
#define SH_SLAB_GENERIC_SLAB_DATA_PAGES {1,2,4,8,16,32,64,128}
#define SH_SLAB_GENERIC_OBJECT_SIZE_BYTES {8,16,32,64,128,256,512,1024}
#define SH_SLAB_GENERIC_OBJECTS_PER_SLAB 512
#define SH_SLAB_GENERIC_ACTUAL_OBJECTS_PER_SLAB {496,504,508,510,511,511,511,511}
#define SH_SLAB_GENERIC_SLAB_BITMAP_INIT {0xFFFF,0xFF,0xF,0x3,1,1,1,1}
#define SH_SLAB_GENERIC_SLAB_BITMAP_SIZE_BYTES 64
#define SH_SLAB_GENERIC_NULL_REF (sh_uint64)0
#define SH_SLAB_GENERIC_SLAB_SIG {'S','h','S','l','G','e','n','e'}
#define SH_SLAB_GENERIC_MAGIC 0x656E65476C536853ULL // little endian
// Generic slab structure
#pragma pack(1)
typedef struct sh_slab_generic_SLAB {
sh_uint8 sig[8];
sh_uint16 used_count;
sh_uint64 slab_index;
struct sh_slab_generic_SLAB* next_slab;
struct sh_slab_generic_SLAB* prev_slab;
struct sh_slab_generic_SLAB* next_partial;
struct sh_slab_generic_SLAB* prev_partial;
sh_uint8 padding[14];
sh_uint64 free_bitmap[SH_SLAB_GENERIC_SLAB_BITMAP_SIZE_BYTES/8]; // First objects will be mark as unavailable due to being replaced by the header and bitmap, their amount depend on the object size
} sh_slab_generic_SLAB;
#pragma pack()
// Radix node slab allocator structure
struct sh_slab_generic_SLAB_ALLOCATOR {
sh_slab_generic_SLAB* first_slab;
sh_slab_generic_SLAB* partial_head;
sh_uint64 level;
sh_uint64 slab_count;
sh_uint64 object_size_bytes;
sh_uint64 object_per_slab;
sh_uint64 actual_object_per_slab;
sh_uint64 bitmap_init;
sh_uint64 slab_pages_count;
sh_pba_PAGE_BLOCK_ALLOCATOR* pba;
};
typedef sh_uint16 sh_slab_generic_OBJECT_INDEX_IN_SLAB;
// Initialize slab allocator structure. Does not allocate any slab
SH_STATUS sh_slab_generic_alloc_init(sh_uint8 level,struct sh_slab_generic_SLAB_ALLOCATOR* slab_alloc,sh_pba_PAGE_BLOCK_ALLOCATOR *pba);
// Allocate a new slab, initialize it and put it into the allocator. If new slab isn't the first to be allocated, push it on the partial slab list
SH_STATUS sh_slab_generic_add_slab(struct sh_slab_generic_SLAB_ALLOCATOR* alloc,sh_page_PAGE_TABLE_POOL *ptp,sh_slab_generic_SLAB** out_slab);
// Obtain a pointer to the first partial slab. Does not scan the slabs. Allocate a new slab if necessary
SH_STATUS sh_slab_generic_get_partial_slab(struct sh_slab_generic_SLAB_ALLOCATOR* alloc,sh_page_PAGE_TABLE_POOL* ptp,sh_slab_generic_SLAB** found_slab);
// Rescan all the slabs to rebuild partial list in case of doubt. Does not modify alloc->slab_count, any slab->free_bitmap or any slab>->nodes
SH_STATUS sh_slab_generic_scan_slabs(struct sh_slab_generic_SLAB_ALLOCATOR* alloc);
// Return a valid pointer to an empty object slot as well as the object index in the corresponding index. Slabs allocation is automated by sh_slab_generic_get_partial_slab
SH_STATUS sh_slab_generic_find_free_object(struct sh_slab_generic_SLAB_ALLOCATOR* alloc,sh_page_PAGE_TABLE_POOL *ptp,void** out,sh_slab_generic_OBJECT_INDEX_IN_SLAB* index_in_slab);
// Allocate one new object. Return a pointer to the struct of the new object. Since it call sh_slab_generic_find_free_object, it can allocate new slab
SH_STATUS sh_slab_generic_alloc(struct sh_slab_generic_SLAB_ALLOCATOR* alloc,sh_page_PAGE_TABLE_POOL *ptp,void** out_obj);
// Dellocate one radix node object provided as pointer.
SH_STATUS sh_slab_generic_dealloc(struct sh_slab_generic_SLAB_ALLOCATOR* alloc,void *object_ptr);
#endif

View File

@@ -0,0 +1,59 @@
// SPDX-License-Identifier: MPL-2.0
// This is the implementation for the slab allocator for sh_radix_NODE
#ifndef SH_LIB_SLAB_RADIX_NODE_H
#define SH_LIB_SLAB_RADIX_NODE_H
#include "memory/page.h"
#include "std/status.h"
#include "std/type.h"
#include "memory/pez/radix.h"
#include "memory/pba.h"
#define SH_SLAB_RADIX_NODE_SLAB_DATA_PAGES (sh_uint64)32
#define SH_SLAB_RADIX_NODE_SLAB_DATA_SIZE_BYTES (sh_uint64)(SH_SLAB_RADIX_NODE_SLAB_DATA_PAGES*4096)
#define SH_SLAB_RADIX_NODE_OBJECT_SIZE_BYTES (sh_uint64)128
#define SH_SLAB_RADIX_NODE_OBJECTS_PER_SLAB (sh_uint64)1024
#define SH_SLAB_RADIX_NODE_ACTUAL_OBJECTS_PER_SLAB (sh_uint64)1006
#define SH_SLAB_RADIX_NODE_SLAB_BITMAP_SIZE_BYTES (sh_uint64)(SH_SLAB_RADIX_NODE_OBJECTS_PER_SLAB/8)
#define SH_SLAB_RADIX_NODE_NULL_REF (sh_uint64)0
#define SH_SLAB_RADIX_NODE_SLAB_SIG {'S','h','S','l','R','a','N','o'}
#define SH_SLAB_RADIX_NODE_MAGIC 0x6F4E61526C536853ULL // little endian
// Radix node slab structure
#pragma pack(1)
typedef struct sh_slab_radix_node_SLAB {
sh_uint8 sig[8];
sh_uint16 used_count;
sh_uint64 slab_index;
struct sh_slab_radix_node_SLAB* next_slab;
struct sh_slab_radix_node_SLAB* prev_slab;
struct sh_slab_radix_node_SLAB* next_partial;
struct sh_slab_radix_node_SLAB* prev_partial;
sh_uint8 padding[78];
sh_uint64 free_bitmap[16]; // First 18 objects will be mark as unavailable due to being replaced by the header and bitmap
sh_uint16 node_bitmap[1024];
sh_radix_NODE nodes[SH_SLAB_RADIX_NODE_ACTUAL_OBJECTS_PER_SLAB];
} sh_slab_radix_node_SLAB;
#pragma pack()
// Radix node slab allocator structure
struct sh_slab_radix_node_SLAB_ALLOCATOR {
sh_slab_radix_node_SLAB* first_slab;
sh_slab_radix_node_SLAB* partial_head;
sh_uint64 slab_count;
sh_pba_PAGE_BLOCK_ALLOCATOR* pba;
};
typedef sh_uint16 sh_slab_radix_node_NODE_INDEX_IN_SLAB;
// Initialize slab allocator structure. Does not allocate any slab
SH_STATUS sh_slab_radix_node_alloc_init(struct sh_slab_radix_node_SLAB_ALLOCATOR* slab_alloc,sh_pba_PAGE_BLOCK_ALLOCATOR *pba);
// Allocate a new slab, initialize it and put it into the allocator. If new slab isn't the first to be allocated, push it on the partial slab list
SH_STATUS sh_slab_radix_node_add_slab(struct sh_slab_radix_node_SLAB_ALLOCATOR* alloc,sh_page_PAGE_TABLE_POOL *ptp,sh_slab_radix_node_SLAB** out_slab);
// Obtain a pointer to the first partial slab. Does not scan the slabs. Allocate a new slab if necessary
SH_STATUS sh_slab_radix_node_get_partial_slab(struct sh_slab_radix_node_SLAB_ALLOCATOR* alloc,sh_page_PAGE_TABLE_POOL* ptp,sh_slab_radix_node_SLAB** found_slab);
// Rescan all the slabs to set all metadatas in case of doubt. Does not modify alloc->slab_count or <any slab>->nodes
SH_STATUS sh_slab_radix_node_scan_slabs(struct sh_slab_radix_node_SLAB_ALLOCATOR* alloc);
// Return a valid pointer to an empty object slot as well as the object index in the corresponding index. Slabs allocation is automated by sh_slab_radix_node_get_partial_slab
SH_STATUS sh_slab_radix_node_find_free_object(struct sh_slab_radix_node_SLAB_ALLOCATOR* alloc,sh_page_PAGE_TABLE_POOL *ptp,sh_radix_NODE** out,sh_slab_radix_node_NODE_INDEX_IN_SLAB* index_in_slab);
// Allocate one new radix node object. Return a pointer to the struct of the new object. Since it call sh_slab_reg_phys_find_free_object, it can allocate new slab
SH_STATUS sh_slab_radix_node_alloc(struct sh_slab_radix_node_SLAB_ALLOCATOR* alloc,sh_page_PAGE_TABLE_POOL *ptp,sh_radix_NODE** out_obj);
// Dellocate one radix node object provided as pointer.
SH_STATUS sh_slab_radix_node_dealloc(struct sh_slab_radix_node_SLAB_ALLOCATOR* alloc,sh_radix_NODE *object_ptr);
// Return a pointer to the bitmap of a node
sh_uint16 *sh_slab_radix_node_get_node_bitmap(struct sh_slab_radix_node_SLAB_ALLOCATOR* alloc,sh_radix_NODE *object_ptr);
#endif

View File

@@ -0,0 +1,58 @@
// SPDX-License-Identifier: MPL-2.0
// This is the implementation for the slab allocator for sh_pez_REGION_PHYSICAL_OBJECT
#ifndef SH_LIB_SLAB_REG_PHYS_H
#define SH_LIB_SLAB_REG_PHYS_H
#include "std/type.h"
#include "std/status.h"
#include "memory/page.h"
#include "memory/vmem_layout.h"
#define SH_SLAB_REG_PHYS_DATA_VA SH_VMEM_LAYOUT_SLAB_REG_PHYS_VA
#define SH_SLAB_REG_PHYS_MAX_SLAB (sh_uint64)(16*1024)
#define SH_SLAB_REG_PHYS_SLAB_DATA_PAGES (sh_uint64)3
#define SH_SLAB_REG_PHYS_SLAB_DATA_SIZE_BYTES (sh_uint64)(SH_SLAB_REG_PHYS_SLAB_DATA_PAGES*4096)
#define SH_SLAB_REG_PHYS_OBJECT_SIZE_BYTES (sh_uint64)12
#define SH_SLAB_REG_PHYS_OBJECTS_PER_SLAB (sh_uint64)1024
#define SH_SLAB_REG_PHYS_ACTUAL_OBJECTS_PER_SLAB (sh_uint64)1023
#define SH_SLAB_REG_PHYS_SLAB_BITMAP_SIZE_BYTES (sh_uint64)(SH_SLAB_REG_PHYS_OBJECTS_PER_SLAB/8)
#define SH_SLAB_REG_PHYS_NULL_REF (sh_uint64)0
// Physical region slab structure
typedef struct sh_slab_reg_phys_SLAB_STRUCT {
sh_uint16 used_count;
sh_uint16 slab_index;
struct sh_slab_reg_phys_SLAB_STRUCT* next;
struct sh_slab_reg_phys_SLAB_STRUCT* prev;
sh_uint64 free_bitmap[16];
} sh_slab_reg_phys_SLAB_STRUCT;
#define SH_SLAB_REG_PHYS_HEADER_LIST_SIZE_BYTES SH_SLAB_REG_PHYS_MAX_SLAB*sizeof(sh_slab_reg_phys_SLAB_STRUCT)
// Physical region object slab allocator structure
typedef struct {
sh_slab_reg_phys_SLAB_STRUCT* slabs_header;
sh_uint8* slabs_data;
sh_uint16 max_slabs;
sh_uint16 slab_count;
sh_slab_reg_phys_SLAB_STRUCT* partial_head;
} sh_slab_reg_phys_SLAB_ALLOCATOR;
typedef sh_uint32 sh_slab_reg_phys_OBJECT_INDEX;
// Return slab index
#define SH_SLAB_REG_PHYS_REF_SLAB(ref) (sh_uint16)((ref)>>10)
// Return object index inside a slab
#define SH_SLAB_REG_PHYS_REF_OBJECT(ref) (sh_uint16)((ref) & 0x3FF)
// Make a valid object index from a slab index and an object index inside this slab
#define SH_SLAB_REG_PHYS_MAKE_REF(slab,obj) (((sh_slab_reg_phys_OBJECT_INDEX)(slab)<<10) | (sh_slab_reg_phys_OBJECT_INDEX)(obj))
// Initialize slab allocator structure. Does not allocate any slabs
SH_STATUS sh_slab_reg_phys_alloc_init(sh_slab_reg_phys_SLAB_ALLOCATOR* slab_alloc,sh_page_PAGE_TABLE_POOL *ptp);
// Allocate a new slab, initialize it and put it into the allocator. If new slab isn't the first to be allocated, push it on the partial slab list
SH_STATUS sh_slab_reg_phys_add_slab(sh_slab_reg_phys_SLAB_ALLOCATOR* alloc,sh_page_PAGE_TABLE_POOL *ptp,sh_slab_reg_phys_SLAB_STRUCT** out_slab);
// Obtain a pointer to the first partial slab. Does not scan the slabs. Allocate a new slab if necessary
SH_STATUS sh_slab_reg_phys_get_partial_slab(sh_slab_reg_phys_SLAB_ALLOCATOR* alloc,sh_page_PAGE_TABLE_POOL* ptp,sh_slab_reg_phys_SLAB_STRUCT** found_slab);
// Rescan all the slabs to set all metadatas in case of doubt. Does not modify alloc->slab_count, alloc->slabs_data
SH_STATUS sh_slab_reg_phys_scan_slabs(sh_slab_reg_phys_SLAB_ALLOCATOR* alloc);
// Return a valid 24 bits index to a empty object slot. Slabs allocation is automated by sh_slab_reg_phys_get_partial_slab
SH_STATUS sh_slab_reg_phys_find_free_object(sh_slab_reg_phys_SLAB_ALLOCATOR* alloc,sh_page_PAGE_TABLE_POOL *ptp,sh_slab_reg_phys_OBJECT_INDEX* out_ref);
// Return a pointer to referenced physical region object
void* sh_slab_reg_phys_ref_to_ptr(sh_slab_reg_phys_SLAB_ALLOCATOR* alloc,sh_slab_reg_phys_OBJECT_INDEX ref);
// Allocate one new physical region object. Return an index to access and deallocate the object. Since it call sh_slab_reg_phys_find_free_object, it can allocate new slab
SH_STATUS sh_slab_reg_phys_alloc(sh_slab_reg_phys_SLAB_ALLOCATOR* alloc,sh_page_PAGE_TABLE_POOL *ptp,sh_slab_reg_phys_OBJECT_INDEX* out_index);
// Dellocate one physical region object provided as index.
SH_STATUS sh_slab_reg_phys_dealloc(sh_slab_reg_phys_SLAB_ALLOCATOR* alloc,sh_slab_reg_phys_OBJECT_INDEX index);
#endif

View File

@@ -0,0 +1,58 @@
// SPDX-License-Identifier: MPL-2.0
// This is the implementation for the slab allocator for sh_pez_REGION_VIRTUAL_OBJECT
#ifndef SH_LIB_SLAB_REG_VIRT_H
#define SH_LIB_SLAB_REG_VIRT_H
#include "std/type.h"
#include "std/status.h"
#include "memory/page.h"
#include "memory/vmem_layout.h"
#define SH_SLAB_REG_VIRT_DATA_VA SH_VMEM_LAYOUT_SLAB_REG_VIRT_VA
#define SH_SLAB_REG_VIRT_MAX_SLAB (sh_uint64)(512*1024)
#define SH_SLAB_REG_VIRT_SLAB_DATA_PAGES (sh_uint64)3
#define SH_SLAB_REG_VIRT_SLAB_DATA_SIZE_BYTES (sh_uint64)(SH_SLAB_REG_VIRT_SLAB_DATA_PAGES*4096)
#define SH_SLAB_REG_VIRT_OBJECT_SIZE_BYTES (sh_uint64)12
#define SH_SLAB_REG_VIRT_OBJECTS_PER_SLAB (sh_uint64)1024
#define SH_SLAB_REG_VIRT_ACTUAL_OBJECTS_PER_SLAB (sh_uint64)1023
#define SH_SLAB_REG_VIRT_SLAB_BITMAP_SIZE_BYTES (sh_uint64)(SH_SLAB_REG_VIRT_OBJECTS_PER_SLAB/8)
#define SH_SLAB_REG_VIRT_NULL_REF (sh_uint64)0
// Virtual region slab structure
typedef struct sh_slab_reg_virt_SLAB_STRUCT {
sh_uint16 used_count;
sh_uint32 slab_index;
struct sh_slab_reg_virt_SLAB_STRUCT* next;
struct sh_slab_reg_virt_SLAB_STRUCT* prev;
sh_uint64 free_bitmap[16];
} sh_slab_reg_virt_SLAB_STRUCT;
#define SH_SLAB_REG_VIRT_HEADER_LIST_SIZE_BYTES SH_SLAB_REG_VIRT_MAX_SLAB*sizeof(sh_slab_reg_virt_SLAB_STRUCT)
// Virtual region object slab allocator structure
typedef struct {
sh_slab_reg_virt_SLAB_STRUCT* slabs_header;
sh_uint8* slabs_data;
sh_uint32 max_slabs;
sh_uint32 slab_count;
sh_slab_reg_virt_SLAB_STRUCT* partial_head;
} sh_slab_reg_virt_SLAB_ALLOCATOR;
typedef sh_uint32 sh_slab_reg_virt_OBJECT_INDEX;
// Return slab index
#define SH_SLAB_REG_VIRT_REF_SLAB(ref) (sh_uint32)((ref)>>10)
// Return object index inside a slab
#define SH_SLAB_REG_VIRT_REF_OBJECT(ref) (sh_uint16)((ref) & 0x3FF)
// Make a valid object index from a slab index and an object index inside this slab
#define SH_SLAB_REG_VIRT_MAKE_REF(slab,obj) (((sh_slab_reg_virt_OBJECT_INDEX)(slab)<<10) | (sh_slab_reg_virt_OBJECT_INDEX)(obj))
// Initialize slab allocator structure. Does not allocate any slabs
SH_STATUS sh_slab_reg_virt_alloc_init(sh_slab_reg_virt_SLAB_ALLOCATOR* slab_alloc,sh_page_PAGE_TABLE_POOL *ptp);
// Allocate a new slab, initialize it and put it into the allocator. If new slab isn't the first to be allocated, push it on the partial slab list
SH_STATUS sh_slab_reg_virt_add_slab(sh_slab_reg_virt_SLAB_ALLOCATOR* alloc,sh_page_PAGE_TABLE_POOL *ptp,sh_slab_reg_virt_SLAB_STRUCT** out_slab);
// Obtain a pointer to the first partial slab. Does not scan the slabs. Allocate a new slab if necessary
SH_STATUS sh_slab_reg_virt_get_partial_slab(sh_slab_reg_virt_SLAB_ALLOCATOR* alloc,sh_page_PAGE_TABLE_POOL* ptp,sh_slab_reg_virt_SLAB_STRUCT** found_slab);
// Rescan all the slabs to set all metadatas in case of doubt. Does not modify alloc->slab_count, alloc->slabs_data
SH_STATUS sh_slab_reg_virt_scan_slabs(sh_slab_reg_virt_SLAB_ALLOCATOR* alloc);
// Return a valid 29 bits index to a empty object slot. Slabs allocation is automated by sh_slab_reg_virt_get_partial_slab
SH_STATUS sh_slab_reg_virt_find_free_object(sh_slab_reg_virt_SLAB_ALLOCATOR* alloc,sh_page_PAGE_TABLE_POOL *ptp,sh_slab_reg_virt_OBJECT_INDEX* out_ref);
// Return a pointer to referenced virtual region object
void* sh_slab_reg_virt_ref_to_ptr(sh_slab_reg_virt_SLAB_ALLOCATOR* alloc,sh_slab_reg_virt_OBJECT_INDEX ref);
// Allocate one new virtual region object. Return both a pointer to the struct of the new object and an index to access and deallocte the object. Since it call sh_slab_reg_virt_find_free_object, it can allocate new slab
SH_STATUS sh_slab_reg_virt_alloc(sh_slab_reg_virt_SLAB_ALLOCATOR* alloc,sh_page_PAGE_TABLE_POOL *ptp,sh_slab_reg_virt_OBJECT_INDEX* out_index);
// Dellocate one virtual region object provided as index.
SH_STATUS sh_slab_reg_virt_dealloc(sh_slab_reg_virt_SLAB_ALLOCATOR* alloc,sh_slab_reg_virt_OBJECT_INDEX index);
#endif

View File

@@ -0,0 +1,93 @@
// SPDX-License-Identifier: MPL-2.0
#ifndef SH_LIB_VMEM_LAYOUT_H
#define SH_LIB_VMEM_LAYOUT_H
// HOW TO USE THIS FILE
// This file contain the VA, size in bytes and sometimes the end of virtual memory regions
// that we are sure that the kernel will search into at boot time or allocate things at these
// places.
// This file is autocheck by an automated script to ensure there is no overlapping.
// Any macro ending with _VA will create a new virtual region for the script. It will look for the
// size of this virtual region in another macro that start with the same prefix and end with
// _SIZE_BYTES.
// If a macro ending with _VA doesn't have a corresponding macro ending with _SIZE_BYTES, the
// script will trigger an error and the kernel compilation will fail.
// If a macro ending with _SIZE_BYTES doesn't have a corresponding macro ending with _VA, the
// script will ignore it.
// The start of each virtual region must be aligned to 4096 bytes and the size must be provided
// in bytes.
// Any overlapping virtual region will trigger a compilation error.
// Consider using this file as the source of trust for everything related to static virtual
// regions.
// Any macro that doesn't end with _VA or _SIZE_BYTES or that doesn't correspong to the behaviour
// described above will be ignored.
// TEMPORARY STRUCTURE
// The base for the memory map
#define SH_VMEM_LAYOUT_BOOT_CONFIG_VA 0x00180000
// The size for the memory map
#define SH_VMEM_LAYOUT_BOOT_CONFIG_SIZE_BYTES 4096
// The base for the memory map
#define SH_VMEM_LAYOUT_MEMORY_MAP_VA 0x00190000
// The size for the memory map
#define SH_VMEM_LAYOUT_MEMORY_MAP_SIZE_BYTES 16*4096
// KERNEL HEAP
// The base for big allocations region
#define SH_VMEM_LAYOUT_HEAP_BIG_VA 16LL*1024LL*1024LL*1024LL*1024LL
// The end for big allocations regions
#define SH_VMEM_LAYOUT_HEAP_BIG_SIZE_BYTES (0xFFFFFFFELL)*4096LL
// The base for all generic slabs allocators for the heap, spaced by 12 TB each
#define SH_VMEM_LAYOUT_HEAP_SLAB_LEVEL_0_VA 0x0000200000000000
#define SH_VMEM_LAYOUT_HEAP_SLAB_LEVEL_1_VA 0x00002C0000000000
#define SH_VMEM_LAYOUT_HEAP_SLAB_LEVEL_2_VA 0x0000380000000000
#define SH_VMEM_LAYOUT_HEAP_SLAB_LEVEL_3_VA 0x0000440000000000
#define SH_VMEM_LAYOUT_HEAP_SLAB_LEVEL_4_VA 0x0000500000000000
#define SH_VMEM_LAYOUT_HEAP_SLAB_LEVEL_5_VA 0x00005C0000000000
#define SH_VMEM_LAYOUT_HEAP_SLAB_LEVEL_6_VA 0x0000680000000000
#define SH_VMEM_LAYOUT_HEAP_SLAB_LEVEL_7_VA 0x0000740000000000
// The size for all generic slabs_allocators for the heap
#define SH_VMEM_LAYOUT_HEAP_SLAB_LEVEL_0_SIZE_BYTES 0xBFFFFFFFLL*4096LL
#define SH_VMEM_LAYOUT_HEAP_SLAB_LEVEL_1_SIZE_BYTES 0xBFFFFFFFLL*4096LL
#define SH_VMEM_LAYOUT_HEAP_SLAB_LEVEL_2_SIZE_BYTES 0xBFFFFFFFLL*4096LL
#define SH_VMEM_LAYOUT_HEAP_SLAB_LEVEL_3_SIZE_BYTES 0xBFFFFFFFLL*4096LL
#define SH_VMEM_LAYOUT_HEAP_SLAB_LEVEL_4_SIZE_BYTES 0xBFFFFFFFLL*4096LL
#define SH_VMEM_LAYOUT_HEAP_SLAB_LEVEL_5_SIZE_BYTES 0xBFFFFFFFLL*4096LL
#define SH_VMEM_LAYOUT_HEAP_SLAB_LEVEL_6_SIZE_BYTES 0xBFFFFFFFLL*4096LL
#define SH_VMEM_LAYOUT_HEAP_SLAB_LEVEL_7_SIZE_BYTES 0xBFFFFFFFLL*4096LL
// The spacing in bytes for each slab allocator base
#define SH_VMEM_LAYOUT_HEAP_SLAB_SPACING 0xC0000000000
// KERNEL AND STACKS AREA
// The base for the kernel image area
#define SH_VMEM_LAYOUT_KERNEL_IMAGE_AREA_VA 0xFFFF800000000000ULL
// The size for the kernel image area
#define SH_VMEM_LAYOUT_KERNEL_IMAGE_AREA_SIZE_BYTES 0xFFFF900000000000ULL-1-0xFFFF800000000000ULL
// The base for the stack area
#define SH_VMEM_LAYOUT_STACK_AREA_VA 0xFFFFF00000000000ULL
// The size for the kernel image area
#define SH_VMEM_LAYOUT_STACK_AREA_SIZE_BYTES 0xFFFFFF8000000000ULL-0xFFFFF00000000000ULL
// KERNEL ALLOCATION SPACE
// The base for the kernel allocation space
#define SH_VMEM_LAYOUT_KERNEL_ALLOC_SPACE_VA 0xFFFF900000000000ULL
// The size for the kernel allocation space
#define SH_VMEM_LAYOUT_KERNEL_ALLOC_SPACE_SIZE_BYTES 0xFFFFEFFFFFFFFFFFULL-0xFFFF900000000000ULL
// The end for the kernel allocation space
#define SH_VMEM_LAYOUT_KERNEL_ALLOC_SPACE_VA_END 0xFFFFEFFFFFFFFFFFULL
// SLABS VIRTUAl REGIONS
// The base for the slabs for physical regions objects
#define SH_VMEM_LAYOUT_SLAB_REG_PHYS_VA 0xFFFFFF8000000000ULL+0x4000ULL
// The total size for the slabs for physical regions objects
#define SH_VMEM_LAYOUT_SLAB_REG_PHYS_SIZE_BYTES 192*1024*1024ULL
// The base for the slabs for virtual regions objects
#define SH_VMEM_LAYOUT_SLAB_REG_VIRT_VA 0xFFFFFF800C600000ULL
// The total size for the slabs for virtual regions objects
#define SH_VMEM_LAYOUT_SLAB_REG_VIRT_SIZE_BYTES (1ULL<<29)*12ULL
// The alignement for SH_VMEM_LAYOUT_SLAB_RADIX_NODE_VA
#define SH_VMEM_LAYOUT_PBA_RADIX_NODE_BLOCK_ALIGN (32ULL*4096ULL)
// The base for the PBA for the slabs for radix nodes
#define SH_VMEM_LAYOUT_SLAB_RADIX_NODE_VA ((SH_VMEM_LAYOUT_SLAB_REG_VIRT_VA+SH_VMEM_LAYOUT_SLAB_REG_VIRT_SIZE_BYTES+SH_VMEM_LAYOUT_PBA_RADIX_NODE_BLOCK_ALIGN)/SH_VMEM_LAYOUT_PBA_RADIX_NODE_BLOCK_ALIGN)*SH_VMEM_LAYOUT_PBA_RADIX_NODE_BLOCK_ALIGN
// The total size for the PBA for the slabs for radix nodes
#define SH_VMEM_LAYOUT_SLAB_RADIX_NODE_SIZE_BYTES 64ULL*1024ULL*1024ULL*1024ULL
// LOGGING RING BUFFER
// The base for the logging ring buffer
#define SH_VMEM_LAYOUT_LOGGING_RING_BUFFER_VA 0xFFFFFFFFF0000000ULL
// The max size for the logging ring buffer
#define SH_VMEM_LAYOUT_LOGGING_RING_BUFFER_SIZE_BYTES 0xFFFF*4096
#endif

View File

@@ -0,0 +1,12 @@
// SPDX-License-Identifier: MPL-2.0
#ifndef SH_LIB_MALLOC_H
#define SH_LIB_MALLOC_H
#include "std/status.h"
#include "std/type.h"
// Return last status
SH_STATUS sh_malloc_get_last_status();
// Allocate memory
void* sh_malloc(sh_uint64 size);
// Free memory
void sh_free(void *ptr);
#endif

View File

@@ -0,0 +1,12 @@
// SPDX-License-Identifier: MPL-2.0
#ifndef SH_LIB_MEM_H
#define SH_LIB_MEM_H
#include "std/type.h"
#include "std/status.h"
// Memory comparaison function
SH_STATUS sh_mem_compare(const void *a,const void *b,sh_uint64 size);
// Memory copy function
SH_STATUS sh_mem_copy(const void *destination,const void *source,sh_uint64 size);
// Memory set function
SH_STATUS sh_mem_set_8(sh_uint8 *ptr,const sh_uint8 byte,sh_uint64 count);
#endif

View File

@@ -0,0 +1,43 @@
// SPDX-License-Identifier: MPL-2.0
#ifndef SH_LIB_STATUS_H
#define SH_LIB_STATUS_H
#include "std/type.h"
typedef sh_int64 SH_STATUS;
#define SH_STATUS_NEW_SLAB_ADDED -5LL
#define SH_STATUS_VA_FULLY_MAPPED -4LL
#define SH_STATUS_VA_PARTIALLY_MAPPED -3LL
#define SH_STATUS_VA_NOT_MAPPED -2LL
#define SH_STATUS_VA_MAPPED -1LL
#define SH_STATUS_SUCCESS 0LL
#define SH_STATUS_INVALID_PARAMETER 1LL
#define SH_STATUS_MEM_NOT_EQUAL 2LL
#define SH_STATUS_INVALID_SIGNATURE 3LL
#define SH_STATUS_MMAP_BUFFER_OVERFLOW 4LL
#define SH_STATUS_PMAP_NO_PAGES_SET 5LL
#define SH_STATUS_PT_POOL_NO_BITMAP_INIT 6LL
#define SH_STATUS_PT_POOL_NO_PAGE_SET 7LL
#define SH_STATUS_OUT_OF_MEMORY 8LL
#define SH_STATUS_INVALID_INTERNAL_PA 9LL
#define SH_STATUS_KERNEL_PANIC 10LL
#define SH_STATUS_PTP_FULL 11LL
#define SH_STATUS_ERROR_VA_FULLY_MAPPED 12LL
#define SH_STATUS_ERROR_VA_PARTIALLY_MAPPED 13LL
#define SH_STATUS_ERROR_VA_NOT_MAPPED 14LL
#define SH_STATUS_SLAB_ALLOCATOR_FULL 15LL
#define SH_STATUS_NOT_FOUND 16LL
#define SH_STATUS_RESCAN_NEEDED 17LL
#define SH_STATUS_ERROR_NULLPTR_RETURNED 18LL
#define SH_STATUS_ERROR_PEZ_INITIALIZED 19LL
#define SH_STATUS_SLAB_SLOT_ALREADY_FREE 20LL
#define SH_STATUS_TEST_FAILED 21LL
#define SH_STATUS_PBA_FULL 22LL
#define SH_STATUS_FOUND_CORRUPTED_SLAB 23LL
#define SH_STATUS_PEZ_CORRUPTED 24LL
#define SH_STATUS_PAGE_ALREADY_FREE 25LL
#define SH_STATUS_TOO_MUCH_DATA 26LL
#define SH_STATUS_HEAP_NOT_INITIALIZED 27LL
// Return SH_TRUE if provided status is an error
static inline sh_bool sh_status_error(SH_STATUS s) {
return s>=SH_STATUS_INVALID_PARAMETER;
}
#endif

View File

@@ -0,0 +1,7 @@
// SPDX-License-Identifier: MPL-2.0
// This header is just here to include all standard header
// If you are looking for printing functions, take a look at kernel/log.h
#include "std/mem.h"
#include "std/malloc.h"
#include "std/status.h"
#include "std/type.h"

View File

@@ -0,0 +1,35 @@
// SPDX-License-Identifier: MPL-2.0
#ifndef SH_LIB_TYPE_H
#define SH_LIB_TYPE_H
typedef signed char sh_int8;
typedef unsigned char sh_uint8;
typedef signed short sh_int16;
typedef unsigned short sh_uint16;
typedef signed int sh_int32;
typedef unsigned int sh_uint32;
typedef signed long long sh_int64;
typedef unsigned long long sh_uint64;
#define SH_INT8_MAX 127
#define SH_INT8_MIN (-128)
#define SH_UINT8_MAX 0xFF
#define SH_INT16_MAX 32767
#define SH_INT16_MIN (-32768)
#define SH_UINT16_MAX 0xFFFF
#define SH_INT32_MAX 2147483647
#define SH_INT32_MIN (-2147483647-1)
#define SH_UINT32_MAX 0xFFFFFFFFU
#define SH_INT64_MAX 9223372036854775807LL
#define SH_INT64_MIN (-9223372036854775807LL-1)
#define SH_UINT64_MAX 0xFFFFFFFFFFFFFFFFULL
#define SH_NULLPTR ((void*)0)
typedef sh_uint8 sh_bool;
#define SH_TRUE ((sh_bool)1)
#define SH_FALSE ((sh_bool)0)
#define SH_DEFVALUE ((sh_uint64)0x446546614C547674)
#define DEFAULT
typedef sh_uint64 sh_iter64;
typedef __builtin_va_list va_list;
#define va_start(v,l) __builtin_va_start(v,l)
#define va_end(v) __builtin_va_end(v)
#define va_arg(v,l) __builtin_va_arg(v,l)
#endif

View File

@@ -0,0 +1,14 @@
// SPDX-License-Identifier: MPL-2.0
#include "cpu/serial.h"
#include "cpu/asm.h"
sh_bool disable_serial_port=SH_FALSE;
void sh_serial_load_serial_port_setting(sh_bool is_disabled) {
disable_serial_port=is_disabled;
return;
}
void sh_serial_send_byte(sh_uint8 b) {
if (disable_serial_port) return;
while (!(sh_asm_inb(SH_SERIAL_PORT_COM1+5) & 0x20));
sh_asm_outb(SH_SERIAL_PORT_COM1,b);
return;
}

13
shelter/lib/src/cpu/tsc.c Normal file
View File

@@ -0,0 +1,13 @@
// SPDX-License-Identifier: MPL-2.0
#include "cpu/tsc.h"
sh_tsc_TSC_VALUE kernel_start_tsc=0;
SH_STATUS sh_tsc_init_tsc() {
kernel_start_tsc=sh_tsc_read_tsc();
return SH_STATUS_SUCCESS;
}
sh_tsc_TSC_VALUE sh_tsc_get_kernel_init_tsc() {
return kernel_start_tsc;
}
sh_tsc_TSC_VALUE sh_tsc_get_kernel_current_tsc() {
return sh_tsc_read_tsc()-kernel_start_tsc;
}

View File

@@ -0,0 +1,19 @@
// SPDX-License-Identifier: MPL-2.0
#include "kernel/conf.h"
#include "kernel/log.h"
#include "std/mem.h"
SH_STATUS sh_conf_get_boot_config(sh_conf_BOOT_CONFIG **config) {
if (config==SH_NULLPTR) {
return SH_STATUS_INVALID_PARAMETER;
}
*config=(sh_conf_BOOT_CONFIG *)SH_CONF_BOOT_CONFIG_VA;
static const sh_uint8 sig_start[8]={'S','h','C','f','g','B','e','g'};
static const sh_uint8 sig_end[8]={'S','h','C','f','g','E','n','d'};
if (sh_mem_compare((*config)->sig_start,sig_start,sizeof(sig_start))==SH_STATUS_MEM_NOT_EQUAL) {
return SH_STATUS_INVALID_SIGNATURE;
}
if (sh_mem_compare((*config)->sig_end,sig_end,sizeof(sig_end))==SH_STATUS_MEM_NOT_EQUAL) {
return SH_STATUS_INVALID_SIGNATURE;
}
return SH_STATUS_SUCCESS;
}

View File

@@ -0,0 +1,720 @@
// SPDX-License-Identifier: MPL-2.0
#include "kernel/log.h"
#include "memory/page.h"
#include "memory/ring.h"
#include "cpu/serial.h"
sh_uint8 kernel_log_level=0;
sh_bool log_disable_serial_port=SH_FALSE;
sh_ring_RING_BUFFER_HEADER logging_ring={.head=0,.tail=0,.buffer_bytes_size=4*4096,.data_start=(sh_uint8*)SH_VMEM_LAYOUT_LOGGING_RING_BUFFER_VA,.total_bytes_written=0};
void sh_log_load_serial_setting(sh_bool is_disabled) {
log_disable_serial_port=is_disabled;
return;
}
sh_bool sh_log_get_serial_setting() {
return log_disable_serial_port;
}
void sh_log_load_logging_ring_size(sh_uint16 pages_count) {
logging_ring.buffer_bytes_size=4096*pages_count;
return;
}
sh_uint32 sh_log_get_logging_ring_size() {
return logging_ring.buffer_bytes_size;
}
sh_uint64 sh_log_get_total_bytes_written() {
return logging_ring.total_bytes_written;
}
void sh_log_byte(sh_uint8 byte) {
if (log_disable_serial_port) return;
sh_serial_send_byte(byte);
sh_ring_write_byte(&logging_ring,(sh_uint8)byte);
return;
}
SH_STATUS sh_log_string(const char* str) {
while (*str) {
sh_log_byte((sh_uint8)*str++);
}
return SH_STATUS_SUCCESS;
}
SH_STATUS sh_log_int8(sh_int8 n) {
return sh_log_int64((sh_int64)n);
}
SH_STATUS sh_log_int16(sh_int16 n) {
return sh_log_int64((sh_int64)n);
}
SH_STATUS sh_log_int32(sh_int32 n) {
return sh_log_int64((sh_int64)n);
}
SH_STATUS sh_log_int64(sh_int64 n) {
sh_uint64 absolute_val;
if (n<0) {
sh_log_byte('-');
absolute_val=(sh_uint64)(-(n+1))+1;
} else {
absolute_val=(sh_uint64)n;
}
return sh_log_uint64(absolute_val);
}
SH_STATUS sh_log_uint8(sh_uint8 n) {
return sh_log_uint64((sh_uint64)n);
}
SH_STATUS sh_log_uint16(sh_uint16 n) {
return sh_log_uint64((sh_uint64)n);
}
SH_STATUS sh_log_uint32(sh_uint32 n) {
return sh_log_uint64((sh_uint64)n);
}
SH_STATUS sh_log_uint64(sh_uint64 n) {
char buf[20];
sh_uint32 i=0;
if (n==0) {
sh_log_byte('0');
return SH_STATUS_SUCCESS;
}
while (n>0) {
buf[i++]='0'+(sh_int8)(n%10);
n/=10;
}
while (i--) {
sh_log_byte((sh_uint8)buf[i]);
}
return SH_STATUS_SUCCESS;
}
SH_STATUS sh_log_uint8_hex(sh_uint8 n) {
return sh_log_uint64_hex((sh_uint64)n);
}
SH_STATUS sh_log_uint16_hex(sh_uint16 n) {
return sh_log_uint64_hex((sh_uint64)n);
}
SH_STATUS sh_log_uint32_hex(sh_uint32 n) {
return sh_log_uint64_hex((sh_uint64)n);
}
SH_STATUS sh_log_uint64_hex(sh_uint64 n) {
char buf[16];
sh_uint32 i=0;
const char hex_digits[]="0123456789ABCDEF";
if (n==0) {
sh_log_byte('0');
return SH_STATUS_SUCCESS;
}
while (n>0) {
buf[i++]=hex_digits[n & 0xF];
n>>=4;
}
while (i--) {
sh_log_byte((sh_uint8)buf[i]);
}
return SH_STATUS_SUCCESS;
}
SH_STATUS sh_log_uint64_hex_fixed(sh_uint64 n) {
const char hex_digits[]="0123456789ABCDEF";
for (sh_int8 i=15;i>=0;i--) {
sh_uint8 nibble=(sh_uint8)((n>>(i*4))&0xF);
sh_log_byte((sh_uint8)hex_digits[nibble]);
}
return SH_STATUS_SUCCESS;
}
SH_STATUS sh_log_double(double value) {
if (value<0) {
sh_log_byte('-');
value=-value;
}
sh_uint64 integer_part=(sh_uint64)value;
double fractional_part=value-(double)integer_part;
SH_STATUS status=sh_log_uint64(integer_part);
if (status!=SH_STATUS_SUCCESS) return status;
sh_log_byte('.');
for (sh_iter64 i=0;i<6;i++) {
fractional_part*=10.0;
sh_uint64 digit=(sh_uint64)fractional_part;
sh_log_byte('0'+(sh_uint8)digit);
fractional_part-=(double)digit;
}
return SH_STATUS_SUCCESS;
}
SH_STATUS sh_log_format(const char* format,va_list args) {
for (const char *p=format;*p!='\0';p++) {
if (*p!='%') {
sh_log_byte((sh_uint8)*p);
continue;
}
p++;
switch (*p) {
case 's': {
char *s=va_arg(args,char *);
sh_log_string(s);
break;
}
case 'd': {
double s=va_arg(args,double);
sh_log_double(s);
break;
}
case '1': {
if (p[1]=='u') {
sh_log_uint8((sh_uint8)va_arg(args,int));
p++;
} else if (p[1]=='s') {
sh_log_int8((sh_int8)va_arg(args,int));
p++;
} else if (p[1]=='U') {
sh_log_uint8_hex((sh_uint8)va_arg(args,int));
p++;
}
break;
}
case '2': {
if (p[1]=='u') {
sh_log_uint16((sh_uint16)va_arg(args,int));
p++;
} else if (p[1]=='s') {
sh_log_int16((sh_int16)va_arg(args,int));
p++;
} else if (p[1]=='U') {
sh_log_uint16_hex((sh_uint16)va_arg(args,int));
p++;
}
break;
}
case '4': {
if (p[1]=='u') {
sh_log_uint32((sh_uint32)va_arg(args,int));
p++;
} else if (p[1]=='s') {
sh_log_int32((sh_int32)va_arg(args,int));
p++;
} else if (p[1]=='U') {
sh_log_uint32_hex((sh_uint32)va_arg(args,int));
p++;
}
break;
}
case '8': {
if (p[1]=='u') {
sh_log_uint64(va_arg(args,unsigned long long));
p++;
} else if (p[1]=='s') {
sh_log_int64(va_arg(args,long long));
p++;
} else if (p[1]=='U') {
sh_log_uint64_hex(va_arg(args,unsigned long long));
p++;
}
break;
}
case 'x': {
sh_uint64 x=va_arg(args,sh_uint64);
sh_log_uint64_hex_fixed(x);
break;
}
case 'c': {
sh_log_byte((sh_uint8)va_arg(args,int));
break;
}
case '%': {
sh_log_byte('%');
break;
}
default:
sh_log_byte((sh_uint8)*p);
break;
}
}
va_end(args);
return SH_STATUS_SUCCESS;
}
SH_STATUS sh_log_payload(sh_log_OUTPUT_PAYLOAD *payload) {
if (payload==SH_NULLPTR) {
return SH_STATUS_INVALID_PARAMETER;
}
if (!(sh_log_output_type_valid(payload->output_type))) {
return SH_STATUS_INVALID_PARAMETER;
}
if (!(sh_log_output_source_valid(payload->output_source))) {
return SH_STATUS_INVALID_PARAMETER;
}
if (payload->output_source!=SH_LOG_SOURCE_TEST && payload->output_type<kernel_log_level) {
return SH_STATUS_SUCCESS;
}
sh_log_string("[Shelter:");
if (payload->output_source==SH_LOG_SOURCE_MAIN) {
sh_log_string("Main@");
} else if (payload->output_source==SH_LOG_SOURCE_CONF) {
sh_log_string("Conf@");
} else if (payload->output_source==SH_LOG_SOURCE_PAGE) {
sh_log_string("Page@");
} else if (payload->output_source==SH_LOG_SOURCE_SLAB) {
sh_log_string("Slab@");
} else if (payload->output_source==SH_LOG_SOURCE_TEST) {
sh_log_string("Test@");
} else if (payload->output_source==SH_LOG_SOURCE_PEZ) {
sh_log_string("Pez @");
} else if (payload->output_source==SH_LOG_SOURCE_PBA) {
sh_log_string("PBA @");
} else if (payload->output_source==SH_LOG_SOURCE_HEAP) {
sh_log_string("Heap@");
} else if (payload->output_source==SH_LOG_SOURCE_STD) {
sh_log_string("STD @");
}
if (payload->output_type==SH_LOG_DEBUG) {
sh_log_string("Debug] ");
} else if (payload->output_type==SH_LOG_LOG) {
sh_log_string("Log] ");
} else if (payload->output_type==SH_LOG_WARNING) {
sh_log_string("Warning] ");
} else if (payload->output_type==SH_LOG_ERROR) {
sh_log_string("Error] ");
} else if (payload->output_type==SH_LOG_CRITICAL) {
sh_log_string("Critical] ");
} else if (payload->output_type==SH_LOG_FATAL) {
sh_log_string("Fatal] ");
} else if (payload->output_type==SH_LOG_TEST) {
sh_log_string("Test] ");
}
sh_log_uint64(payload->tsc_value);
sh_log_string(" : ");
sh_log_string(payload->message_pointer);
return SH_STATUS_SUCCESS;
}
SH_STATUS sh_log_payload_format(sh_log_OUTPUT_PAYLOAD *payload,va_list args) {
if (payload==SH_NULLPTR) {
return SH_STATUS_INVALID_PARAMETER;
}
if (!(sh_log_output_type_valid(payload->output_type))) {
return SH_STATUS_INVALID_PARAMETER;
}
if (!(sh_log_output_source_valid(payload->output_source))) {
return SH_STATUS_INVALID_PARAMETER;
}
if (payload->output_source!=SH_LOG_SOURCE_TEST && payload->output_type<kernel_log_level) {
return SH_STATUS_SUCCESS;
}
sh_log_string("[Shelter:");
if (payload->output_source==SH_LOG_SOURCE_MAIN) {
sh_log_string("Main@");
} else if (payload->output_source==SH_LOG_SOURCE_CONF) {
sh_log_string("Conf@");
} else if (payload->output_source==SH_LOG_SOURCE_PAGE) {
sh_log_string("Page@");
} else if (payload->output_source==SH_LOG_SOURCE_SLAB) {
sh_log_string("Slab@");
} else if (payload->output_source==SH_LOG_SOURCE_TEST) {
sh_log_string("Test@");
} else if (payload->output_source==SH_LOG_SOURCE_PEZ) {
sh_log_string("Pez @");
} else if (payload->output_source==SH_LOG_SOURCE_PBA) {
sh_log_string("PBA @");
} else if (payload->output_source==SH_LOG_SOURCE_HEAP) {
sh_log_string("Heap@");
} else if (payload->output_source==SH_LOG_SOURCE_STD) {
sh_log_string("STD @");
}
if (payload->output_type==SH_LOG_DEBUG) {
sh_log_string("Debug] ");
} else if (payload->output_type==SH_LOG_LOG) {
sh_log_string("Log] ");
} else if (payload->output_type==SH_LOG_WARNING) {
sh_log_string("Warning] ");
} else if (payload->output_type==SH_LOG_ERROR) {
sh_log_string("Error] ");
} else if (payload->output_type==SH_LOG_CRITICAL) {
sh_log_string("Critical] ");
} else if (payload->output_type==SH_LOG_FATAL) {
sh_log_string("Fatal] ");
} else if (payload->output_type==SH_LOG_TEST) {
sh_log_string("Test] ");
}
sh_log_uint64(payload->tsc_value);
sh_log_string(" : ");
sh_log_format(payload->message_pointer,args);
return SH_STATUS_SUCCESS;
}
SH_STATUS sh_log_load_log_level(sh_uint8 log_level) {
kernel_log_level=log_level;
return SH_STATUS_SUCCESS;
}
sh_uint8 sh_log_get_log_level() {
return kernel_log_level;
}
SH_STATUS sh_log_test(const char* str) {
if (str==SH_NULLPTR) {
return SH_STATUS_INVALID_PARAMETER;
}
sh_log_OUTPUT_PAYLOAD payload={
.output_type=SH_LOG_TEST,
.output_source=SH_LOG_SOURCE_TEST,
.tsc_value=sh_tsc_get_kernel_current_tsc(),
.message_pointer=str
};
SH_STATUS status=sh_log_payload(&payload);
if (sh_status_error(status)) {
return status;
}
sh_log_string("\n");
return SH_STATUS_SUCCESS;
}
SH_STATUS sh_log_debug(const char* str,sh_log_OUTPUT_SOURCE source) {
if (str==SH_NULLPTR || !(sh_log_output_source_valid(source))) {
return SH_STATUS_INVALID_PARAMETER;
}
sh_log_OUTPUT_PAYLOAD payload={
.output_type=SH_LOG_DEBUG,
.output_source=source,
.tsc_value=sh_tsc_get_kernel_current_tsc(),
.message_pointer=str
};
SH_STATUS status=sh_log_payload(&payload);
if (sh_status_error(status)) {
return status;
}
sh_log_string("\n");
return SH_STATUS_SUCCESS;
}
SH_STATUS sh_log_log(const char* str,sh_log_OUTPUT_SOURCE source) {
if (str==SH_NULLPTR || !(sh_log_output_source_valid(source))) {
return SH_STATUS_INVALID_PARAMETER;
}
sh_log_OUTPUT_PAYLOAD payload={
.output_type=SH_LOG_LOG,
.output_source=source,
.tsc_value=sh_tsc_get_kernel_current_tsc(),
.message_pointer=str
};
SH_STATUS status=sh_log_payload(&payload);
if (sh_status_error(status)) {
return status;
}
sh_log_string("\n");
return SH_STATUS_SUCCESS;
}
SH_STATUS sh_log_warning(const char* str,sh_log_OUTPUT_SOURCE source) {
if (str==SH_NULLPTR || !(sh_log_output_source_valid(source))) {
return SH_STATUS_INVALID_PARAMETER;
}
sh_log_OUTPUT_PAYLOAD payload={
.output_type=SH_LOG_WARNING,
.output_source=source,
.tsc_value=sh_tsc_get_kernel_current_tsc(),
.message_pointer=str
};
SH_STATUS status=sh_log_payload(&payload);
if (sh_status_error(status)) {
return status;
}
sh_log_string("\n");
return SH_STATUS_SUCCESS;
}
SH_STATUS sh_log_error(const char* str,sh_log_OUTPUT_SOURCE source) {
if (str==SH_NULLPTR || !(sh_log_output_source_valid(source))) {
return SH_STATUS_INVALID_PARAMETER;
}
sh_log_OUTPUT_PAYLOAD payload={
.output_type=SH_LOG_ERROR,
.output_source=source,
.tsc_value=sh_tsc_get_kernel_current_tsc(),
.message_pointer=str
};
SH_STATUS status=sh_log_payload(&payload);
if (sh_status_error(status)) {
return status;
}
sh_log_string("\n");
return SH_STATUS_SUCCESS;
}
SH_STATUS sh_log_critical(const char* str,sh_log_OUTPUT_SOURCE source) {
if (str==SH_NULLPTR || !(sh_log_output_source_valid(source))) {
return SH_STATUS_INVALID_PARAMETER;
}
sh_log_OUTPUT_PAYLOAD payload={
.output_type=SH_LOG_CRITICAL,
.output_source=source,
.tsc_value=sh_tsc_get_kernel_current_tsc(),
.message_pointer=str
};
SH_STATUS status=sh_log_payload(&payload);
if (sh_status_error(status)) {
return status;
}
sh_log_string("\n");
return SH_STATUS_SUCCESS;
}
SH_STATUS sh_log_fatal(const char* str,sh_log_OUTPUT_SOURCE source) {
if (str==SH_NULLPTR || !(sh_log_output_source_valid(source))) {
return SH_STATUS_INVALID_PARAMETER;
}
sh_log_OUTPUT_PAYLOAD payload={
.output_type=SH_LOG_FATAL,
.output_source=source,
.tsc_value=sh_tsc_get_kernel_current_tsc(),
.message_pointer=str
};
SH_STATUS status=sh_log_payload(&payload);
if (sh_status_error(status)) {
return status;
}
sh_log_string("\n");
return SH_STATUS_SUCCESS;
}
SH_STATUS sh_log_ltest(const char* str) {
if (str==SH_NULLPTR) {
return SH_STATUS_INVALID_PARAMETER;
}
sh_log_OUTPUT_PAYLOAD payload={
.output_type=SH_LOG_TEST,
.output_source=SH_LOG_SOURCE_TEST,
.tsc_value=sh_tsc_get_kernel_current_tsc(),
.message_pointer=str
};
SH_STATUS status=sh_log_payload(&payload);
if (sh_status_error(status)) {
return status;
}
return SH_STATUS_SUCCESS;
}
SH_STATUS sh_log_ldebug(const char* str,sh_log_OUTPUT_SOURCE source) {
if (str==SH_NULLPTR || !(sh_log_output_source_valid(source))) {
return SH_STATUS_INVALID_PARAMETER;
}
sh_log_OUTPUT_PAYLOAD payload={
.output_type=SH_LOG_DEBUG,
.output_source=source,
.tsc_value=sh_tsc_get_kernel_current_tsc(),
.message_pointer=str
};
SH_STATUS status=sh_log_payload(&payload);
if (sh_status_error(status)) {
return status;
}
return SH_STATUS_SUCCESS;
}
SH_STATUS sh_log_llog(const char* str,sh_log_OUTPUT_SOURCE source) {
if (str==SH_NULLPTR || !(sh_log_output_source_valid(source))) {
return SH_STATUS_INVALID_PARAMETER;
}
sh_log_OUTPUT_PAYLOAD payload={
.output_type=SH_LOG_LOG,
.output_source=source,
.tsc_value=sh_tsc_get_kernel_current_tsc(),
.message_pointer=str
};
SH_STATUS status=sh_log_payload(&payload);
if (sh_status_error(status)) {
return status;
}
return SH_STATUS_SUCCESS;
}
SH_STATUS sh_log_lwarning(const char* str,sh_log_OUTPUT_SOURCE source) {
if (str==SH_NULLPTR || !(sh_log_output_source_valid(source))) {
return SH_STATUS_INVALID_PARAMETER;
}
sh_log_OUTPUT_PAYLOAD payload={
.output_type=SH_LOG_WARNING,
.output_source=source,
.tsc_value=sh_tsc_get_kernel_current_tsc(),
.message_pointer=str
};
SH_STATUS status=sh_log_payload(&payload);
if (sh_status_error(status)) {
return status;
}
return SH_STATUS_SUCCESS;
}
SH_STATUS sh_log_lerror(const char* str,sh_log_OUTPUT_SOURCE source) {
if (str==SH_NULLPTR || !(sh_log_output_source_valid(source))) {
return SH_STATUS_INVALID_PARAMETER;
}
sh_log_OUTPUT_PAYLOAD payload={
.output_type=SH_LOG_ERROR,
.output_source=source,
.tsc_value=sh_tsc_get_kernel_current_tsc(),
.message_pointer=str
};
SH_STATUS status=sh_log_payload(&payload);
if (sh_status_error(status)) {
return status;
}
return SH_STATUS_SUCCESS;
}
SH_STATUS sh_log_lcritical(const char* str,sh_log_OUTPUT_SOURCE source) {
if (str==SH_NULLPTR || !(sh_log_output_source_valid(source))) {
return SH_STATUS_INVALID_PARAMETER;
}
sh_log_OUTPUT_PAYLOAD payload={
.output_type=SH_LOG_CRITICAL,
.output_source=source,
.tsc_value=sh_tsc_get_kernel_current_tsc(),
.message_pointer=str
};
SH_STATUS status=sh_log_payload(&payload);
if (sh_status_error(status)) {
return status;
}
return SH_STATUS_SUCCESS;
}
SH_STATUS sh_log_lfatal(const char* str,sh_log_OUTPUT_SOURCE source) {
if (str==SH_NULLPTR || !(sh_log_output_source_valid(source))) {
return SH_STATUS_INVALID_PARAMETER;
}
sh_log_OUTPUT_PAYLOAD payload={
.output_type=SH_LOG_FATAL,
.output_source=source,
.tsc_value=sh_tsc_get_kernel_current_tsc(),
.message_pointer=str
};
SH_STATUS status=sh_log_payload(&payload);
if (sh_status_error(status)) {
return status;
}
return SH_STATUS_SUCCESS;
}
SH_STATUS sh_log_ftest(const char* format,...) {
if (format==SH_NULLPTR) {
return SH_STATUS_INVALID_PARAMETER;
}
sh_log_OUTPUT_PAYLOAD payload={
.output_type=SH_LOG_TEST,
.output_source=SH_LOG_SOURCE_TEST,
.tsc_value=sh_tsc_get_kernel_current_tsc(),
.message_pointer=format
};
va_list args;
va_start(args,format);
SH_STATUS status=sh_log_payload_format(&payload,args);
va_end(args);
if (sh_status_error(status)) {
return status;
}
return SH_STATUS_SUCCESS;
}
SH_STATUS sh_log_fdebug(const sh_log_OUTPUT_SOURCE source,const char* format,...) {
if (format==SH_NULLPTR || !(sh_log_output_source_valid(source))) {
return SH_STATUS_INVALID_PARAMETER;
}
sh_log_OUTPUT_PAYLOAD payload={
.output_type=SH_LOG_DEBUG,
.output_source=source,
.tsc_value=sh_tsc_get_kernel_current_tsc(),
.message_pointer=format
};
va_list args;
va_start(args,format);
SH_STATUS status=sh_log_payload_format(&payload,args);
va_end(args);
if (sh_status_error(status)) {
return status;
}
return SH_STATUS_SUCCESS;
}
SH_STATUS sh_log_flog(const sh_log_OUTPUT_SOURCE source,const char* format,...) {
if (format==SH_NULLPTR || !(sh_log_output_source_valid(source))) {
return SH_STATUS_INVALID_PARAMETER;
}
sh_log_OUTPUT_PAYLOAD payload={
.output_type=SH_LOG_LOG,
.output_source=source,
.tsc_value=sh_tsc_get_kernel_current_tsc(),
.message_pointer=format
};
va_list args;
va_start(args,format);
SH_STATUS status=sh_log_payload_format(&payload,args);
va_end(args);
if (sh_status_error(status)) {
return status;
}
return SH_STATUS_SUCCESS;
}
SH_STATUS sh_log_fwarning(const sh_log_OUTPUT_SOURCE source,const char* format,...) {
if (format==SH_NULLPTR || !(sh_log_output_source_valid(source))) {
return SH_STATUS_INVALID_PARAMETER;
}
sh_log_OUTPUT_PAYLOAD payload={
.output_type=SH_LOG_WARNING,
.output_source=source,
.tsc_value=sh_tsc_get_kernel_current_tsc(),
.message_pointer=format
};
va_list args;
va_start(args,format);
SH_STATUS status=sh_log_payload_format(&payload,args);
va_end(args);
if (sh_status_error(status)) {
return status;
}
return SH_STATUS_SUCCESS;
}
SH_STATUS sh_log_ferror(const sh_log_OUTPUT_SOURCE source,const char* format,...) {
if (format==SH_NULLPTR || !(sh_log_output_source_valid(source))) {
return SH_STATUS_INVALID_PARAMETER;
}
sh_log_OUTPUT_PAYLOAD payload={
.output_type=SH_LOG_ERROR,
.output_source=source,
.tsc_value=sh_tsc_get_kernel_current_tsc(),
.message_pointer=format
};
va_list args;
va_start(args,format);
SH_STATUS status=sh_log_payload_format(&payload,args);
va_end(args);
if (sh_status_error(status)) {
return status;
}
return SH_STATUS_SUCCESS;
}
SH_STATUS sh_log_fcritical(const sh_log_OUTPUT_SOURCE source,const char* format,...) {
if (format==SH_NULLPTR || !(sh_log_output_source_valid(source))) {
return SH_STATUS_INVALID_PARAMETER;
}
sh_log_OUTPUT_PAYLOAD payload={
.output_type=SH_LOG_CRITICAL,
.output_source=source,
.tsc_value=sh_tsc_get_kernel_current_tsc(),
.message_pointer=format
};
va_list args;
va_start(args,format);
SH_STATUS status=sh_log_payload_format(&payload,args);
va_end(args);
if (sh_status_error(status)) {
return status;
}
return SH_STATUS_SUCCESS;
}
SH_STATUS sh_log_ffatal(const sh_log_OUTPUT_SOURCE source,const char* format,...) {
if (format==SH_NULLPTR || !(sh_log_output_source_valid(source))) {
return SH_STATUS_INVALID_PARAMETER;
}
sh_log_OUTPUT_PAYLOAD payload={
.output_type=SH_LOG_FATAL,
.output_source=source,
.tsc_value=sh_tsc_get_kernel_current_tsc(),
.message_pointer=format
};
va_list args;
va_start(args,format);
SH_STATUS status=sh_log_payload_format(&payload,args);
va_end(args);
if (sh_status_error(status)) {
return status;
}
return SH_STATUS_SUCCESS;
}
SH_STATUS sh_log_mem_stats(sh_log_OUTPUT_SOURCE source) {
sh_page_MEM_STATS mem_stats;
sh_page_get_memory_stats(&mem_stats);
sh_log_flog(source,"Total physical memory (bytes) : %8u / 0x%8U\n",mem_stats.memory_total_bytes,mem_stats.memory_total_bytes);
sh_log_flog(source,"Total physical memory (pages) : %8u / 0x%8U\n",mem_stats.memory_total_pages,mem_stats.memory_total_pages);
sh_log_flog(source,"Total installed memory (bytes) : %8u / 0x%8U\n",mem_stats.memory_installed_bytes,mem_stats.memory_installed_bytes);
sh_log_flog(source,"Total installed memory (pages) : %8u / 0x%8U\n",mem_stats.memory_installed_pages,mem_stats.memory_installed_pages);
sh_log_flog(source,"Free memory : %d%%\n",mem_stats.free_ratio*100);
sh_log_flog(source,"Used memory : %d%%\n",mem_stats.used_ratio*100);
sh_log_flog(source,"Free pages : %8u\n",mem_stats.free_pages);
sh_log_flog(source,"Used pages : %8u\n",mem_stats.used_pages);
sh_log_flog(source,"Largest free block (pages) : %8u\n",mem_stats.largest_free_block);
sh_log_flog(source,"Largest used block (pages) : %8u\n",mem_stats.largest_used_block);
sh_log_flog(source,"Free block count : %8u\n",mem_stats.free_blocks_count);
sh_log_flog(source,"Used block count : %8u\n",mem_stats.used_blocks_count);
sh_log_flog(source,"Total memory taken by physical bitmap (bytes) : %8u / 0x%8U\n",mem_stats.physical_bitmap_size_bytes,mem_stats.physical_bitmap_size_bytes);
sh_log_flog(source,"Total memory taken by physical bitmap (pages) : %8u / 0x%8U\n",mem_stats.physical_bitmap_size_pages,mem_stats.physical_bitmap_size_pages);
return SH_STATUS_SUCCESS;
}

View File

@@ -0,0 +1,92 @@
// SPDX-License-Identifier: MPL-2.0
#include "kernel/tests/test_malloc.h"
#include "kernel/tests/test_utils.h"
#include "kernel/tests/payloads/test_malloc_payload.h"
#include "kernel/log.h"
#include "memory/page.h"
#include "memory/heap.h"
#include "std/mem.h"
#include "std/malloc.h"
static sh_uint64 iter_num=10000;
__attribute__((section(".bss")))
static sh_uint64 address_list[10000];
SH_STATUS sh_test_malloc_benchmark() {
sh_tsc_TSC_VALUE *tsc_value=sh_test_get_tsc_values_buffer_ptr();
sh_mem_set_8((sh_uint8*)tsc_value,0x00,10000*sizeof(sh_tsc_TSC_VALUE));
sh_mem_set_8((sh_uint8*)address_list,0x00,sizeof(address_list));
sh_log_test("Benchmarking Malloc subsystem...");
sh_tsc_TSC_VALUE start=0;
sh_tsc_TSC_VALUE end=0;
for (sh_iter64 i=0;i<iter_num;i++) {
start=sh_tsc_get_kernel_current_tsc();
address_list[i]=(sh_uint64)sh_malloc(test_malloc_small_size[i]);
end=sh_tsc_get_kernel_current_tsc();
tsc_value[i]=end-start;
if (sh_malloc_get_last_status()!=SH_STATUS_SUCCESS) {
sh_log_error("Test failed for sh_malloc for small size. See detail below:",SH_LOG_SOURCE_TEST);
sh_log_ferror(SH_LOG_SOURCE_TEST,"Error code: %8s\n",sh_malloc_get_last_status());
sh_log_ferror(SH_LOG_SOURCE_TEST,"Index: %8u\n",i);
sh_log_ferror(SH_LOG_SOURCE_TEST,"Size: %4u\n",test_malloc_small_size[i]);
return SH_STATUS_TEST_FAILED;
}
}
sh_test_compute_print_stats("sh_malloc for small size",tsc_value,iter_num);
sh_mem_set_8((sh_uint8*)tsc_value,0x00,10000*sizeof(sh_tsc_TSC_VALUE));
for (sh_iter64 i=0;i<iter_num;i++) {
start=sh_tsc_get_kernel_current_tsc();
sh_free((void*)address_list[i]);
end=sh_tsc_get_kernel_current_tsc();
tsc_value[i]=end-start;
if (sh_malloc_get_last_status()!=SH_STATUS_SUCCESS) {
sh_log_error("Test failed for sh_free for small size. See detail below:",SH_LOG_SOURCE_TEST);
sh_log_ferror(SH_LOG_SOURCE_TEST,"Error code: %8s\n",sh_malloc_get_last_status());
sh_log_ferror(SH_LOG_SOURCE_TEST,"Index: %8u\n",i);
sh_log_ferror(SH_LOG_SOURCE_TEST,"Size: %4u\n",test_malloc_small_size[i]);
return SH_STATUS_TEST_FAILED;
}
}
sh_test_compute_print_stats("sh_free for small size",tsc_value,iter_num);
sh_mem_set_8((sh_uint8*)tsc_value,0x00,10000*sizeof(sh_tsc_TSC_VALUE));
sh_mem_set_8((sh_uint8*)address_list,0x00,sizeof(address_list));
sh_uint16 alloc_count=0;
sh_uint16 free_count=1000;
for (sh_iter64 i=0;i<2000;i++) {
sh_uint64 alloc_num=test_malloc_big_alloc[i];
sh_uint64 alloc_size=test_malloc_big_size[alloc_num]*SH_PAGE_SIZE;
if (address_list[alloc_num]==0) {
start=sh_tsc_get_kernel_current_tsc();
address_list[alloc_num]=(sh_uint64)sh_malloc(alloc_size);
end=sh_tsc_get_kernel_current_tsc();
tsc_value[alloc_count]=end-start;
alloc_count++;
if (sh_malloc_get_last_status()!=SH_STATUS_SUCCESS) {
sh_log_error("Test failed for sh_malloc for big size. See detail below:",SH_LOG_SOURCE_TEST);
sh_log_ferror(SH_LOG_SOURCE_TEST,"Error code: %8s\n",sh_malloc_get_last_status());
sh_log_ferror(SH_LOG_SOURCE_TEST,"Index: %8u\n",i);
sh_log_ferror(SH_LOG_SOURCE_TEST,"Size: %8u\n",alloc_size);
sh_log_ferror(SH_LOG_SOURCE_TEST,"Alloc Num: %8u\n",alloc_num);
sh_log_mem_stats(SH_LOG_SOURCE_TEST);
return SH_STATUS_TEST_FAILED;
}
} else {
start=sh_tsc_get_kernel_current_tsc();
sh_free((void*)address_list[alloc_num]);
end=sh_tsc_get_kernel_current_tsc();
tsc_value[free_count]=end-start;
free_count++;
if (sh_malloc_get_last_status()!=SH_STATUS_SUCCESS) {
sh_log_error("Test failed for sh_free for big size. See detail below:",SH_LOG_SOURCE_TEST);
sh_log_ferror(SH_LOG_SOURCE_TEST,"Error code: %8s\n",sh_malloc_get_last_status());
sh_log_ferror(SH_LOG_SOURCE_TEST,"Index: %8u\n",i);
sh_log_ferror(SH_LOG_SOURCE_TEST,"Size: %8u\n",alloc_size);
sh_log_ferror(SH_LOG_SOURCE_TEST,"Alloc Num: %8u\n",alloc_num);
sh_log_mem_stats(SH_LOG_SOURCE_TEST);
return SH_STATUS_TEST_FAILED;
}
}
}
sh_test_compute_print_stats("sh_malloc for pages allocations",tsc_value,alloc_count);
sh_test_compute_print_stats("sh_free for pages allocations",tsc_value+1000,free_count-1000);
sh_log_mem_stats(SH_LOG_SOURCE_TEST);
return SH_STATUS_SUCCESS;
}

View File

@@ -0,0 +1,77 @@
// SPDX-License-Identifier: MPL-2.0
#include "kernel/tests/test_pez.h"
#include "kernel/tests/test_utils.h"
#include "kernel/tests/payloads/test_pez_payload.h"
#include "kernel/log.h"
#include "memory/page.h"
#include "std/mem.h"
static sh_uint64 iter_num=4000;
__attribute__((section(".bss")))
static sh_page_PHYSICAL_ADDRESS address_list[2000];
SH_STATUS sh_test_pez_benchmark_physical(sh_pez_PHYSICAL_PLANE *phys_plane) {
if (phys_plane==SH_NULLPTR) return SH_STATUS_INVALID_PARAMETER;
sh_tsc_TSC_VALUE *tsc_value=sh_test_get_tsc_values_buffer_ptr();
sh_mem_set_8((sh_uint8*)tsc_value,0x00,SH_TEST_PEZ_TOTAL_TSC_TIME_COUNT*sizeof(sh_tsc_TSC_VALUE));
sh_mem_set_8((sh_uint8*)address_list,0x00,sizeof(address_list));
sh_log_test("Benchmarking Pez physical plane...");
sh_tsc_TSC_VALUE start=0;
sh_tsc_TSC_VALUE end=0;
sh_uint16 alloc_single_count=0;
sh_uint16 unalloc_single_count=1000;
sh_uint16 alloc_multiple_count=2000;
sh_uint16 unalloc_multiple_count=3000;
SH_STATUS status;
for (sh_iter64 i=0;i<iter_num;i++) {
sh_uint64 alloc_num=test_pez_physical_alloc[i];
sh_uint64 alloc_size=test_pez_physical_size[alloc_num];
if (address_list[alloc_num]==0) {
sh_page_PHYSICAL_ADDRESS address;
start=sh_tsc_get_kernel_current_tsc();
status=sh_pez_alloc_physical_pages(phys_plane,(sh_uint32)alloc_size,&address);
end=sh_tsc_get_kernel_current_tsc();
if (alloc_size==1) {
tsc_value[alloc_single_count]=end-start;
alloc_single_count++;
} else {
tsc_value[alloc_multiple_count]=end-start;
alloc_multiple_count++;
}
if (status!=SH_STATUS_SUCCESS) {
sh_log_error("Test failed for allocation on Pez physical plane. See detail below:",SH_LOG_SOURCE_TEST);
sh_log_ferror(SH_LOG_SOURCE_TEST,"Error code: %8s\n",status);
sh_log_ferror(SH_LOG_SOURCE_TEST,"Index: %8u\n",i);
sh_log_ferror(SH_LOG_SOURCE_TEST,"Size: %8u\n",alloc_size);
sh_log_ferror(SH_LOG_SOURCE_TEST,"Alloc Num: %8u\n",alloc_num);
sh_pez_debug_physical(phys_plane);
return SH_STATUS_TEST_FAILED;
} else {
address_list[alloc_num]=address;
}
} else {
start=sh_tsc_get_kernel_current_tsc();
status=sh_pez_free_physical_pages(phys_plane,&address_list[alloc_num],(sh_uint32)alloc_size);
end=sh_tsc_get_kernel_current_tsc();
if (alloc_size==1) {
tsc_value[unalloc_single_count]=end-start;
unalloc_single_count++;
} else {
tsc_value[unalloc_multiple_count]=end-start;
unalloc_multiple_count++;
}
if (status!=SH_STATUS_SUCCESS) {
sh_log_error("Test failed for free on Pez physical plane. See detail below:",SH_LOG_SOURCE_TEST);
sh_log_ferror(SH_LOG_SOURCE_TEST,"Error code: %8s\n",status);
sh_log_ferror(SH_LOG_SOURCE_TEST,"Index: %8u\n",i);
sh_log_ferror(SH_LOG_SOURCE_TEST,"Size: %8u\n",alloc_size);
sh_log_ferror(SH_LOG_SOURCE_TEST,"Alloc Num: %8u\n",alloc_num);
sh_pez_debug_physical(phys_plane);
return SH_STATUS_TEST_FAILED;
}
}
}
sh_test_compute_print_stats("allocations for single page",tsc_value,alloc_single_count);
sh_test_compute_print_stats("free for single page",tsc_value+1000,unalloc_single_count-1000);
sh_test_compute_print_stats("allocations for multiple pages",tsc_value+2000,alloc_multiple_count-2000);
sh_test_compute_print_stats("free for multiple pages",tsc_value+3000,unalloc_multiple_count-3000);
return SH_STATUS_SUCCESS;
}

View File

@@ -0,0 +1,92 @@
// SPDX-License-Identifier: MPL-2.0
#include "kernel/tests/test_radix.h"
#include "kernel/tests/test_utils.h"
#include "kernel/tests/payloads/test_radix_payload.h"
#include "kernel/log.h"
#include "std/mem.h"
static sh_uint64 iter_num=10000;
void sh_test_radix_load_iterations_count(sh_uint64 iterations_num) {
iter_num=iterations_num;
return;
}
SH_STATUS sh_test_radix_benchmark(struct sh_slab_radix_node_SLAB_ALLOCATOR *alloc,sh_page_PAGE_TABLE_POOL *ptp) {
if (alloc==SH_NULLPTR || ptp==SH_NULLPTR) return SH_STATUS_INVALID_PARAMETER;
sh_tsc_TSC_VALUE *tsc_value=sh_test_get_tsc_values_buffer_ptr();
sh_mem_set_8((sh_uint8*)tsc_value,0x00,iter_num);
sh_log_test("Benchmarking radix trees subsystem...");
sh_radix_TREE tree;
SH_STATUS status=sh_radix_tree_init(alloc,ptp,&tree,16);
if (status!=SH_STATUS_SUCCESS) {
sh_log_error("Test failed for initialization of a 16-deep radix tree. See detail below:",SH_LOG_SOURCE_TEST);
sh_log_ferror(SH_LOG_SOURCE_TEST,"Error code: %8s\n",status);
return SH_STATUS_TEST_FAILED;
}
sh_tsc_TSC_VALUE start=0;
sh_tsc_TSC_VALUE end=0;
for (sh_iter64 i=0;i<iter_num;i++) {
start=sh_tsc_get_kernel_current_tsc();
status=sh_radix_tree_insert_value(alloc,ptp,&tree,test_keys[i],test_values[i]);
end=sh_tsc_get_kernel_current_tsc();
tsc_value[i]=end-start;
if (status!=SH_STATUS_SUCCESS) {
sh_log_error("Test failed for insertion into radix tree. See detail below:",SH_LOG_SOURCE_TEST);
sh_log_ferror(SH_LOG_SOURCE_TEST,"Error code: %8s\n",status);
sh_log_ferror(SH_LOG_SOURCE_TEST,"Index: %8u\n",i);
return SH_STATUS_TEST_FAILED;
}
}
sh_test_compute_print_stats("insertions into radix trees",tsc_value,iter_num);
sh_mem_set_8((sh_uint8*)tsc_value,0x00,iter_num);
for (sh_iter64 i=0;i<iter_num;i++) {
sh_page_VIRTUAL_ADDRESS temp;
start=sh_tsc_get_kernel_current_tsc();
status=sh_radix_tree_get_value(&tree,test_keys[i],&temp);
end=sh_tsc_get_kernel_current_tsc();
tsc_value[i]=end-start;
if (status!=SH_STATUS_SUCCESS) {
sh_log_error("Test failed at status level for reading into radix tree. See detail below:",SH_LOG_SOURCE_TEST);
sh_log_ferror(SH_LOG_SOURCE_TEST,"Error code: %8s\n",status);
sh_log_ferror(SH_LOG_SOURCE_TEST,"Index: %8u\n",i);
return SH_STATUS_TEST_FAILED;
}
if (temp!=test_values[i]) {
sh_log_error("Test failed at value level for reading into radix tree. See detail below:",SH_LOG_SOURCE_TEST);
sh_log_ferror(SH_LOG_SOURCE_TEST,"Index: %8u\n",i);
sh_log_ferror(SH_LOG_SOURCE_TEST,"Key: %x\n",test_keys[i]);
sh_log_ferror(SH_LOG_SOURCE_TEST,"Expected value: %x\n",test_values[i]);
sh_log_ferror(SH_LOG_SOURCE_TEST,"Obtained value: %x\n",temp);
return SH_STATUS_TEST_FAILED;
}
}
sh_test_compute_print_stats("reading into radix trees",tsc_value,iter_num);
sh_mem_set_8((sh_uint8*)tsc_value,0x00,iter_num);
for (sh_iter64 i=0;i<iter_num;i++) {
sh_page_VIRTUAL_ADDRESS temp;
start=sh_tsc_get_kernel_current_tsc();
status=sh_radix_tree_search_smallest_min_bound(alloc,&tree,test_search[i],&temp);
end=sh_tsc_get_kernel_current_tsc();
tsc_value[i]=end-start;
if (status!=SH_STATUS_SUCCESS && status!=SH_STATUS_NOT_FOUND) {
sh_log_error("Test failed for searching value with lower bound key into radix tree. See detail below:",SH_LOG_SOURCE_TEST);
sh_log_ferror(SH_LOG_SOURCE_TEST,"Error code: %8s\n",status);
sh_log_ferror(SH_LOG_SOURCE_TEST,"Index: %8u\n",i);
return SH_STATUS_TEST_FAILED;
}
}
sh_test_compute_print_stats("searching value with lower bound key",tsc_value,iter_num);
sh_mem_set_8((sh_uint8*)tsc_value,0x00,iter_num);
for (sh_iter64 i=0;i<iter_num;i++) {
start=sh_tsc_get_kernel_current_tsc();
status=sh_radix_tree_delete_value(alloc,&tree,test_keys[i]);
end=sh_tsc_get_kernel_current_tsc();
tsc_value[i]=end-start;
if (status!=SH_STATUS_SUCCESS) {
sh_log_error("Test failed for deleting value from radix tree. See detail below:",SH_LOG_SOURCE_TEST);
sh_log_ferror(SH_LOG_SOURCE_TEST,"Error code: %8s\n",status);
sh_log_ferror(SH_LOG_SOURCE_TEST,"Index: %8u\n",i);
return SH_STATUS_TEST_FAILED;
}
}
sh_test_compute_print_stats("deleting values",tsc_value,iter_num);
return SH_STATUS_SUCCESS;
}

View File

@@ -0,0 +1,147 @@
// SPDX-License-Identifier: MPL-2.0
#include "kernel/tests/test_slabs.h"
#include "kernel/tests/test_utils.h"
#include "kernel/log.h"
#include "std/mem.h"
static sh_uint64 iter_num=10000;
__attribute__((section(".bss")))
static sh_uint32 indexs[10000];
__attribute__((section(".bss")))
static sh_uint64 ptrs[10000];
void sh_test_slabs_load_iterations_count(sh_uint64 iterations_num) {
iter_num=iterations_num;
return;
}
SH_STATUS sh_test_slabs_benchmark_region_physical(sh_slab_reg_phys_SLAB_ALLOCATOR *alloc,sh_page_PAGE_TABLE_POOL *ptp) {
if (alloc==SH_NULLPTR || ptp==SH_NULLPTR) return SH_STATUS_INVALID_PARAMETER;
sh_tsc_TSC_VALUE *tsc_value=sh_test_get_tsc_values_buffer_ptr();
sh_mem_set_8((sh_uint8*)tsc_value,0x00,sizeof(indexs));
sh_mem_set_8((sh_uint8*)indexs,0x00,sizeof(indexs));
sh_log_test("Benchmarking slab allocator for physical objects region...");
sh_tsc_TSC_VALUE start=0;
sh_tsc_TSC_VALUE end=0;
SH_STATUS status;
for (sh_iter64 i=0;i<iter_num;i++) {
sh_slab_reg_phys_OBJECT_INDEX reg_idx;
start=sh_tsc_get_kernel_current_tsc();
status=sh_slab_reg_phys_alloc(alloc,ptp,&reg_idx);
end=sh_tsc_get_kernel_current_tsc();
tsc_value[i]=end-start;
if (status!=SH_STATUS_SUCCESS) {
sh_log_error("Test failed for allocation on physical region objects slab allocator. See detail below:",SH_LOG_SOURCE_TEST);
sh_log_ferror(SH_LOG_SOURCE_TEST,"Error code: %8s\n",status);
sh_log_ferror(SH_LOG_SOURCE_TEST,"Index: %8u\n",i);
return SH_STATUS_TEST_FAILED;
} else {
indexs[i]=reg_idx;
}
}
sh_test_compute_print_stats("allocations",tsc_value,iter_num);
sh_mem_set_8((sh_uint8*)tsc_value,0x00,sizeof(indexs));
for (sh_iter64 i=0;i<iter_num;i++) {
start=sh_tsc_get_kernel_current_tsc();
status=sh_slab_reg_phys_dealloc(alloc,indexs[i]);
end=sh_tsc_get_kernel_current_tsc();
tsc_value[i]=end-start;
if (status!=SH_STATUS_SUCCESS) {
sh_log_error("Test failed for deallocation on physical region objects slab allocator. See detail below:",SH_LOG_SOURCE_TEST);
sh_log_ferror(SH_LOG_SOURCE_TEST,"Error code: %8s\n",status);
sh_log_ferror(SH_LOG_SOURCE_TEST,"Index: %8u\n",i);
return SH_STATUS_TEST_FAILED;
}
}
sh_test_compute_print_stats("deallocations",tsc_value,iter_num);
return SH_STATUS_SUCCESS;
}
SH_STATUS sh_test_slabs_benchmark_region_virtual(sh_slab_reg_virt_SLAB_ALLOCATOR *alloc,sh_page_PAGE_TABLE_POOL *ptp) {
if (alloc==SH_NULLPTR || ptp==SH_NULLPTR) return SH_STATUS_INVALID_PARAMETER;
sh_tsc_TSC_VALUE *tsc_value=sh_test_get_tsc_values_buffer_ptr();
sh_mem_set_8((sh_uint8*)tsc_value,0x00,sizeof(indexs));
sh_mem_set_8((sh_uint8*)indexs,0x00,sizeof(indexs));
sh_log_test("Benchmarking slab allocator for virtual objects region...");
sh_tsc_TSC_VALUE start=0;
sh_tsc_TSC_VALUE end=0;
SH_STATUS status;
for (sh_iter64 i=0;i<iter_num;i++) {
sh_slab_reg_virt_OBJECT_INDEX reg_idx;
start=sh_tsc_get_kernel_current_tsc();
status=sh_slab_reg_virt_alloc(alloc,ptp,&reg_idx);
end=sh_tsc_get_kernel_current_tsc();
tsc_value[i]=end-start;
if (status!=SH_STATUS_SUCCESS) {
sh_log_error("Test failed for allocation on virtual region objects slab allocator. See detail below:",SH_LOG_SOURCE_TEST);
sh_log_ferror(SH_LOG_SOURCE_TEST,"Error code: %8s\n",status);
sh_log_ferror(SH_LOG_SOURCE_TEST,"Index: %8u\n",i);
return SH_STATUS_TEST_FAILED;
} else {
indexs[i]=reg_idx;
}
}
sh_test_compute_print_stats("allocations",tsc_value,iter_num);
sh_mem_set_8((sh_uint8*)tsc_value,0x00,sizeof(indexs));
for (sh_iter64 i=0;i<iter_num;i++) {
start=sh_tsc_get_kernel_current_tsc();
status=sh_slab_reg_virt_dealloc(alloc,indexs[i]);
end=sh_tsc_get_kernel_current_tsc();
tsc_value[i]=end-start;
if (status!=SH_STATUS_SUCCESS) {
sh_log_error("Test failed for deallocation on virtual region objects slab allocator. See detail below:",SH_LOG_SOURCE_TEST);
sh_log_ferror(SH_LOG_SOURCE_TEST,"Error code: %8s\n",status);
sh_log_ferror(SH_LOG_SOURCE_TEST,"Index: %8u\n",i);
return SH_STATUS_TEST_FAILED;
}
}
sh_test_compute_print_stats("deallocations",tsc_value,iter_num);
return SH_STATUS_SUCCESS;
}
SH_STATUS sh_test_slabs_benchmark_radix_node(struct sh_slab_radix_node_SLAB_ALLOCATOR *alloc,sh_page_PAGE_TABLE_POOL *ptp) {
if (alloc==SH_NULLPTR || ptp==SH_NULLPTR) return SH_STATUS_INVALID_PARAMETER;
sh_tsc_TSC_VALUE *tsc_value=sh_test_get_tsc_values_buffer_ptr();
sh_mem_set_8((sh_uint8*)tsc_value,0x00,sizeof(indexs));
sh_mem_set_8((sh_uint8*)ptrs,0x00,sizeof(indexs));
sh_log_test("Benchmarking slab allocator for radix nodes objects...");
sh_tsc_TSC_VALUE start=0;
sh_tsc_TSC_VALUE end=0;
SH_STATUS status;
for (sh_iter64 i=0;i<iter_num;i++) {
sh_radix_NODE *node_ptr;
start=sh_tsc_get_kernel_current_tsc();
status=sh_slab_radix_node_alloc(alloc,ptp,&node_ptr);
end=sh_tsc_get_kernel_current_tsc();
tsc_value[i]=end-start;
if (status!=SH_STATUS_SUCCESS) {
sh_log_error("Test failed for allocation on radix nodes slab allocator. See detail below:",SH_LOG_SOURCE_TEST);
sh_log_ferror(SH_LOG_SOURCE_TEST,"Error code: %8s\n",status);
sh_log_ferror(SH_LOG_SOURCE_TEST,"Index: %8u\n",i);
return SH_STATUS_TEST_FAILED;
} else {
ptrs[i]=(sh_uint64)node_ptr;
}
}
sh_test_compute_print_stats("allocations",tsc_value,iter_num);
sh_mem_set_8((sh_uint8*)tsc_value,0x00,sizeof(indexs));
for (sh_iter64 i=0;i<iter_num;i++) {
start=sh_tsc_get_kernel_current_tsc();
status=sh_slab_radix_node_dealloc(alloc,(sh_radix_NODE*)ptrs[i]);
end=sh_tsc_get_kernel_current_tsc();
tsc_value[i]=end-start;
if (status!=SH_STATUS_SUCCESS) {
sh_log_error("Test failed for deallocation on radix nodes slab allocator. See detail below:",SH_LOG_SOURCE_TEST);
sh_log_ferror(SH_LOG_SOURCE_TEST,"Error code: %8s\n",status);
sh_log_ferror(SH_LOG_SOURCE_TEST,"Index: %8u\n",i);
return SH_STATUS_TEST_FAILED;
}
}
sh_test_compute_print_stats("deallocations",tsc_value,iter_num);
return SH_STATUS_SUCCESS;
}
SH_STATUS sh_test_slabs_benchmark(sh_slab_reg_phys_SLAB_ALLOCATOR *alloc_reg_phys,sh_slab_reg_virt_SLAB_ALLOCATOR *alloc_reg_virt,struct sh_slab_radix_node_SLAB_ALLOCATOR *alloc_radix_node,sh_page_PAGE_TABLE_POOL *ptp) {
if (alloc_reg_phys==SH_NULLPTR || alloc_reg_virt==SH_NULLPTR || alloc_radix_node==SH_NULLPTR) return SH_STATUS_INVALID_PARAMETER;
SH_STATUS status=sh_test_slabs_benchmark_region_physical(alloc_reg_phys,ptp);
if (sh_status_error(status)) return status;
status=sh_test_slabs_benchmark_region_virtual(alloc_reg_virt,ptp);
if (sh_status_error(status)) return status;
status=sh_test_slabs_benchmark_radix_node(alloc_radix_node,ptp);
if (sh_status_error(status)) return status;
return SH_STATUS_SUCCESS;
}

View File

@@ -0,0 +1,59 @@
// SPDX-License-Identifier: MPL-2.0
#include "kernel/tests/test_utils.h"
#include "kernel/tests/test_slabs.h"
#include "kernel/tests/test_radix.h"
#include "kernel/log.h"
__attribute__((section(".bss")))
static sh_tsc_TSC_VALUE tsc_value[10000];
static void sort(sh_tsc_TSC_VALUE *array,sh_uint64 n) {
for (sh_iter64 i=1;i<n;i++) {
sh_tsc_TSC_VALUE key=array[i];
sh_uint64 j=i;
while (j>0 && array[j-1]>key) {
array[j]=array[j-1];
j--;
}
array[j]=key;
}
}
static sh_tsc_TSC_VALUE percentile(sh_tsc_TSC_VALUE *array,sh_uint64 n,sh_uint8 p) {
sh_uint64 idx=(n*p)/100;
if (idx>=n) idx=n-1;
return array[idx];
}
SH_STATUS sh_test_compute_print_stats(char* benchname,sh_tsc_TSC_VALUE *tsc_value_array,sh_uint64 array_size) {
if (tsc_value_array==SH_NULLPTR || array_size==0) return SH_STATUS_INVALID_PARAMETER;
sort(tsc_value_array,array_size);
sh_uint64 min=tsc_value_array[0];
sh_uint64 max=tsc_value_array[array_size-1];
sh_uint64 median=tsc_value_array[array_size/2];
sh_uint64 sum=0;
for(sh_iter64 i=0;i<array_size;i++) sum+=tsc_value_array[i];
sh_uint64 avrg=sum/array_size;
sh_log_test("");
sh_log_ftest("Result for benchmark \"%s\" :\n",benchname);
sh_log_ftest("Min: %8u | Med: %8u | Avg: %8u | Max: %8u | Total : %8u (TSC)\n",min,median,avrg,max,sum);
sh_uint64 p90=percentile(tsc_value_array,array_size,90);
sh_uint64 p99=percentile(tsc_value_array,array_size,99);
const char* labels[]={"[P00-P90]","[P90-P99]","[P99-Max]"};
sh_uint64 bounds[]={min,p90,p99,max};
sh_uint64 counts[]={90,9,1};
for (int i=0;i<3;i++) {
char bar[21];
sh_uint64 fill=(counts[i]*20)/100;
sh_uint64 j=0;
for (;j<fill;j++) bar[j]='#';
for (;j<20;j++) bar[j]='-';
bar[20]='\0';
sh_log_ftest("%s %8u-%8u : [%s] %8u%%\n",labels[i],bounds[i],bounds[i+1],bar,counts[i]);
}
return SH_STATUS_SUCCESS;
}
void sh_test_load_iterations_count(sh_uint64 iterations_num) {
sh_test_slabs_load_iterations_count(iterations_num);
sh_test_radix_load_iterations_count(iterations_num);
return;
}
sh_tsc_TSC_VALUE* sh_test_get_tsc_values_buffer_ptr() {
return &tsc_value[0];
}

View File

@@ -0,0 +1,95 @@
// SPDX-License-Identifier: MPL-2.0
#include "memory/heap.h"
#include "kernel/log.h"
#include "memory/vmem_layout.h"
static sh_heap_KERNEL_HEAP *default_heap=SH_NULLPTR;
void sh_heap_load_default_heap(sh_heap_KERNEL_HEAP *heap) {
default_heap=heap;
}
sh_heap_KERNEL_HEAP *sh_heap_get_default_heap() {
return default_heap;
}
SH_STATUS sh_heap_init_heap(sh_pez_PHYSICAL_PLANE *phys_plane,sh_pez_VIRTUAL_PLANE *virt_plane,sh_page_PAGE_TABLE_POOL *kernel_ptp,sh_heap_KERNEL_HEAP *kernel_heap) {
if (phys_plane==SH_NULLPTR || virt_plane==SH_NULLPTR || kernel_ptp==SH_NULLPTR || kernel_heap==SH_NULLPTR) return SH_STATUS_INVALID_PARAMETER;
kernel_heap->phys_plane=phys_plane;
kernel_heap->virt_plane=virt_plane;
kernel_heap->kernel_ptp=kernel_ptp;
SH_STATUS status=sh_radix_tree_init(phys_plane->slab_radix_node,kernel_ptp,&kernel_heap->alloc_size_tree,8);
if (sh_status_error(status)) return status;
return SH_STATUS_SUCCESS;
}
static void sh_heap_internal_crash(const char *str,SH_STATUS status) {
sh_log_ffatal(SH_LOG_SOURCE_HEAP,str,status);
sh_log_mem_stats(SH_LOG_SOURCE_HEAP);
while (SH_TRUE) {};
return;
}
SH_STATUS sh_heap_allocate_pages(sh_uint32 pages_count,sh_page_VIRTUAL_ADDRESS *address) {
if (pages_count==0 || address==SH_NULLPTR) return SH_STATUS_INVALID_PARAMETER;
if (default_heap==SH_NULLPTR) return SH_STATUS_HEAP_NOT_INITIALIZED;
sh_page_PHYSICAL_ADDRESS pa;
SH_STATUS status=sh_pez_alloc_physical_pages(default_heap->phys_plane,pages_count,&pa);
if (sh_status_error(status)) return status;
sh_page_PHYSICAL_ADDRESS va;
status=sh_pez_alloc_virtual_pages(default_heap->virt_plane,pages_count,&va);
if (sh_status_error(status)) {
status=sh_pez_free_physical_pages(default_heap->phys_plane,&pa,pages_count);
if (sh_status_error(status)) sh_heap_internal_crash("Heap alloc error: couldn't free in emergency physical pages after virtual alloc error. Status: %8s\n",status);
return status;
}
if (pa%SH_PAGE_SIZE!=0 || va%SH_PAGE_SIZE!=0) sh_heap_internal_crash("Heap alloc error: physical address or virtual address isn't page aligned. Status: %8s\n",SH_STATUS_PEZ_CORRUPTED);
status=sh_page_map_contiguous_pages_range_ptp(default_heap->kernel_ptp,va,pa,SH_PAGE_PRESENT | SH_PAGE_RW | SH_PAGE_NX,pages_count*SH_PAGE_SIZE);
if (status!=SH_STATUS_SUCCESS) sh_heap_internal_crash("Heap alloc error: couldn't map all pages. Status: %8s",status);
sh_uint32 page_index=(sh_uint32)((va/SH_PAGE_SIZE)-SH_VMEM_LAYOUT_HEAP_BIG_VA);
status=sh_radix_tree_insert_value(default_heap->phys_plane->slab_radix_node,default_heap->kernel_ptp,&default_heap->alloc_size_tree,page_index,pages_count);
if (status!=SH_STATUS_SUCCESS) sh_heap_internal_crash("Heap alloc error: couldn't insert alloc record inside alloc_size_tree. Status: %8s\n",status);
*address=va;
return SH_STATUS_SUCCESS;
}
SH_STATUS sh_heap_free_pages(sh_page_VIRTUAL_ADDRESS va) {
if (default_heap==SH_NULLPTR) return SH_STATUS_HEAP_NOT_INITIALIZED;
if (va%SH_PAGE_SIZE!=0) return SH_STATUS_INVALID_PARAMETER;
sh_uint32 page_index=(sh_uint32)((va/SH_PAGE_SIZE)-SH_VMEM_LAYOUT_HEAP_BIG_VA);
sh_page_VIRTUAL_ADDRESS pages_count_raw=0;
SH_STATUS status=sh_radix_tree_get_value(&default_heap->alloc_size_tree,page_index,&pages_count_raw);
if (status!=SH_STATUS_SUCCESS) {
// sh_log_flog(SH_LOG_SOURCE_HEAP,"va=0x%x\n",va);
sh_heap_internal_crash("Heap free error: alloc record not found in alloc_size_tree. Status: %8s\n",status);
}
sh_uint32 pages_count=(sh_uint32)pages_count_raw;
sh_page_PHYSICAL_ADDRESS pa;
status=sh_page_ptp_va_to_pa(default_heap->kernel_ptp,va,&pa);
if (sh_status_error(status)) sh_heap_internal_crash("Heap free error: couldn't find associated physical address. Status: %8s\n",status);
status=sh_page_unmap_contiguous_pages_range_ptp(default_heap->kernel_ptp,va,pages_count*SH_PAGE_SIZE);
if (sh_status_error(status)) sh_heap_internal_crash("Heap free error: unmap failed. Status: %8s\n",status);
// sh_log_flog(SH_LOG_SOURCE_HEAP,"freeed va=0x%x\n",va);
status=sh_pez_free_virtual_pages(default_heap->virt_plane,&va,pages_count);
if (sh_status_error(status)) sh_heap_internal_crash("Heap free error: virt_plane free failed. Status: %8s\n",status);
status=sh_pez_free_physical_pages(default_heap->phys_plane,&pa,pages_count);
if (sh_status_error(status)) sh_heap_internal_crash("Heap free error: phys_plane free failed. Status: %8s\n",status);
status=sh_radix_tree_delete_value(default_heap->phys_plane->slab_radix_node,&default_heap->alloc_size_tree,page_index);
if (sh_status_error(status)) sh_heap_internal_crash("Heap free error: record deletion failed. Status: %8s\n",status);
return SH_STATUS_SUCCESS;
}
static inline sh_uint32 sh_heap_internal_get_index(sh_uint32 n) {
if (n<=8) return 0;
return (sh_uint32)31-(sh_uint32)__builtin_clz(n-1)-(sh_uint32)2;
}
SH_STATUS sh_heap_allocate_object(sh_uint32 size_bytes,sh_page_VIRTUAL_ADDRESS *address) {
if (default_heap==SH_NULLPTR) return SH_STATUS_HEAP_NOT_INITIALIZED;
if (size_bytes==0 || address==SH_NULLPTR) return SH_STATUS_INVALID_PARAMETER;
if (size_bytes>1024) return SH_STATUS_INVALID_PARAMETER;
sh_uint32 slab_alloc_index=sh_heap_internal_get_index(size_bytes);
void *ptr;
SH_STATUS status=sh_slab_generic_alloc(&default_heap->slabs_allocator[slab_alloc_index],default_heap->kernel_ptp,&ptr);
if (sh_status_error(status)) return status;
sh_page_VIRTUAL_ADDRESS va=(sh_uint64)ptr;
*address=va;
return SH_STATUS_SUCCESS;
}
SH_STATUS sh_heap_free_object(sh_page_VIRTUAL_ADDRESS va) {
if (default_heap==SH_NULLPTR) return SH_STATUS_HEAP_NOT_INITIALIZED;
sh_uint64 slab_alloc_index=(va-SH_VMEM_LAYOUT_HEAP_SLAB_LEVEL_0_VA)/0x00000C0000000000;
if (slab_alloc_index>7) return SH_STATUS_INVALID_PARAMETER;
return sh_slab_generic_dealloc(&default_heap->slabs_allocator[slab_alloc_index],(void*)va);
}

View File

@@ -0,0 +1,669 @@
// SPDX-License-Identifier: MPL-2.0
#include "memory/page.h"
#include "kernel/log.h"
#include "std/mem.h"
__attribute__((section(".bss")))
static sh_uint8 memory_map_buffer[64*1024];
static sh_uint8 *physical_bitmap;
__attribute__((section(".bss")))
static sh_uint64 physical_memory_pages_count=0;
__attribute__((section(".bss")))
static sh_uint64 physical_memory_bytes_count=0;
__attribute__((section(".bss")))
static sh_uint64 physical_bitmap_size_bytes=0;
__attribute__((section(".bss")))
static sh_uint64 physical_bitmap_size_pages=0;
__attribute__((section(".bss")))
static sh_uint64 physical_memory_installed=0;
static sh_page_VIRTUAL_ADDRESS page_table_pool_va_ptr=SH_PAGE_NULL_VA;
SH_STATUS sh_page_load_boot_ptp_va(sh_page_VIRTUAL_ADDRESS pt_pool_va) {
page_table_pool_va_ptr=pt_pool_va;
sh_log_fdebug(SH_LOG_SOURCE_PAGE,"Page table pool VA: 0x%8U\n",(sh_uint64)page_table_pool_va_ptr);
volatile sh_uint8 first_byte=*(sh_uint8*)(page_table_pool_va_ptr);
(void)first_byte;
sh_log_debug("If you can see this message, no fault happened.",SH_LOG_SOURCE_PAGE);
return SH_STATUS_SUCCESS;
}
sh_page_VIRTUAL_ADDRESS sh_page_get_boot_ptp_va() {
return page_table_pool_va_ptr;
}
SH_STATUS sh_page_copy_memory_map() {
return sh_mem_copy(memory_map_buffer,(void*)SH_PAGE_MEMORY_MAP_VA,sizeof(memory_map_buffer));
}
SH_STATUS sh_page_check_memory_map() {
static const sh_uint8 memory_map_sig[8]={'S','h','e','M','m','a','p','B'};
if (sh_mem_compare(memory_map_sig,memory_map_buffer,sizeof(memory_map_sig))==SH_STATUS_MEM_NOT_EQUAL) {
sh_log_critical("Memory map doesn't have signature on.",SH_LOG_SOURCE_PAGE);
return SH_STATUS_INVALID_SIGNATURE;
}
sh_page_MEMORY_MAP_HEADER *memory_map_header=(sh_page_MEMORY_MAP_HEADER *)memory_map_buffer;
sh_log_fdebug(SH_LOG_SOURCE_PAGE,"Memory map entry count: %8u\n",(sh_uint64)memory_map_header->entry_count);
sh_log_fdebug(SH_LOG_SOURCE_PAGE,"Memory map entry size: %8u\n",(sh_uint64)memory_map_header->entry_size);
sh_log_fdebug(SH_LOG_SOURCE_PAGE,"Memory map syntax version: %1u\n",memory_map_header->mmap_syntax_version);
if (memory_map_header->entry_count*memory_map_header->entry_size+sizeof(sh_page_MEMORY_MAP_HEADER)>sizeof(memory_map_buffer)) {
sh_log_error("Memory map overflow allocated buffer.",SH_LOG_SOURCE_PAGE);
return SH_STATUS_MMAP_BUFFER_OVERFLOW;
}
return SH_STATUS_SUCCESS;
}
sh_uint64 sh_page_get_physical_memory_amount_pages() {
return physical_memory_pages_count;
}
sh_uint64 sh_page_get_physical_memory_amount_bytes() {
return physical_memory_bytes_count;
}
sh_uint64 sh_page_get_one_page_na() {
sh_uint64 page_count=physical_memory_pages_count;
sh_uint64 bitmap_word_count=(page_count+63)/64;
for (sh_iter64 word=0;word<bitmap_word_count;word++) {
sh_uint64 value=physical_bitmap[word];
if (value==0xFFFFFFFFFFFFFFFFULL) {
continue;
}
for (sh_iter64 bit=0;bit<64;bit++) {
sh_uint64 page_index=(word*64)+bit;
if (page_index>=page_count) {
return 0;
}
if ((value & (1ULL<<bit))==0) {
return page_index*SH_PAGE_SIZE;
}
}
}
return 0;
}
SH_STATUS sh_page_set_pages_range_bitmap(sh_uint8 *bitmap,sh_uint64 page_count_in_bitmap,sh_uint64 page_index,sh_uint64 page_count,sh_bool state) {
if (bitmap==SH_NULLPTR) {
return SH_STATUS_INVALID_PARAMETER;
}
if (page_index+page_count>page_count_in_bitmap) {
return SH_STATUS_INVALID_PARAMETER;
}
for (sh_iter64 i=0;i<page_count;++i) {
sh_uint64 page=page_index+i;
sh_uint64 byte_index=page/8;
sh_uint8 bit_index=page%8;
if (state) {
bitmap[byte_index]|=(sh_uint8)(1u<<bit_index);
} else {
bitmap[byte_index]&=(sh_uint8)~(1u<<bit_index);
}
}
return SH_STATUS_SUCCESS;
}
SH_STATUS sh_page_init_ptp(sh_page_PHYSICAL_ADDRESS ptp_pa,sh_page_VIRTUAL_ADDRESS ptp_va,sh_uint64 initial_fill_level,sh_page_PAGE_TABLE_POOL *page_table_pool) {
page_table_pool->page_table_pa=ptp_pa;
page_table_pool->page_table_va=ptp_va;
page_table_pool->ptp_pages_count=SH_PAGE_PTP_ALLOCATOR_PAGES_COUNT;
page_table_pool->ptp_alloc_bitmap_uint64_count=SH_PAGE_PTP_ALLOCATOR_BITMAP_UINT64;
SH_STATUS status=sh_mem_set_8((sh_uint8*)page_table_pool->ptp_alloc_bitmap,SH_FALSE,sizeof(page_table_pool->ptp_alloc_bitmap));
if (sh_status_error(status)) {
sh_log_error("Error: couldn't initialize page table pool bitmap.",SH_LOG_SOURCE_PAGE);
return SH_STATUS_PT_POOL_NO_BITMAP_INIT;
}
if (initial_fill_level!=0) {
status=sh_page_set_pages_range_bitmap((sh_uint8*)page_table_pool->ptp_alloc_bitmap,page_table_pool->ptp_pages_count,0,initial_fill_level,SH_TRUE);
if (sh_status_error(status)) {
sh_log_error("Error: couldn't initialize pages tables already alocated.",SH_LOG_SOURCE_PAGE);
return SH_STATUS_PT_POOL_NO_PAGE_SET;
}
}
return SH_STATUS_SUCCESS;
}
SH_STATUS sh_page_dump_ptp_bitmap(sh_page_PAGE_TABLE_POOL *ptp) {
for (sh_iter64 i=0;i<ptp->ptp_alloc_bitmap_uint64_count;++i) {
sh_log_fdebug(SH_LOG_SOURCE_PAGE," 0x%8U\n",ptp->ptp_alloc_bitmap[i]);
}
return SH_STATUS_SUCCESS;
}
sh_page_PHYSICAL_ADDRESS sh_page_ptp_alloc_one_page(sh_page_PAGE_TABLE_POOL *pt_pool) {
if (pt_pool==SH_NULLPTR) {
return SH_STATUS_INVALID_PARAMETER;
}
sh_uint64 page_count=pt_pool->ptp_pages_count;
sh_uint64 bitmap_word_count=(page_count+63)/64;
for (sh_iter64 word=0;word<bitmap_word_count;word++) {
sh_uint64 value=pt_pool->ptp_alloc_bitmap[word];
if (value==0xFFFFFFFFFFFFFFFFULL) {
continue;
}
for (sh_iter64 bit=0;bit<64;bit++) {
sh_uint64 page_index=(word*64)+bit;
if (page_index>=page_count) {
return 0;
}
if ((value & (1ULL<<bit))==0) {
pt_pool->ptp_alloc_bitmap[word]|=(1ULL<<bit);
sh_page_PHYSICAL_ADDRESS pa=pt_pool->page_table_pa+page_index*SH_PAGE_SIZE;
return pa;
}
}
}
return 0;
}
SH_STATUS sh_page_map_one_page_ptp(sh_page_PAGE_TABLE_POOL *ptp,sh_page_VIRTUAL_ADDRESS va,sh_page_PHYSICAL_ADDRESS pa,sh_uint64 flags) {
if (ptp==SH_NULLPTR) return SH_STATUS_INVALID_PARAMETER;
if (va%SH_PAGE_SIZE!=0 || pa%SH_PAGE_SIZE!=0) return SH_STATUS_INVALID_PARAMETER;
sh_uint64 pml4_i=(va>>39) & 0x1FF;
sh_uint64 pdpt_i=(va>>30) & 0x1FF;
sh_uint64 pd_i=(va>>21) & 0x1FF;
sh_uint64 pt_i=(va>>12) & 0x1FF;
sh_uint64 *pdpt;
sh_uint64 *pd;
sh_uint64 *pt;
sh_uint64 *pml4=(sh_uint64*)ptp->page_table_va;
if (!(pml4[pml4_i] & SH_PAGE_PRESENT)) {
sh_page_PHYSICAL_ADDRESS pdpt_pa=sh_page_ptp_alloc_one_page(ptp);
if (!pdpt_pa) return SH_STATUS_OUT_OF_MEMORY;
pdpt=sh_page_ptp_pa_to_va(ptp,pdpt_pa);
if (!pdpt) return SH_STATUS_INVALID_INTERNAL_PA;
sh_mem_set_8((sh_uint8*)pdpt,0,SH_PAGE_SIZE);
pml4[pml4_i]=pdpt_pa | SH_PAGE_TABLE_FLAGS | SH_PAGE_PRESENT;
} else {
pdpt=sh_page_ptp_pa_to_va(ptp,(pml4[pml4_i] & ~0xFFFULL));
if (!pdpt) return SH_STATUS_INVALID_INTERNAL_PA;
}
if (!(pdpt[pdpt_i] & SH_PAGE_PRESENT)) {
sh_page_PHYSICAL_ADDRESS pd_pa=sh_page_ptp_alloc_one_page(ptp);
if (!pd_pa) return SH_STATUS_OUT_OF_MEMORY;
pd=sh_page_ptp_pa_to_va(ptp,pd_pa);
if (!pd) return SH_STATUS_INVALID_INTERNAL_PA;
sh_mem_set_8((sh_uint8*)pd,0,SH_PAGE_SIZE);
pdpt[pdpt_i]=pd_pa | SH_PAGE_TABLE_FLAGS | SH_PAGE_PRESENT;
} else {
pd=sh_page_ptp_pa_to_va(ptp,(pdpt[pdpt_i] & ~0xFFFULL));
if (!pd) return SH_STATUS_INVALID_INTERNAL_PA;
}
if (!(pd[pd_i] & SH_PAGE_PRESENT)) {
sh_page_PHYSICAL_ADDRESS pt_pa=sh_page_ptp_alloc_one_page(ptp);
if (!pt_pa) return SH_STATUS_OUT_OF_MEMORY;
pt=sh_page_ptp_pa_to_va(ptp,pt_pa);
if (!pt) return SH_STATUS_INVALID_INTERNAL_PA;
sh_mem_set_8((sh_uint8*)pt,0,SH_PAGE_SIZE);
pd[pd_i]=pt_pa | SH_PAGE_TABLE_FLAGS | SH_PAGE_PRESENT;
} else {
pt=sh_page_ptp_pa_to_va(ptp,pd[pd_i] & ~0xFFFULL);
if (!pt) return SH_STATUS_INVALID_INTERNAL_PA;
}
pt[pt_i]=(pa & ~0xFFFULL) | flags | SH_PAGE_PRESENT;
return SH_STATUS_SUCCESS;
}
SH_STATUS sh_page_is_va_mapped_ptp(sh_page_PAGE_TABLE_POOL *ptp,sh_page_VIRTUAL_ADDRESS va) {
if (ptp==SH_NULLPTR) return SH_STATUS_INVALID_PARAMETER;
sh_uint64 pml4_i=(va>>39) & 0x1FF;
sh_uint64 pdpt_i=(va>>30) & 0x1FF;
sh_uint64 pd_i=(va>>21) & 0x1FF;
sh_uint64 pt_i=(va>>12) & 0x1FF;
sh_uint64 *pdpt;
sh_uint64 *pd;
sh_uint64 *pt;
sh_uint64 *pml4=(sh_uint64*)ptp->page_table_va;
if (!(pml4[pml4_i] & SH_PAGE_PRESENT)) {
return SH_STATUS_VA_NOT_MAPPED;
} else {
pdpt=sh_page_ptp_pa_to_va(ptp,(pml4[pml4_i] & ~0xFFFULL));
if (pdpt==0) return SH_STATUS_INVALID_INTERNAL_PA;
}
if (!(pdpt[pdpt_i] & SH_PAGE_PRESENT)) {
return SH_STATUS_VA_NOT_MAPPED;
} else {
pd=sh_page_ptp_pa_to_va(ptp,(pdpt[pdpt_i] & ~0xFFFULL));
if (pd==0) return SH_STATUS_INVALID_INTERNAL_PA;
}
if (!(pd[pd_i] & SH_PAGE_PRESENT)) {
return SH_STATUS_VA_NOT_MAPPED;
} else {
pt=sh_page_ptp_pa_to_va(ptp,(pd[pd_i] & ~0xFFFULL));
if (pt==0) return SH_STATUS_INVALID_INTERNAL_PA;
}
if (!(pt[pt_i] & SH_PAGE_PRESENT)) {
return SH_STATUS_VA_NOT_MAPPED;
} else {
return SH_STATUS_VA_MAPPED;
}
}
SH_STATUS sh_page_is_va_range_mapped_ptp(sh_page_PAGE_TABLE_POOL *ptp,sh_page_VIRTUAL_ADDRESS va,sh_uint64 size_bytes) {
if (ptp==SH_NULLPTR) return SH_STATUS_INVALID_PARAMETER;
if (va%SH_PAGE_SIZE!=0 || size_bytes%SH_PAGE_SIZE!=0 || size_bytes==0) return SH_STATUS_INVALID_PARAMETER;
sh_uint64 counter=0;
for (sh_iter64 i=0;i<size_bytes/SH_PAGE_SIZE;i++) {
if (sh_page_is_va_mapped_ptp(ptp,va+i*SH_PAGE_SIZE)==SH_STATUS_VA_MAPPED) {
counter++;
}
}
if (counter==0) return SH_STATUS_VA_NOT_MAPPED;
if (counter==size_bytes/SH_PAGE_SIZE) return SH_STATUS_VA_FULLY_MAPPED;
return SH_STATUS_VA_PARTIALLY_MAPPED;
}
SH_STATUS sh_page_search_available_va_range(sh_page_PAGE_TABLE_POOL *ptp,sh_page_VIRTUAL_ADDRESS range_base,sh_page_VIRTUAL_ADDRESS range_size_bytes,sh_uint64 size_bytes,sh_page_VIRTUAL_ADDRESS *address_found) {
if (ptp==SH_NULLPTR || address_found==SH_NULLPTR) {
return SH_STATUS_INVALID_PARAMETER;
}
if (size_bytes==0 || size_bytes%SH_PAGE_SIZE!=0) {
return SH_STATUS_INVALID_PARAMETER;
};
if (range_base%SH_PAGE_SIZE!=0 || range_size_bytes%4096!=0 || range_size_bytes==0) {
return SH_STATUS_INVALID_PARAMETER;
};
sh_uint64 pages_needed=size_bytes/SH_PAGE_SIZE;
sh_page_VIRTUAL_ADDRESS current_va=range_base;
sh_uint64 contiguous=0;
sh_page_VIRTUAL_ADDRESS candidate_start=0;
while (current_va<range_base+range_size_bytes) {
SH_STATUS status=sh_page_is_va_mapped_ptp(ptp,current_va);
if (status==SH_STATUS_VA_NOT_MAPPED) {
if (contiguous==0) {
candidate_start=current_va;
}
contiguous++;
if (contiguous==pages_needed) {
*address_found=(sh_page_VIRTUAL_ADDRESS)candidate_start;
return SH_STATUS_SUCCESS;
}
} else if (status==SH_STATUS_VA_MAPPED) {
contiguous=0;
} else {
return SH_STATUS_INVALID_INTERNAL_PA;
}
current_va+=SH_PAGE_SIZE;
}
return SH_STATUS_OUT_OF_MEMORY;
}
SH_STATUS sh_page_map_contiguous_pages_range_ptp(sh_page_PAGE_TABLE_POOL *ptp,sh_page_VIRTUAL_ADDRESS va,sh_page_PHYSICAL_ADDRESS pa,sh_uint64 flags,sh_uint64 size_bytes) {
if (ptp==SH_NULLPTR) return SH_STATUS_INVALID_PARAMETER;
if (va%SH_PAGE_SIZE!=0 || pa%SH_PAGE_SIZE!=0 || size_bytes==0 || size_bytes%SH_PAGE_SIZE!=0) return SH_STATUS_INVALID_PARAMETER;
if ((flags & SH_PAGE_PS)==SH_PAGE_PS) return SH_STATUS_INVALID_PARAMETER;
sh_uint64 pages=size_bytes/SH_PAGE_SIZE;
SH_STATUS status=sh_page_is_va_range_mapped_ptp(ptp,va,size_bytes);
if (status==SH_STATUS_VA_PARTIALLY_MAPPED) return SH_STATUS_ERROR_VA_PARTIALLY_MAPPED;
if (status==SH_STATUS_VA_FULLY_MAPPED) return SH_STATUS_ERROR_VA_FULLY_MAPPED;
for (sh_iter64 i=0;i<pages;i++) {
status=sh_page_map_one_page_ptp(ptp,va+i*SH_PAGE_SIZE,pa+i*SH_PAGE_SIZE,flags);
if (status!=SH_STATUS_SUCCESS) {
return status;
}
}
return SH_STATUS_SUCCESS;
}
SH_STATUS sh_page_search_physical_contiguous_block_na(sh_uint64 pages_needed,sh_page_PHYSICAL_ADDRESS *pa) {
if (pages_needed==0) return SH_STATUS_INVALID_PARAMETER;
sh_uint64 page_count=sh_page_get_physical_memory_amount_pages();
sh_uint64 contiguous=0;
sh_uint64 candidate_start=0;
for (sh_iter64 page_index=0;page_index<page_count;page_index++) {
if (!sh_page_is_allocated(physical_bitmap,page_index)) {
if (contiguous==0) candidate_start=page_index;
contiguous++;
if (contiguous==pages_needed) {
*pa=candidate_start*SH_PAGE_SIZE;
return SH_STATUS_SUCCESS;
}
} else {
contiguous=0;
}
}
return SH_STATUS_OUT_OF_MEMORY;
}
SH_STATUS sh_page_alloc_contiguous(sh_page_PAGE_TABLE_POOL *ptp,sh_uint64 size_bytes,sh_page_VIRTUAL_ADDRESS *va) {
if (ptp==SH_NULLPTR || va==SH_NULLPTR || size_bytes==0) return SH_STATUS_INVALID_PARAMETER;
sh_uint64 pages_needed=size_bytes/SH_PAGE_SIZE;
if (size_bytes%SH_PAGE_SIZE!=0) pages_needed++;
sh_page_VIRTUAL_ADDRESS candidate_va=0;
SH_STATUS status=sh_page_search_available_va_range(ptp,0x0,0x00007FFFFFFFF000,pages_needed*SH_PAGE_SIZE,&candidate_va);
if (status==SH_STATUS_OUT_OF_MEMORY) {
return SH_STATUS_OUT_OF_MEMORY;
} else if (status==SH_STATUS_INVALID_INTERNAL_PA) {
return SH_STATUS_KERNEL_PANIC;
} else if (status==SH_STATUS_INVALID_PARAMETER) {
return SH_STATUS_OUT_OF_MEMORY;
} else if (sh_status_error(status)) {
return SH_STATUS_OUT_OF_MEMORY;
}
sh_page_PHYSICAL_ADDRESS candidate_pa=0;
status=sh_page_search_physical_contiguous_block_na(pages_needed,&candidate_pa);
if (status!=SH_STATUS_SUCCESS) {
return SH_STATUS_OUT_OF_MEMORY;
}
status=sh_page_map_contiguous_pages_range_ptp(ptp,candidate_va,candidate_pa,SH_PAGE_PRESENT | SH_PAGE_NX | SH_PAGE_RW,pages_needed*SH_PAGE_SIZE);
if (status!=SH_STATUS_SUCCESS) return status;
sh_page_set_pages_range_bitmap(physical_bitmap,physical_memory_pages_count,(sh_uint64)candidate_pa/SH_PAGE_SIZE,pages_needed,SH_TRUE);
*va=candidate_va;
return SH_STATUS_SUCCESS;
}
SH_STATUS sh_page_alloc_contiguous_extended(sh_page_PAGE_TABLE_POOL *ptp,sh_uint64 size_bytes,sh_page_VIRTUAL_ADDRESS* va,DEFAULT sh_uint64 flags,DEFAULT sh_page_VIRTUAL_ADDRESS va_range_start,DEFAULT sh_uint64 va_range_size_bytes) {
if (ptp==SH_NULLPTR || va==SH_NULLPTR || size_bytes==0) return SH_STATUS_INVALID_PARAMETER;
if (flags==SH_DEFVALUE) flags=SH_PAGE_PRESENT | SH_PAGE_NX | SH_PAGE_RW;
if (va_range_start==SH_DEFVALUE) va_range_start=0x0;
if (va_range_size_bytes==SH_DEFVALUE) va_range_size_bytes=0x00007FFFFFFFF000;
if (va_range_start%SH_PAGE_SIZE!=0 || va_range_size_bytes==0 || va_range_size_bytes%SH_PAGE_SIZE!=0) return SH_STATUS_INVALID_PARAMETER;
sh_uint64 pages_needed=size_bytes/SH_PAGE_SIZE;
if (size_bytes%SH_PAGE_SIZE!=0) pages_needed++;
sh_page_VIRTUAL_ADDRESS candidate_va=0;
SH_STATUS status=sh_page_search_available_va_range(ptp,va_range_start,va_range_size_bytes,pages_needed*SH_PAGE_SIZE,&candidate_va);
if (status==SH_STATUS_OUT_OF_MEMORY) {
return SH_STATUS_OUT_OF_MEMORY;
} else if (status==SH_STATUS_INVALID_INTERNAL_PA) {
return SH_STATUS_KERNEL_PANIC;
} else if (status==SH_STATUS_INVALID_PARAMETER) {
return SH_STATUS_OUT_OF_MEMORY;
} else if (sh_status_error(status)) {
return SH_STATUS_OUT_OF_MEMORY;
}
sh_page_PHYSICAL_ADDRESS candidate_pa=0;
status=sh_page_search_physical_contiguous_block_na(pages_needed,&candidate_pa);
if (status!=SH_STATUS_SUCCESS) {
return SH_STATUS_OUT_OF_MEMORY;
}
status=sh_page_map_contiguous_pages_range_ptp(ptp,candidate_va,candidate_pa,flags,pages_needed*SH_PAGE_SIZE);
if (status!=SH_STATUS_SUCCESS) return status;
sh_page_set_pages_range_bitmap(physical_bitmap,physical_memory_pages_count,(sh_uint64)candidate_pa/SH_PAGE_SIZE,pages_needed,SH_TRUE);
*va=candidate_va;
return SH_STATUS_SUCCESS;
}
SH_STATUS sh_page_unmap_one_page_ptp(sh_page_PAGE_TABLE_POOL *ptp,sh_page_VIRTUAL_ADDRESS va) {
if (ptp==SH_NULLPTR) return SH_STATUS_INVALID_PARAMETER;
if (va%SH_PAGE_SIZE!=0) return SH_STATUS_INVALID_PARAMETER;
sh_uint64 pml4_i=(va>>39) & 0x1FF;
sh_uint64 pdpt_i=(va>>30) & 0x1FF;
sh_uint64 pd_i=(va>>21) & 0x1FF;
sh_uint64 pt_i=(va>>12) & 0x1FF;
sh_uint64 *pdpt;
sh_uint64 *pd;
sh_uint64 *pt;
sh_uint64 *pml4=(sh_uint64*)ptp->page_table_va;
if (!(pml4[pml4_i] & SH_PAGE_PRESENT)) {
return SH_STATUS_ERROR_VA_NOT_MAPPED;
} else {
pdpt=sh_page_ptp_pa_to_va(ptp,(pml4[pml4_i] & ~0xFFFULL));
if (!pdpt) return SH_STATUS_INVALID_INTERNAL_PA;
}
if (!(pdpt[pdpt_i] & SH_PAGE_PRESENT)) {
return SH_STATUS_ERROR_VA_NOT_MAPPED;
} else {
pd=sh_page_ptp_pa_to_va(ptp,(pdpt[pdpt_i] & ~0xFFFULL));
if (!pd) return SH_STATUS_INVALID_INTERNAL_PA;
}
if (!(pd[pd_i] & SH_PAGE_PRESENT)) {
return SH_STATUS_ERROR_VA_NOT_MAPPED;
} else {
pt=sh_page_ptp_pa_to_va(ptp,pd[pd_i] & ~0xFFFULL);
if (!pt) return SH_STATUS_INVALID_INTERNAL_PA;
}
pt[pt_i]=0x0ULL;
sh_asm_invlpg((void*)va);
return SH_STATUS_SUCCESS;
}
SH_STATUS sh_page_unmap_contiguous_pages_range_ptp(sh_page_PAGE_TABLE_POOL *ptp,sh_page_VIRTUAL_ADDRESS va,sh_uint64 size_bytes) {
if (ptp==SH_NULLPTR) return SH_STATUS_INVALID_PARAMETER;
if (va%SH_PAGE_SIZE!=0 || size_bytes==0 || size_bytes%SH_PAGE_SIZE!=0) return SH_STATUS_INVALID_PARAMETER;
sh_uint64 pages=size_bytes/SH_PAGE_SIZE;
SH_STATUS status=sh_page_is_va_range_mapped_ptp(ptp,va,size_bytes);
if (status==SH_STATUS_VA_PARTIALLY_MAPPED) return SH_STATUS_ERROR_VA_PARTIALLY_MAPPED;
if (status==SH_STATUS_VA_NOT_MAPPED) return SH_STATUS_ERROR_VA_NOT_MAPPED;
for (sh_iter64 i=0;i<pages;i++) {
status=sh_page_unmap_one_page_ptp(ptp,va+i*SH_PAGE_SIZE);
if (status!=SH_STATUS_SUCCESS) {
return status;
}
}
return SH_STATUS_SUCCESS;
}
SH_STATUS sh_page_ptp_va_to_pa(sh_page_PAGE_TABLE_POOL *ptp,sh_page_VIRTUAL_ADDRESS va,sh_page_PHYSICAL_ADDRESS *pa) {
if (ptp==SH_NULLPTR || pa==SH_NULLPTR) return SH_STATUS_INVALID_PARAMETER;
if (va%SH_PAGE_SIZE!=0) return SH_STATUS_INVALID_PARAMETER;
sh_uint64 pml4_i=(va>>39) & 0x1FF;
sh_uint64 pdpt_i=(va>>30) & 0x1FF;
sh_uint64 pd_i=(va>>21) & 0x1FF;
sh_uint64 pt_i=(va>>12) & 0x1FF;
sh_uint64 *pdpt;
sh_uint64 *pd;
sh_uint64 *pt;
sh_uint64 *pml4=(sh_uint64*)ptp->page_table_va;
if (!(pml4[pml4_i] & SH_PAGE_PRESENT)) {
return SH_STATUS_ERROR_VA_NOT_MAPPED;
} else {
pdpt=sh_page_ptp_pa_to_va(ptp,(pml4[pml4_i] & ~0xFFFULL));
if (!pdpt) return SH_STATUS_INVALID_INTERNAL_PA;
}
if (!(pdpt[pdpt_i] & SH_PAGE_PRESENT)) {
return SH_STATUS_ERROR_VA_NOT_MAPPED;
} else {
pd=sh_page_ptp_pa_to_va(ptp,(pdpt[pdpt_i] & ~0xFFFULL));
if (!pd) return SH_STATUS_INVALID_INTERNAL_PA;
}
if (!(pd[pd_i] & SH_PAGE_PRESENT)) {
return SH_STATUS_ERROR_VA_NOT_MAPPED;
} else {
pt=sh_page_ptp_pa_to_va(ptp,pd[pd_i] & ~0xFFFULL);
if (!pt) return SH_STATUS_INVALID_INTERNAL_PA;
}
if (!(pt[pt_i] & SH_PAGE_PRESENT)) return SH_STATUS_ERROR_VA_NOT_MAPPED;
*pa=pt[pt_i] & 0x000FFFFFFFFFF000;
return SH_STATUS_SUCCESS;
}
SH_STATUS sh_page_unalloc_one_page(sh_page_PAGE_TABLE_POOL *ptp,sh_page_VIRTUAL_ADDRESS va) {
if (ptp==SH_NULLPTR) return SH_STATUS_INVALID_PARAMETER;
if (va%SH_PAGE_SIZE!=0) return SH_STATUS_INVALID_PARAMETER;
sh_page_PHYSICAL_ADDRESS equivalent_pa;
SH_STATUS status=sh_page_ptp_va_to_pa(ptp,va,&equivalent_pa);
if (status!=SH_STATUS_SUCCESS) return status;
status=sh_page_unmap_one_page_ptp(ptp,va); // If this call return SH_STATUS_ERROR_VA_NOT_MAPPED, there is a severe bug that should cause kernel panic because sh_page_ptp_va_to_pa should already have returned exact same error code.
if (status!=SH_STATUS_SUCCESS) return status;
status=sh_page_set_pages_range_bitmap(physical_bitmap,physical_memory_pages_count,(sh_uint64)(equivalent_pa/SH_PAGE_SIZE),1,SH_FALSE);
if (status!=SH_STATUS_SUCCESS) return status;
return SH_STATUS_SUCCESS;
}
SH_STATUS sh_page_unalloc_contiguous(sh_page_PAGE_TABLE_POOL *ptp,sh_page_VIRTUAL_ADDRESS va,sh_uint64 size_bytes) {
if (ptp==SH_NULLPTR) return SH_STATUS_INVALID_PARAMETER;
if (va%SH_PAGE_SIZE!=0 || size_bytes==0 || size_bytes%SH_PAGE_SIZE!=0) return SH_STATUS_INVALID_PARAMETER;
SH_STATUS status=sh_page_is_va_range_mapped_ptp(ptp,va,size_bytes);
if (status==SH_STATUS_VA_NOT_MAPPED) return SH_STATUS_ERROR_VA_NOT_MAPPED;
if (status==SH_STATUS_VA_PARTIALLY_MAPPED) return SH_STATUS_ERROR_VA_PARTIALLY_MAPPED;
sh_uint64 pages=size_bytes/SH_PAGE_SIZE;
for (sh_iter64 i=0;i<pages;i++) {
status=sh_page_unalloc_one_page(ptp,va+i*SH_PAGE_SIZE);
if (status!=SH_STATUS_SUCCESS) {
return status;
}
}
return SH_STATUS_SUCCESS;
}
SH_STATUS sh_page_analyse_memory_map(sh_page_PAGE_TABLE_POOL *ptp) {
if (ptp==SH_NULLPTR) return SH_STATUS_INVALID_PARAMETER;
sh_page_MEMORY_MAP_HEADER *memory_map_header=(sh_page_MEMORY_MAP_HEADER *)memory_map_buffer;
sh_page_MEMORY_MAP_ENTRY *memory_map_cursor=(sh_page_MEMORY_MAP_ENTRY *)(memory_map_buffer+sizeof(sh_page_MEMORY_MAP_HEADER));
sh_uint64 highest_usable_segment=0;
sh_uint64 highest_usable_page=0;
sh_uint64 biggest_segment_index=0;
sh_uint64 biggest_segment_pages=0;
sh_log_flog(SH_LOG_SOURCE_PAGE,"Max pages count is currently set to 0x%8U pages or 0x%8U bytes.\n",SH_PAGE_MAX_PAGES_COUNT,SH_PAGE_MAX_PAGES_COUNT*4096);
// first loop : identify memory amount and bigest free region
for (sh_iter64 i=0;i<memory_map_header->entry_count;i++) {
sh_uint64 start_page=memory_map_cursor[i].physical_start/4096;
sh_uint64 end_page=start_page+memory_map_cursor[i].pages_count;
if (memory_map_cursor[i].type==SH_PAGE_CONVENTIONAL_MEMORY && memory_map_cursor[i].pages_count>biggest_segment_pages) {
biggest_segment_pages=memory_map_cursor[i].pages_count;
biggest_segment_index=i;
}
if (memory_map_cursor[i].type==SH_PAGE_CONVENTIONAL_MEMORY) {
sh_log_fdebug(SH_LOG_SOURCE_PAGE,"Found memory map segment #%8u: [0x%8U - 0x%8U] Memory type : %4u --> usable\n",i,start_page*4096,end_page*4096,memory_map_cursor[i].type);
} else {
sh_log_fdebug(SH_LOG_SOURCE_PAGE,"Found memory map segment #%8u: [0x%8U - 0x%8U] Memory type : %4u --> not usable\n",i,start_page*4096,end_page*4096,memory_map_cursor[i].type);
}
if (!(end_page<=SH_PAGE_MAX_PAGES_COUNT)) {
sh_log_fwarning(SH_LOG_SOURCE_PAGE,"Memory map segment #%8u isn't usable because it overflow over max page count. Enable debug log channel to see more.\n",i);
}
if (memory_map_cursor[i].type==SH_PAGE_CONVENTIONAL_MEMORY && end_page<=SH_PAGE_MAX_PAGES_COUNT) {
physical_memory_installed+=memory_map_cursor[i].pages_count*SH_PAGE_SIZE;
if (end_page>highest_usable_page) {
highest_usable_segment=i;
highest_usable_page=end_page;
}
}
}
physical_memory_pages_count=highest_usable_page;
physical_memory_bytes_count=physical_memory_pages_count*SH_PAGE_SIZE;
sh_log_fdebug(SH_LOG_SOURCE_PAGE,"Total memory was given by memory map segment #%8u\n",highest_usable_segment);
sh_log_fdebug(SH_LOG_SOURCE_PAGE,"Total memory (pages): %8u\n",physical_memory_pages_count);
sh_log_fdebug(SH_LOG_SOURCE_PAGE,"Total memory (bytes) : %8u\n",physical_memory_bytes_count);
if (biggest_segment_pages==0) {
sh_log_error("No suitable conventional memory segment found.",SH_LOG_SOURCE_PAGE);
return SH_STATUS_OUT_OF_MEMORY;
}
if (memory_map_cursor[biggest_segment_index].pages_count<(physical_memory_pages_count/8)) {
sh_log_error("Memory is too low or too fragmented to allocate physical bitmap.",SH_LOG_SOURCE_PAGE);
return SH_STATUS_OUT_OF_MEMORY;
}
sh_page_PHYSICAL_ADDRESS pa=memory_map_cursor[biggest_segment_index].physical_start;
sh_page_VIRTUAL_ADDRESS va;
physical_bitmap_size_bytes=physical_memory_pages_count/8;
if (physical_memory_pages_count%8!=0) physical_bitmap_size_bytes++;
physical_bitmap_size_pages=physical_bitmap_size_bytes/SH_PAGE_SIZE;
if (physical_bitmap_size_bytes%SH_PAGE_SIZE!=0) physical_bitmap_size_pages++;
SH_STATUS status=sh_page_search_available_va_range(ptp,SH_PAGE_KERNEL_PERM_VA_BASE,(SH_PAGE_KERNEL_PERM_VA_END-SH_PAGE_KERNEL_PERM_VA_BASE+1-0x1000),physical_bitmap_size_pages*SH_PAGE_SIZE,&va);
if (status!=SH_STATUS_SUCCESS) {
sh_log_error("Memory is too low or too fragmented to allocate physical bitmap.",SH_LOG_SOURCE_PAGE);
return status;
}
status=sh_page_map_contiguous_pages_range_ptp(ptp,va,pa,SH_PAGE_PRESENT | SH_PAGE_NX | SH_PAGE_RW,physical_bitmap_size_pages*SH_PAGE_SIZE);
if (status==SH_STATUS_OUT_OF_MEMORY) {
sh_log_error("Memory is too low or too fragmented to allocate physical bitmap.",SH_LOG_SOURCE_PAGE);
return status;
} else if (status!=SH_STATUS_SUCCESS) {
sh_log_error("An unknow error happened during physical bitmap pages mapping. See error below",SH_LOG_SOURCE_PAGE);
return status;
}
physical_bitmap=(sh_uint8*)va;
status=sh_mem_set_8(physical_bitmap,0xFF,physical_bitmap_size_bytes);
if (sh_status_error(status)) {
sh_log_error("An unknow error happened during physical bitmap filling with 0xFF. See error below.",SH_LOG_SOURCE_PAGE);
return status;
}
// second loop : actually set all free regions into physical bitmap
for (sh_iter64 i=0;i<memory_map_header->entry_count;i++) {
sh_uint64 start_page=memory_map_cursor[i].physical_start/4096;
sh_uint64 end_page=start_page+memory_map_cursor[i].pages_count;
if (end_page<=SH_PAGE_MAX_PAGES_COUNT) {
if (memory_map_cursor[i].type==SH_PAGE_CONVENTIONAL_MEMORY) {
status=sh_page_set_pages_range_bitmap(physical_bitmap,physical_memory_pages_count,memory_map_cursor[i].physical_start/SH_PAGE_SIZE,memory_map_cursor[i].pages_count,SH_FALSE);
if (sh_status_error(status)) {
sh_log_error("Couldn't set this memory map segment to usable.",SH_LOG_SOURCE_PAGE);
return SH_STATUS_PMAP_NO_PAGES_SET;
}
}
}
}
sh_page_set_pages_range_bitmap(physical_bitmap,physical_memory_pages_count,pa/SH_PAGE_SIZE,physical_bitmap_size_pages,SH_TRUE);
return SH_STATUS_SUCCESS;
}
sh_page_VIRTUAL_ADDRESS sh_page_get_physical_bitmap_ptr() {
return (sh_page_VIRTUAL_ADDRESS)physical_bitmap;
}
static sh_uint64 popcount64(sh_uint64 x) {
x=x-((x>>1) & 0x5555555555555555ULL);
x=(x & 0x3333333333333333ULL)+((x>>2) & 0x3333333333333333ULL);
x=(x+(x>>4)) & 0x0F0F0F0F0F0F0F0FULL;
x=x+(x>>8);
x=x+(x>>16);
x=x+(x>>32);
return x & 0x7F;
}
SH_STATUS sh_page_get_memory_stats(sh_page_MEM_STATS *mem_stats) {
if (mem_stats==SH_NULLPTR) return SH_STATUS_INVALID_PARAMETER;
mem_stats->memory_total_pages=physical_memory_pages_count;
mem_stats->memory_total_bytes=physical_memory_bytes_count;
sh_uint64 free_pages=0;
sh_uint64 used_pages=0;
sh_uint64 largest_free_block=0;
sh_uint64 largest_used_block=0;
sh_uint64 free_blocks_count=0;
sh_uint64 used_blocks_count=0;
sh_uint64 current_free_block=0;
sh_uint64 current_used_block=0;
sh_uint64 full_uint64_count=physical_memory_pages_count/64;
sh_uint64 remaining_bits=physical_memory_pages_count%64;
sh_uint64 *bitmap64=(sh_uint64*)physical_bitmap;
for (sh_iter64 i=0;i<full_uint64_count;i++) {
sh_uint64 val=bitmap64[i];
sh_uint64 ones=popcount64(val);
sh_uint64 zeros=64-ones;
used_pages+=ones;
free_pages+=zeros;
for (sh_iter64 b=0;b<64;b++) {
sh_bool bit_set=(val>>b) & 1;
if (bit_set) {
current_used_block++;
if (current_free_block) {
free_blocks_count++;
if (current_free_block>largest_free_block) {
largest_free_block=current_free_block;
}
current_free_block=0;
}
} else {
current_free_block++;
if (current_used_block) {
used_blocks_count++;
if (current_used_block>largest_used_block) {
largest_used_block=current_used_block;
}
current_used_block=0;
}
}
}
}
if (remaining_bits) {
sh_uint64 val=bitmap64[full_uint64_count] & ((1ULL<<remaining_bits)-1);
sh_uint64 ones=popcount64(val);
sh_uint64 zeros=remaining_bits-ones;
used_pages+=ones;
free_pages+=zeros;
for (sh_iter64 b=0;b<remaining_bits;b++) {
sh_bool bit_set=(val>>b) & 1;
if (bit_set) {
current_used_block++;
if (current_free_block) {
free_blocks_count++;
if (current_free_block>largest_free_block) {
largest_free_block=current_free_block;
}
current_free_block=0;
}
} else {
current_free_block++;
if (current_used_block) {
used_blocks_count++;
if (current_used_block>largest_used_block) {
largest_used_block=current_used_block;
}
current_used_block=0;
}
}
}
}
if (current_free_block) {
free_blocks_count++;
if (current_free_block>largest_free_block) {
largest_free_block=current_free_block;
}
}
if (current_used_block) {
used_blocks_count++;
if (current_used_block>largest_used_block) {
largest_used_block=current_used_block;
}
}
mem_stats->free_pages=free_pages;
mem_stats->used_pages=used_pages;
mem_stats->free_ratio=(double)free_pages/(double)physical_memory_pages_count;
mem_stats->used_ratio=(double)used_pages/(double)physical_memory_pages_count;
mem_stats->largest_free_block=largest_free_block;
mem_stats->largest_used_block=largest_used_block;
mem_stats->free_blocks_count=free_blocks_count;
mem_stats->used_blocks_count=used_blocks_count;
mem_stats->physical_bitmap_size_bytes=(physical_memory_pages_count+7)/8;
mem_stats->physical_bitmap_size_pages=(mem_stats->physical_bitmap_size_bytes+4095)/4096;
mem_stats->memory_installed_pages=physical_memory_installed/SH_PAGE_SIZE;
mem_stats->memory_installed_bytes=physical_memory_installed;
return SH_STATUS_SUCCESS;
}

View File

@@ -0,0 +1,71 @@
// SPDX-License-Identifier: MPL-2.0
#include "memory/pba.h"
#include "memory/pez/pez.h"
#include "kernel/log.h"
SH_STATUS sh_pba_init(sh_pba_PAGE_BLOCK_ALLOCATOR *pba,sh_page_VIRTUAL_ADDRESS start_va,sh_uint64 area_pages_amount,sh_uint64 block_pages) {
if (pba==SH_NULLPTR) {
return SH_STATUS_INVALID_PARAMETER;
}
if (area_pages_amount%block_pages!=0) {
return SH_STATUS_INVALID_PARAMETER;
}
if (start_va%(SH_PAGE_SIZE*block_pages)!=0) {
return SH_STATUS_INVALID_PARAMETER;
}
pba->start_va=start_va;
pba->block_pages=block_pages;
pba->block_count=0;
pba->total_pages=area_pages_amount;
pba->max_blocks=area_pages_amount/block_pages;
return SH_STATUS_SUCCESS;
}
SH_STATUS sh_pba_alloc(sh_pba_PAGE_BLOCK_ALLOCATOR *pba,sh_page_PAGE_TABLE_POOL *ptp,sh_page_VIRTUAL_ADDRESS *ptr) {
if (pba==SH_NULLPTR || ptr==SH_NULLPTR) return SH_STATUS_INVALID_PARAMETER;
if (pba->block_count==pba->max_blocks) return SH_STATUS_PBA_FULL;
if (!sh_pez_is_available()) {
sh_page_PHYSICAL_ADDRESS block_pa;
SH_STATUS status=sh_page_search_physical_contiguous_block_na(pba->block_pages,&block_pa);
if (sh_status_error(status)) return status;
sh_page_VIRTUAL_ADDRESS temp_ptr=pba->start_va+pba->block_count*pba->block_pages*SH_PAGE_SIZE;
status=sh_page_is_va_range_mapped_ptp(ptp,temp_ptr,pba->block_pages*SH_PAGE_SIZE);
if (status==SH_STATUS_VA_FULLY_MAPPED || status==SH_STATUS_VA_PARTIALLY_MAPPED) {
return status;
} else if (sh_status_error(status)) {
return status;
} else if (status!=SH_STATUS_VA_NOT_MAPPED) {
return status;
}
status=sh_page_set_pages_range_bitmap((sh_uint8*)sh_page_get_physical_bitmap_ptr(),sh_page_get_physical_memory_amount_pages(),block_pa/SH_PAGE_SIZE,pba->block_pages,SH_TRUE);
if (sh_status_error(status)) return status;
status=sh_page_map_contiguous_pages_range_ptp(ptp,temp_ptr,block_pa,SH_PAGE_RW | SH_PAGE_NX | SH_PAGE_PRESENT,pba->block_pages*SH_PAGE_SIZE);
if (sh_status_error(status)) {
SH_STATUS status2=sh_page_set_pages_range_bitmap((sh_uint8*)sh_page_get_physical_bitmap_ptr(),sh_page_get_physical_memory_amount_pages(),block_pa/SH_PAGE_SIZE,pba->block_pages,SH_FALSE);
if (sh_status_error(status2)) return status2;
return status;
}
*ptr=temp_ptr;
} else {
if (sh_pez_get_reference_phys_plane()==SH_NULLPTR) return SH_STATUS_ERROR_PEZ_INITIALIZED;
sh_page_PHYSICAL_ADDRESS block_pa;
SH_STATUS status=sh_pez_alloc_physical_pages(sh_pez_get_reference_phys_plane(),(sh_uint32)pba->block_pages,&block_pa);
if (sh_status_error(status)) return status;
sh_page_VIRTUAL_ADDRESS temp_ptr=pba->start_va+pba->block_count*pba->block_pages*SH_PAGE_SIZE;
status=sh_page_is_va_range_mapped_ptp(ptp,temp_ptr,pba->block_pages*SH_PAGE_SIZE);
if (status==SH_STATUS_VA_FULLY_MAPPED || status==SH_STATUS_VA_PARTIALLY_MAPPED) {
return status;
} else if (sh_status_error(status)) {
return status;
} else if (status!=SH_STATUS_VA_NOT_MAPPED) {
return status;
}
status=sh_page_map_contiguous_pages_range_ptp(ptp,temp_ptr,block_pa,SH_PAGE_RW | SH_PAGE_NX | SH_PAGE_PRESENT,pba->block_pages*SH_PAGE_SIZE);
if (sh_status_error(status)) {
SH_STATUS status2=sh_page_set_pages_range_bitmap((sh_uint8*)sh_page_get_physical_bitmap_ptr(),sh_page_get_physical_memory_amount_pages(),block_pa/SH_PAGE_SIZE,pba->block_pages,SH_FALSE);
if (sh_status_error(status2)) return status2;
return status;
}
*ptr=temp_ptr;
}
pba->block_count++;
return SH_STATUS_SUCCESS;
}

View File

@@ -0,0 +1,860 @@
// SPDX-License-Identifier: MPL-2.0
#include "memory/pez/pez.h"
#include "memory/pez/pez_debug.h"
#include "kernel/log.h"
sh_bool sh_pez_is_pez_available=SH_FALSE;
sh_pez_PHYSICAL_PLANE *reference_phys_plane=SH_NULLPTR;
void sh_pez_set_available() {
sh_pez_is_pez_available=SH_TRUE;
}
sh_bool sh_pez_is_available() {
return sh_pez_is_pez_available;
}
static void sh_pez_set_reference_phys_plane(sh_pez_PHYSICAL_PLANE *phys_plane) {
reference_phys_plane=phys_plane;
}
sh_pez_PHYSICAL_PLANE* sh_pez_get_reference_phys_plane() {
return reference_phys_plane;
}
static inline void sh_pez_internal_pack_index(sh_uint8 *dest,sh_uint32 index) {
dest[0]=(sh_uint8)(index & 0xFF);
dest[1]=(sh_uint8)((index>>8)&0xFF);
dest[2]=(sh_uint8)((index>>16)&0xFF);
return;
}
static inline sh_uint32 sh_pez_internal_unpack_index(sh_uint8 *src) {
return (sh_uint32)src[0] | ((sh_uint32)src[1]<<8) | ((sh_uint32)src[2]<<16);
}
typedef struct {
sh_uint32 region_index;
sh_uint32 previous_index;
} sh_pez_internal_BOUNDARY_ENTRY;
static inline sh_page_VIRTUAL_ADDRESS sh_pez_internal_pack_boundary(sh_uint32 region,sh_uint32 prev) {
return (sh_page_VIRTUAL_ADDRESS)(((sh_uint64)prev<<32) | region);
}
static inline sh_pez_internal_BOUNDARY_ENTRY sh_pez_internal_unpack_boundary(sh_page_VIRTUAL_ADDRESS value) {
sh_pez_internal_BOUNDARY_ENTRY entry;
entry.region_index=(sh_uint32)(value & 0xFFFFFFFF);
entry.previous_index=(sh_uint32)(value>>32);
return entry;
}
static SH_STATUS sh_pez_internal_scan_physical_bitmap(sh_pez_PHYSICAL_PLANE *phys_plane) {
if (phys_plane==SH_NULLPTR) return SH_STATUS_INVALID_PARAMETER;
sh_log_fdebug(SH_LOG_SOURCE_PEZ,"Scanning physical bitmap:\n");
sh_uint64 *bitmap64=(sh_uint64*)phys_plane->physical_bitmap;
sh_uint32 current_page=0;
sh_uint64 free_region_count=0;
sh_pez_debug_BITMAP bitmap_struct;
while (current_page<phys_plane->physical_page_count) {
if ((current_page%64)==0) {
while (current_page+64<=phys_plane->physical_page_count && bitmap64[current_page/64]==0xFFFFFFFFFFFFFFFF) {
current_page+=64;
}
}
if (current_page<phys_plane->physical_page_count && (sh_page_is_allocated(phys_plane->physical_bitmap,current_page)==0)) {
sh_uint32 start=current_page;
while (current_page<phys_plane->physical_page_count && sh_page_is_allocated(phys_plane->physical_bitmap,current_page)==0) {
current_page++;
}
sh_uint32 size=current_page-start;
bitmap_struct.regions[free_region_count].start=start;
bitmap_struct.regions[free_region_count].size=size;
free_region_count++;
if (free_region_count==512) {
return SH_STATUS_TOO_MUCH_DATA;
}
} else if (current_page<phys_plane->physical_page_count) {
current_page++;
}
}
bitmap_struct.count=(sh_uint32)free_region_count;
sh_pez_debug_send_bitmap(&bitmap_struct);
return SH_STATUS_SUCCESS;
}
static SH_STATUS sh_pez_internal_scan_boundary_radix_physical(sh_pez_PHYSICAL_PLANE *phys_plane) {
if (phys_plane==SH_NULLPTR) return SH_STATUS_INVALID_PARAMETER;
sh_log_fdebug(SH_LOG_SOURCE_PEZ,"Scanning boundary radix:\n");
sh_uint64 free_region_count=0;
sh_uint64 stop=sh_page_get_physical_memory_amount_pages();
sh_pez_debug_BOUNDARY_RADIX boundary_radix;
sh_bool is_in_region=SH_FALSE;
for (sh_iter64 i=0;i<stop;i++) {
sh_page_VIRTUAL_ADDRESS boundary;
SH_STATUS status=sh_radix_tree_get_value(&phys_plane->boundary_radix_tree,i,&boundary);
if (sh_status_error(status) && status!=SH_STATUS_NOT_FOUND) return status;
if (status==SH_STATUS_NOT_FOUND) continue;
if (is_in_region==SH_FALSE) {
boundary_radix.regions[free_region_count].pos_start=(sh_uint32)i;
sh_pez_internal_BOUNDARY_ENTRY boundary_unpack=sh_pez_internal_unpack_boundary(boundary);
boundary_radix.regions[free_region_count].idx_start=boundary_unpack.region_index;
boundary_radix.regions[free_region_count].prev_start=boundary_unpack.previous_index;
is_in_region=SH_TRUE;
continue;
} else {
sh_pez_internal_BOUNDARY_ENTRY boundary_unpack=sh_pez_internal_unpack_boundary(boundary);
// check to see if region is one page wide or more
if (boundary_unpack.region_index==boundary_radix.regions[free_region_count].idx_start) {
boundary_radix.regions[free_region_count].pos_end=(sh_uint32)i;
boundary_radix.regions[free_region_count].idx_end=boundary_unpack.region_index;
boundary_radix.regions[free_region_count].prev_end=boundary_unpack.previous_index;
is_in_region=SH_FALSE;
free_region_count++;
if (free_region_count==512) {
return SH_STATUS_TOO_MUCH_DATA;
}
continue;
} else {
boundary_radix.regions[free_region_count].pos_end=boundary_radix.regions[free_region_count].pos_start;
boundary_radix.regions[free_region_count].idx_end=boundary_radix.regions[free_region_count].idx_start;
boundary_radix.regions[free_region_count].prev_end=boundary_radix.regions[free_region_count].prev_start;
is_in_region=SH_FALSE;
free_region_count++;
if (free_region_count==512) {
return SH_STATUS_TOO_MUCH_DATA;
}
continue;
}
}
}
boundary_radix.count=(sh_uint32)free_region_count;
sh_pez_debug_send_boundary_radix(&boundary_radix);
return SH_STATUS_SUCCESS;
}
static SH_STATUS sh_pez_internal_check_physical_radix(sh_pez_PHYSICAL_PLANE *phys_plane) {
if (phys_plane==SH_NULLPTR) return SH_STATUS_INVALID_PARAMETER;
sh_page_MEM_STATS mem_stats;
SH_STATUS status=sh_page_get_memory_stats(&mem_stats);
for (sh_iter64 i=1;i<mem_stats.largest_free_block+1;i++) {
sh_uint64 pos=0;
sh_pez_REGION_PHYSICAL_OBJECT *reg;
sh_page_VIRTUAL_ADDRESS index;
status=sh_radix_tree_get_value(&phys_plane->region_radix_tree,i,&index);
if (sh_status_error(status) && status!=SH_STATUS_NOT_FOUND) return status;
sh_slab_reg_phys_OBJECT_INDEX idx=(sh_uint32)index;
if (status==SH_STATUS_NOT_FOUND) continue;
while (SH_TRUE) {
reg=sh_slab_reg_phys_ref_to_ptr(phys_plane->slab_reg_phys,idx);
if (reg==SH_NULLPTR) return SH_STATUS_ERROR_NULLPTR_RETURNED;
if (reg->region_size_pages==0 || reg->start_page_index==0) {
sh_log_fcritical(SH_LOG_SOURCE_PEZ,"Found free region that have either his address or his size starting at 0 (#%8u in size list) : [0x%x - 0x%x[; Size in object: %8u pages; Size in list: %8u pages\n",pos,((sh_uint64)reg->start_page_index)*SH_PAGE_SIZE,(((sh_uint64)reg->start_page_index)+reg->region_size_pages)*SH_PAGE_SIZE,reg->region_size_pages,i);
return SH_STATUS_PEZ_CORRUPTED;
}
if (reg->region_size_pages!=i) {
sh_log_fcritical(SH_LOG_SOURCE_PEZ,"Found free region that doesn't have his placement (#%8u in size list) and size matching : [0x%x - 0x%x[; Size in object: %8u pages; Size in list: %8u pages\n",pos,((sh_uint64)reg->start_page_index)*SH_PAGE_SIZE,(((sh_uint64)reg->start_page_index)+reg->region_size_pages)*SH_PAGE_SIZE,reg->region_size_pages,i);
return SH_STATUS_PEZ_CORRUPTED;
}
for (sh_uint64 y=reg->start_page_index;y<(sh_uint64)(reg->start_page_index+reg->region_size_pages);y++) {
if (sh_page_is_allocated(phys_plane->physical_bitmap,y)) {
sh_log_fcritical(SH_LOG_SOURCE_PEZ,"Found free region that have a page allocated (#%8u in size list) : [0x%x - 0x%x[; Size in object: %8u pages; Size in list: %8u pages; Concerned page: 0x%x\n",pos,((sh_uint64)reg->start_page_index)*SH_PAGE_SIZE,(((sh_uint64)reg->start_page_index)+reg->region_size_pages)*SH_PAGE_SIZE,reg->region_size_pages,i,((sh_uint64)y)*SH_PAGE_SIZE);
return SH_STATUS_PEZ_CORRUPTED;
}
}
if (!sh_page_is_allocated(phys_plane->physical_bitmap,reg->start_page_index-1)) {
sh_log_fcritical(SH_LOG_SOURCE_PEZ,"Found free region that doesn't fully extend at left, found a page free at left (#%8u in size list) : [0x%x - 0x%x[; Size in object: %8u pages; Size in list: %8u pages; Concerned page: 0x%x\n",pos,((sh_uint64)reg->start_page_index)*SH_PAGE_SIZE,(((sh_uint64)reg->start_page_index)+reg->region_size_pages)*SH_PAGE_SIZE,reg->region_size_pages,i,((sh_uint64)reg->start_page_index-1)*SH_PAGE_SIZE);
return SH_STATUS_PEZ_CORRUPTED;
}
if (!sh_page_is_allocated(phys_plane->physical_bitmap,reg->start_page_index+reg->region_size_pages) && reg->start_page_index+reg->region_size_pages!=sh_page_get_physical_memory_amount_pages()) {
sh_log_fcritical(SH_LOG_SOURCE_PEZ,"Found free region that doesn't fully extend at right, found a page free at right (#%8u in size list) : [0x%x - 0x%x[; Size in object: %8u pages; Size in list: %8u pages; Concerned page: 0x%x\n",pos,((sh_uint64)reg->start_page_index)*SH_PAGE_SIZE,(((sh_uint64)reg->start_page_index)+reg->region_size_pages)*SH_PAGE_SIZE,reg->region_size_pages,i,((sh_uint64)(reg->start_page_index+reg->region_size_pages))*SH_PAGE_SIZE);
return SH_STATUS_PEZ_CORRUPTED;
}
if (sh_pez_internal_unpack_index(reg->next_region_index)==0) {
break;
} else {
idx=sh_pez_internal_unpack_index(reg->next_region_index);
pos++;
}
}
}
return SH_STATUS_SUCCESS;
}
static SH_STATUS sh_pez_internal_scan_size_list_physical(sh_pez_PHYSICAL_PLANE *phys_plane) {
if (phys_plane==SH_NULLPTR) return SH_STATUS_INVALID_PARAMETER;
sh_page_MEM_STATS mem_stats;
SH_STATUS status=sh_page_get_memory_stats(&mem_stats);
sh_log_fdebug(SH_LOG_SOURCE_PEZ,"Scanning size list radix:\n");
sh_uint64 free_region_count=0;
sh_log_byte(SH_PEZ_DEBUG_SIZE_LIST_BLOCK_HEADER);
sh_log_byte('\n');
for (sh_iter64 i=1;i<mem_stats.largest_free_block+1;i++) {
sh_pez_REGION_PHYSICAL_OBJECT *reg;
sh_page_VIRTUAL_ADDRESS index;
status=sh_radix_tree_get_value(&phys_plane->region_radix_tree,i,&index);
if (sh_status_error(status) && status!=SH_STATUS_NOT_FOUND) return status;
sh_slab_reg_phys_OBJECT_INDEX idx=(sh_uint32)index;
if (status==SH_STATUS_NOT_FOUND) continue;
sh_uint64 size_list_region_count=0;
sh_pez_debug_SIZE_LIST size_list;
size_list.size=(sh_uint32)i;
while (SH_TRUE) {
reg=sh_slab_reg_phys_ref_to_ptr(phys_plane->slab_reg_phys,idx);
if (reg==SH_NULLPTR) return SH_STATUS_ERROR_NULLPTR_RETURNED;
size_list.regions[size_list_region_count].start=reg->start_page_index;
size_list.regions[size_list_region_count].size=reg->region_size_pages;
size_list.regions[size_list_region_count].idx=idx;
size_list.regions[size_list_region_count].next_idx=sh_pez_internal_unpack_index(reg->next_region_index);
free_region_count++;
size_list_region_count++;
if (size_list_region_count==512) {
return SH_STATUS_TOO_MUCH_DATA;
}
if (sh_pez_internal_unpack_index(reg->next_region_index)==0) {
break;
} else {
idx=sh_pez_internal_unpack_index(reg->next_region_index);
}
}
size_list.count=(sh_uint32)size_list_region_count;
sh_pez_debug_send_size_list(&size_list);
}
return SH_STATUS_SUCCESS;
}
static SH_STATUS sh_pez_internal_create_free_region_physical(sh_pez_PHYSICAL_PLANE *phys_plane,sh_uint32 region_start,sh_uint32 region_size,sh_pez_REGION_PHYSICAL_OBJECT **region) {
if (phys_plane==SH_NULLPTR || region_size==0 || region==SH_NULLPTR) return SH_STATUS_INVALID_PARAMETER;
sh_slab_reg_phys_OBJECT_INDEX reg_idx;
SH_STATUS status=sh_slab_reg_phys_alloc(phys_plane->slab_reg_phys,phys_plane->kernel_ptp,&reg_idx);
if (sh_status_error(status)) return status;
sh_pez_REGION_PHYSICAL_OBJECT *reg=sh_slab_reg_phys_ref_to_ptr(phys_plane->slab_reg_phys,reg_idx);
if (reg==SH_NULLPTR) return SH_STATUS_ERROR_NULLPTR_RETURNED;
reg->start_page_index=region_start;
reg->region_size_pages=region_size;
sh_page_VIRTUAL_ADDRESS head_index=0;
status=sh_radix_tree_get_value(&phys_plane->region_radix_tree,(sh_uint64)region_size,&head_index);
if (sh_status_error(status) && status!=SH_STATUS_NOT_FOUND) return status;
sh_page_VIRTUAL_ADDRESS new_boundary_val=sh_pez_internal_pack_boundary(reg_idx,0);
status=sh_radix_tree_insert_value(phys_plane->slab_radix_node,phys_plane->kernel_ptp,&phys_plane->boundary_radix_tree,(sh_uint64)region_start,new_boundary_val);
if (sh_status_error(status)) return status;
status=sh_radix_tree_insert_value(phys_plane->slab_radix_node,phys_plane->kernel_ptp,&phys_plane->boundary_radix_tree,(sh_uint64)region_start+region_size-1,new_boundary_val);
if (sh_status_error(status)) return status;
if (head_index!=0) {
sh_pez_REGION_PHYSICAL_OBJECT *old_head_ptr=sh_slab_reg_phys_ref_to_ptr(phys_plane->slab_reg_phys,(sh_uint32)head_index);
if (old_head_ptr==SH_NULLPTR) return SH_STATUS_ERROR_NULLPTR_RETURNED;
sh_page_VIRTUAL_ADDRESS updated_old_head_boundary=sh_pez_internal_pack_boundary((sh_uint32)head_index,reg_idx);
status=sh_radix_tree_insert_value(phys_plane->slab_radix_node,phys_plane->kernel_ptp,&phys_plane->boundary_radix_tree,(sh_uint64)old_head_ptr->start_page_index,updated_old_head_boundary);
if (sh_status_error(status)) return status;
sh_radix_tree_insert_value(phys_plane->slab_radix_node,phys_plane->kernel_ptp,&phys_plane->boundary_radix_tree,(sh_uint64)old_head_ptr->start_page_index+old_head_ptr->region_size_pages-1,updated_old_head_boundary);
if (sh_status_error(status)) return status;
sh_pez_internal_pack_index(reg->next_region_index,(sh_uint32)head_index);
} else {
sh_pez_internal_pack_index(reg->next_region_index,0);
}
status=sh_radix_tree_insert_value(phys_plane->slab_radix_node,phys_plane->kernel_ptp,&phys_plane->region_radix_tree,(sh_uint64)region_size,(sh_page_VIRTUAL_ADDRESS)reg_idx);
if (sh_status_error(status)) return status;
*region=reg;
return SH_STATUS_SUCCESS;
}
static SH_STATUS sh_pez_internal_check_region_integrity_physical(sh_pez_PHYSICAL_PLANE *phys_plane,sh_pez_REGION_PHYSICAL_OBJECT *reg,sh_bool *optional_is_first,sh_slab_reg_phys_OBJECT_INDEX *optional_reg_idx,sh_slab_reg_phys_OBJECT_INDEX *optional_prev_idx) {
if (phys_plane==SH_NULLPTR || reg==SH_NULLPTR) return SH_STATUS_INVALID_PARAMETER;
sh_page_VIRTUAL_ADDRESS boundary_left;
sh_page_VIRTUAL_ADDRESS boundary_right;
SH_STATUS status=sh_radix_tree_get_value(&phys_plane->boundary_radix_tree,reg->start_page_index,&boundary_left);
if (sh_status_error(status)) return status;
status=sh_radix_tree_get_value(&phys_plane->boundary_radix_tree,reg->start_page_index+reg->region_size_pages-1,&boundary_right);
if (sh_status_error(status)) return status;
if (boundary_left!=boundary_right) return SH_STATUS_PEZ_CORRUPTED;
sh_pez_internal_BOUNDARY_ENTRY boundary=sh_pez_internal_unpack_boundary(boundary_left);
sh_bool should_be_first;
if (boundary.previous_index==0) {
should_be_first=SH_TRUE;
} else {
should_be_first=SH_FALSE;
}
sh_page_VIRTUAL_ADDRESS reg_idx;
status=sh_radix_tree_get_value(&phys_plane->region_radix_tree,reg->region_size_pages,&reg_idx);
if (sh_status_error(status)) return status;
sh_pez_REGION_PHYSICAL_OBJECT *region=sh_slab_reg_phys_ref_to_ptr(phys_plane->slab_reg_phys,(sh_uint32)reg_idx);
if (region==SH_NULLPTR) return SH_STATUS_ERROR_NULLPTR_RETURNED;
if ((!should_be_first && region==reg) || (should_be_first && region!=reg)) {
return SH_STATUS_PEZ_CORRUPTED;
}
if (optional_is_first!=SH_NULLPTR) {
*optional_is_first=should_be_first;
}
if (optional_reg_idx!=SH_NULLPTR) {
*optional_reg_idx=boundary.region_index;
}
if (optional_prev_idx!=SH_NULLPTR) {
*optional_prev_idx=boundary.previous_index;
}
return SH_STATUS_SUCCESS;
}
static SH_STATUS sh_pez_internal_delete_free_region_physical(sh_pez_PHYSICAL_PLANE *phys_plane,sh_pez_REGION_PHYSICAL_OBJECT *reg) {
if (phys_plane==SH_NULLPTR || reg==SH_NULLPTR) return SH_STATUS_INVALID_PARAMETER;
sh_bool is_first;
sh_slab_reg_phys_OBJECT_INDEX reg_idx;
sh_slab_reg_phys_OBJECT_INDEX prev_idx;
SH_STATUS status=sh_pez_internal_check_region_integrity_physical(phys_plane,reg,&is_first,&reg_idx,&prev_idx);
if (sh_status_error(status)) return status;
if (is_first) {
// if region is the first of the list
if (sh_pez_internal_unpack_index(reg->next_region_index)==0) {
// if region was alone in his list
// delete radix entry
status=sh_radix_tree_delete_value(phys_plane->slab_radix_node,&phys_plane->region_radix_tree,reg->region_size_pages);
if (sh_status_error(status)) return status;
// delete left boundary
status=sh_radix_tree_delete_value(phys_plane->slab_radix_node,&phys_plane->boundary_radix_tree,reg->start_page_index);
if (sh_status_error(status)) return status;
// delete right boundary
if (reg->region_size_pages!=1) {
status=sh_radix_tree_delete_value(phys_plane->slab_radix_node,&phys_plane->boundary_radix_tree,reg->start_page_index+reg->region_size_pages-1);
if (sh_status_error(status)) return status;
}
// delete region object
status=sh_slab_reg_phys_dealloc(phys_plane->slab_reg_phys,reg_idx);
if (sh_status_error(status)) return status;
return SH_STATUS_SUCCESS;
} else {
// if region isn't alone in his list
// obtain next region informations
sh_slab_reg_phys_OBJECT_INDEX next_reg_idx=sh_pez_internal_unpack_index(reg->next_region_index);
sh_pez_REGION_PHYSICAL_OBJECT *next_region=sh_slab_reg_phys_ref_to_ptr(phys_plane->slab_reg_phys,next_reg_idx);
if (next_region==SH_NULLPTR) return SH_STATUS_ERROR_NULLPTR_RETURNED;
// insert next region as first inside size list
status=sh_radix_tree_insert_value(phys_plane->slab_radix_node,phys_plane->kernel_ptp,&phys_plane->region_radix_tree,reg->region_size_pages,next_reg_idx);
if (sh_status_error(status)) return status;
// update left boundary of next region
sh_page_VIRTUAL_ADDRESS new_boundary_for_next_region=sh_pez_internal_pack_boundary(next_reg_idx,0);
status=sh_radix_tree_insert_value(phys_plane->slab_radix_node,phys_plane->kernel_ptp,&phys_plane->boundary_radix_tree,next_region->start_page_index,new_boundary_for_next_region);
if (sh_status_error(status)) return status;
// update right boundary of next region
status=sh_radix_tree_insert_value(phys_plane->slab_radix_node,phys_plane->kernel_ptp,&phys_plane->boundary_radix_tree,next_region->start_page_index+next_region->region_size_pages-1,new_boundary_for_next_region);
if (sh_status_error(status)) return status;
// delete left boundary
status=sh_radix_tree_delete_value(phys_plane->slab_radix_node,&phys_plane->boundary_radix_tree,reg->start_page_index);
if (sh_status_error(status)) return status;
// delete right boundary
if (reg->region_size_pages!=1) {
status=sh_radix_tree_delete_value(phys_plane->slab_radix_node,&phys_plane->boundary_radix_tree,reg->start_page_index+reg->region_size_pages-1);
if (sh_status_error(status)) return status;
}
// delete region object
status=sh_slab_reg_phys_dealloc(phys_plane->slab_reg_phys,reg_idx);
if (sh_status_error(status)) return status;
return SH_STATUS_SUCCESS;
}
} else {
// if region isn't the first of his list
// obtain information about prev region
sh_pez_REGION_PHYSICAL_OBJECT *prev_region=sh_slab_reg_phys_ref_to_ptr(phys_plane->slab_reg_phys,prev_idx);
if (prev_region==SH_NULLPTR) return SH_STATUS_ERROR_NULLPTR_RETURNED;
if (sh_pez_internal_unpack_index(reg->next_region_index)==0) {
// if region is at the end of the size list
// put next_idx of prev region to 0
sh_pez_internal_pack_index(prev_region->next_region_index,0);
// delete left boundary
status=sh_radix_tree_delete_value(phys_plane->slab_radix_node,&phys_plane->boundary_radix_tree,reg->start_page_index);
if (sh_status_error(status)) return status;
// delete right boundary
if (reg->region_size_pages!=1) {
status=sh_radix_tree_delete_value(phys_plane->slab_radix_node,&phys_plane->boundary_radix_tree,reg->start_page_index+reg->region_size_pages-1);
if (sh_status_error(status)) return status;
}
// delete region object
status=sh_slab_reg_phys_dealloc(phys_plane->slab_reg_phys,reg_idx);
if (sh_status_error(status)) return status;
return SH_STATUS_SUCCESS;
} else {
// if region is in the middle of the size list
// obtain information about next region
sh_slab_reg_phys_OBJECT_INDEX next_reg_idx=sh_pez_internal_unpack_index(reg->next_region_index);
sh_pez_REGION_PHYSICAL_OBJECT *next_region=sh_slab_reg_phys_ref_to_ptr(phys_plane->slab_reg_phys,next_reg_idx);
if (next_region==SH_NULLPTR) return SH_STATUS_ERROR_NULLPTR_RETURNED;
// put next_idx of prev region to next_region_idx
sh_pez_internal_pack_index(prev_region->next_region_index,next_reg_idx);
// update left boundary of next region
sh_page_VIRTUAL_ADDRESS new_boundary_for_next_region=sh_pez_internal_pack_boundary(next_reg_idx,prev_idx);
status=sh_radix_tree_insert_value(phys_plane->slab_radix_node,phys_plane->kernel_ptp,&phys_plane->boundary_radix_tree,next_region->start_page_index,new_boundary_for_next_region);
if (sh_status_error(status)) return status;
// update right boundary of next region
status=sh_radix_tree_insert_value(phys_plane->slab_radix_node,phys_plane->kernel_ptp,&phys_plane->boundary_radix_tree,next_region->start_page_index+next_region->region_size_pages-1,new_boundary_for_next_region);
if (sh_status_error(status)) return status;
// delete left boundary
status=sh_radix_tree_delete_value(phys_plane->slab_radix_node,&phys_plane->boundary_radix_tree,reg->start_page_index);
if (sh_status_error(status)) return status;
// delete right boundary
if (reg->region_size_pages!=1) {
status=sh_radix_tree_delete_value(phys_plane->slab_radix_node,&phys_plane->boundary_radix_tree,reg->start_page_index+reg->region_size_pages-1);
if (sh_status_error(status)) return status;
}
// delete region object
status=sh_slab_reg_phys_dealloc(phys_plane->slab_reg_phys,reg_idx);
if (sh_status_error(status)) return status;
return SH_STATUS_SUCCESS;
}
}
}
SH_STATUS sh_pez_init_physical_plane(sh_uint8 *physical_bitmap,sh_uint64 physical_page_count,sh_slab_reg_phys_SLAB_ALLOCATOR *slab_reg_phys,struct sh_slab_radix_node_SLAB_ALLOCATOR *slab_radix_node,sh_page_PAGE_TABLE_POOL *kernel_ptp,sh_pez_PHYSICAL_PLANE *phys_plane) {
if (physical_bitmap==SH_NULLPTR || physical_page_count==0 || slab_reg_phys==SH_NULLPTR || slab_radix_node==SH_NULLPTR || kernel_ptp==SH_NULLPTR || phys_plane==SH_NULLPTR) return SH_STATUS_INVALID_PARAMETER;
sh_radix_tree_init(slab_radix_node,kernel_ptp,&phys_plane->region_radix_tree,8);
sh_radix_tree_init(slab_radix_node,kernel_ptp,&phys_plane->boundary_radix_tree,8);
phys_plane->free_pages=0;
phys_plane->used_pages=0;
phys_plane->physical_bitmap=physical_bitmap;
phys_plane->physical_page_count=physical_page_count;
phys_plane->slab_reg_phys=slab_reg_phys;
phys_plane->slab_radix_node=slab_radix_node;
phys_plane->kernel_ptp=kernel_ptp;
sh_uint64 *bitmap64=(sh_uint64*)physical_bitmap;
sh_uint32 current_page=0;
while (current_page<physical_page_count) {
if ((current_page%64)==0) {
while (current_page+64<=physical_page_count && bitmap64[current_page/64]==0xFFFFFFFFFFFFFFFF) {
current_page+=64;
}
}
if (current_page<physical_page_count && (sh_page_is_allocated(physical_bitmap,current_page)==0)) {
sh_uint32 start=current_page;
while (current_page<physical_page_count && sh_page_is_allocated(physical_bitmap,current_page)==0) {
current_page++;
}
sh_uint32 size=current_page-start;
sh_pez_REGION_PHYSICAL_OBJECT *reg=SH_NULLPTR;
SH_STATUS status=sh_pez_internal_create_free_region_physical(phys_plane,start,size,&reg);
if (sh_status_error(status)) return status;
} else if (current_page<physical_page_count) {
current_page++;
}
}
sh_page_MEM_STATS mem_stats;
SH_STATUS status=sh_page_get_memory_stats(&mem_stats);
if (sh_status_error(status)) return status;
phys_plane->free_pages=(sh_uint32)mem_stats.free_pages;
phys_plane->used_pages=(sh_uint32)mem_stats.used_pages;
sh_pez_set_reference_phys_plane(phys_plane);
return SH_STATUS_SUCCESS;
}
SH_STATUS sh_pez_alloc_physical_pages(sh_pez_PHYSICAL_PLANE *phys_plane,sh_uint32 pages_count,sh_page_PHYSICAL_ADDRESS *address) {
if (phys_plane==SH_NULLPTR || pages_count==0 || address==SH_NULLPTR) return SH_STATUS_INVALID_PARAMETER;
sh_page_VIRTUAL_ADDRESS reg_idx;
SH_STATUS status=sh_radix_tree_search_smallest_min_bound(phys_plane->slab_radix_node,&phys_plane->region_radix_tree,pages_count,&reg_idx);
if (sh_status_error(status) && status!=SH_STATUS_NOT_FOUND) return status;
if (status==SH_STATUS_NOT_FOUND) return SH_STATUS_OUT_OF_MEMORY;
sh_pez_REGION_PHYSICAL_OBJECT *reg=sh_slab_reg_phys_ref_to_ptr(phys_plane->slab_reg_phys,(sh_uint32)reg_idx);
if (reg==SH_NULLPTR) return SH_STATUS_ERROR_NULLPTR_RETURNED;
if (reg->region_size_pages<pages_count) {
// something has gone bad with successor function for finding a big enougth region
return SH_STATUS_PEZ_CORRUPTED;
} else if (reg->region_size_pages==pages_count) {
// exact fit case
// save metadata for later modifications
sh_uint32 start=reg->start_page_index;
// delete free region
status=sh_pez_internal_delete_free_region_physical(phys_plane,reg);
if (sh_status_error(status)) return status;
// mark pages as occupied inside physical bitmap
status=sh_page_set_pages_range_bitmap(phys_plane->physical_bitmap,phys_plane->physical_page_count,start,pages_count,SH_TRUE);
if (sh_status_error(status)) return status;
// give the address
*address=((sh_page_PHYSICAL_ADDRESS)start)*SH_PAGE_SIZE;
} else if (reg->region_size_pages>pages_count) {
// best fit case
// save metadata for later modifications
sh_uint32 start=reg->start_page_index;
// compute new size and index
sh_uint32 new_start=reg->start_page_index+pages_count;
if (new_start==0) return SH_STATUS_PEZ_CORRUPTED;
sh_uint32 new_size=reg->region_size_pages-pages_count;
if (new_size==0) return SH_STATUS_PEZ_CORRUPTED;
// delete free region
status=sh_pez_internal_delete_free_region_physical(phys_plane,reg);
if (sh_status_error(status)) return status;
// mark pages as occupied inside physical bitmap
status=sh_page_set_pages_range_bitmap(phys_plane->physical_bitmap,phys_plane->physical_page_count,start,pages_count,SH_TRUE);
if (sh_status_error(status)) return status;
// create new free region with splitted part
sh_pez_REGION_PHYSICAL_OBJECT *new_reg;
status=sh_pez_internal_create_free_region_physical(phys_plane,new_start,new_size,&new_reg);
if (sh_status_error(status)) return status;
// give the address
*address=((sh_page_PHYSICAL_ADDRESS)start)*SH_PAGE_SIZE;
}
phys_plane->free_pages=phys_plane->free_pages-pages_count;
phys_plane->used_pages=phys_plane->used_pages+pages_count;
return SH_STATUS_SUCCESS;
}
SH_STATUS sh_pez_free_physical_pages(sh_pez_PHYSICAL_PLANE *phys_plane,sh_page_PHYSICAL_ADDRESS *address,sh_uint32 pages_count) {
if (phys_plane==SH_NULLPTR || address==SH_NULLPTR || pages_count==0) return SH_STATUS_INVALID_PARAMETER;
// save freeed region data
sh_uint32 start_reg=(sh_uint32)((*address)/SH_PAGE_SIZE);
if (start_reg==0) return SH_STATUS_INVALID_PARAMETER;
sh_uint32 size_reg=pages_count;
// checking if region is entirely used
for (sh_iter64 i=0;i<pages_count;i++) {
if (!sh_page_is_allocated(phys_plane->physical_bitmap,start_reg+i)) {
return SH_STATUS_PAGE_ALREADY_FREE;
}
}
// marking pages as free
SH_STATUS status=sh_page_set_pages_range_bitmap(phys_plane->physical_bitmap,phys_plane->physical_page_count,start_reg,size_reg,SH_FALSE);
if (sh_status_error(status)) return status;
// identifying neighbours
// left
sh_page_VIRTUAL_ADDRESS left_neighbour;
status=sh_radix_tree_get_value(&phys_plane->boundary_radix_tree,start_reg-1,&left_neighbour);
if (sh_status_error(status) && status!=SH_STATUS_NOT_FOUND) return status;
sh_bool left_fusion;
if (status==SH_STATUS_NOT_FOUND) {
left_fusion=SH_FALSE;
} else {
left_fusion=SH_TRUE;
}
// right
sh_page_VIRTUAL_ADDRESS right_neighbour;
status=sh_radix_tree_get_value(&phys_plane->boundary_radix_tree,start_reg+size_reg,&right_neighbour);
if (sh_status_error(status) && status!=SH_STATUS_NOT_FOUND) return status;
sh_bool right_fusion;
if (status==SH_STATUS_NOT_FOUND) {
right_fusion=SH_FALSE;
} else {
right_fusion=SH_TRUE;
}
// preparing fusion
sh_uint32 new_start=start_reg;
sh_uint32 new_size=size_reg;
// fusionning left region
if (left_fusion) {
// obtaining information about left region
sh_pez_internal_BOUNDARY_ENTRY left_boundary=sh_pez_internal_unpack_boundary(left_neighbour);
sh_slab_reg_phys_OBJECT_INDEX left_reg_idx=left_boundary.region_index;
sh_pez_REGION_PHYSICAL_OBJECT *left_reg=sh_slab_reg_phys_ref_to_ptr(phys_plane->slab_reg_phys,left_reg_idx);
if (left_reg==SH_NULLPTR) return SH_STATUS_ERROR_NULLPTR_RETURNED;
// updating new region informations
new_start=left_reg->start_page_index;
if (new_start==0 || new_start>sh_page_get_physical_memory_amount_pages()) return SH_STATUS_PEZ_CORRUPTED;
new_size=new_size+left_reg->region_size_pages;
if (new_size==0 || new_size>sh_page_get_physical_memory_amount_pages()) return SH_STATUS_PEZ_CORRUPTED;
// deleting left region
status=sh_pez_internal_delete_free_region_physical(phys_plane,left_reg);
if (sh_status_error(status)) return status;
}
// fusionning right region
if (right_fusion) {
// obtaining information about right region
sh_pez_internal_BOUNDARY_ENTRY right_boundary=sh_pez_internal_unpack_boundary(right_neighbour);
sh_slab_reg_phys_OBJECT_INDEX right_reg_idx=right_boundary.region_index;
sh_pez_REGION_PHYSICAL_OBJECT *right_reg=sh_slab_reg_phys_ref_to_ptr(phys_plane->slab_reg_phys,right_reg_idx);
if (right_reg==SH_NULLPTR) return SH_STATUS_ERROR_NULLPTR_RETURNED;
// updating new region informations
new_size=new_size+right_reg->region_size_pages;
if (new_size==0 || new_size>sh_page_get_physical_memory_amount_pages()) return SH_STATUS_PEZ_CORRUPTED;
// deleting right region
status=sh_pez_internal_delete_free_region_physical(phys_plane,right_reg);
if (sh_status_error(status)) return status;
}
// inserting new region
sh_pez_REGION_PHYSICAL_OBJECT *new_reg;
status=sh_pez_internal_create_free_region_physical(phys_plane,new_start,new_size,&new_reg);
if (sh_status_error(status)) return status;
phys_plane->free_pages=phys_plane->free_pages+pages_count;
phys_plane->used_pages=phys_plane->used_pages-pages_count;
*address=0;
return SH_STATUS_SUCCESS;
}
SH_STATUS sh_pez_debug_physical(sh_pez_PHYSICAL_PLANE *phys_plane) {
sh_pez_internal_check_physical_radix(phys_plane);
sh_pez_internal_scan_physical_bitmap(phys_plane);
sh_pez_internal_scan_size_list_physical(phys_plane);
sh_pez_internal_scan_boundary_radix_physical(phys_plane);
return SH_STATUS_SUCCESS;
}
static SH_STATUS sh_pez_internal_create_free_region_virtual(sh_pez_VIRTUAL_PLANE *virt_plane,sh_uint32 region_start,sh_uint32 region_size,sh_pez_REGION_VIRTUAL_OBJECT **region) {
if (virt_plane==SH_NULLPTR || region_size==0 || region==SH_NULLPTR) return SH_STATUS_INVALID_PARAMETER;
sh_slab_reg_virt_OBJECT_INDEX reg_idx;
SH_STATUS status=sh_slab_reg_virt_alloc(virt_plane->slab_reg_virt,virt_plane->kernel_ptp,&reg_idx);
if (sh_status_error(status)) return status;
sh_pez_REGION_VIRTUAL_OBJECT *reg=sh_slab_reg_virt_ref_to_ptr(virt_plane->slab_reg_virt,reg_idx);
if (reg==SH_NULLPTR) return SH_STATUS_ERROR_NULLPTR_RETURNED;
reg->start_page_index=region_start;
reg->region_size_pages=region_size;
sh_page_VIRTUAL_ADDRESS head_index=0;
status=sh_radix_tree_get_value(&virt_plane->region_radix_tree,(sh_uint64)region_size,&head_index);
if (sh_status_error(status) && status!=SH_STATUS_NOT_FOUND) return status;
sh_page_VIRTUAL_ADDRESS new_boundary_val=sh_pez_internal_pack_boundary(reg_idx,0);
status=sh_radix_tree_insert_value(virt_plane->slab_radix_node,virt_plane->kernel_ptp,&virt_plane->boundary_radix_tree,(sh_uint64)region_start,new_boundary_val);
if (sh_status_error(status)) return status;
status=sh_radix_tree_insert_value(virt_plane->slab_radix_node,virt_plane->kernel_ptp,&virt_plane->boundary_radix_tree,(sh_uint64)region_start+region_size-1,new_boundary_val);
if (sh_status_error(status)) return status;
if (head_index!=0) {
sh_pez_REGION_PHYSICAL_OBJECT *old_head_ptr=sh_slab_reg_virt_ref_to_ptr(virt_plane->slab_reg_virt,(sh_uint32)head_index);
if (old_head_ptr==SH_NULLPTR) return SH_STATUS_ERROR_NULLPTR_RETURNED;
sh_page_VIRTUAL_ADDRESS updated_old_head_boundary=sh_pez_internal_pack_boundary((sh_uint32)head_index,reg_idx);
status=sh_radix_tree_insert_value(virt_plane->slab_radix_node,virt_plane->kernel_ptp,&virt_plane->boundary_radix_tree,(sh_uint64)old_head_ptr->start_page_index,updated_old_head_boundary);
if (sh_status_error(status)) return status;
sh_radix_tree_insert_value(virt_plane->slab_radix_node,virt_plane->kernel_ptp,&virt_plane->boundary_radix_tree,(sh_uint64)old_head_ptr->start_page_index+old_head_ptr->region_size_pages-1,updated_old_head_boundary);
if (sh_status_error(status)) return status;
reg->next_region_index=(sh_uint32)head_index;
} else {
reg->next_region_index=0;
}
status=sh_radix_tree_insert_value(virt_plane->slab_radix_node,virt_plane->kernel_ptp,&virt_plane->region_radix_tree,(sh_uint64)region_size,(sh_page_VIRTUAL_ADDRESS)reg_idx);
if (sh_status_error(status)) return status;
*region=reg;
return SH_STATUS_SUCCESS;
}
static SH_STATUS sh_pez_internal_check_region_integrity_virtual(sh_pez_VIRTUAL_PLANE *virt_plane,sh_pez_REGION_VIRTUAL_OBJECT *reg,sh_bool *optional_is_first,sh_slab_reg_virt_OBJECT_INDEX *optional_reg_idx,sh_slab_reg_virt_OBJECT_INDEX *optional_prev_idx) {
if (virt_plane==SH_NULLPTR || reg==SH_NULLPTR) return SH_STATUS_INVALID_PARAMETER;
sh_page_VIRTUAL_ADDRESS boundary_left;
sh_page_VIRTUAL_ADDRESS boundary_right;
SH_STATUS status=sh_radix_tree_get_value(&virt_plane->boundary_radix_tree,reg->start_page_index,&boundary_left);
if (sh_status_error(status)) return status;
status=sh_radix_tree_get_value(&virt_plane->boundary_radix_tree,reg->start_page_index+reg->region_size_pages-1,&boundary_right);
if (sh_status_error(status)) return status;
if (boundary_left!=boundary_right) return SH_STATUS_PEZ_CORRUPTED;
sh_pez_internal_BOUNDARY_ENTRY boundary=sh_pez_internal_unpack_boundary(boundary_left);
sh_bool should_be_first;
if (boundary.previous_index==0) {
should_be_first=SH_TRUE;
} else {
should_be_first=SH_FALSE;
}
sh_page_VIRTUAL_ADDRESS reg_idx;
status=sh_radix_tree_get_value(&virt_plane->region_radix_tree,reg->region_size_pages,&reg_idx);
if (sh_status_error(status)) return status;
sh_pez_REGION_VIRTUAL_OBJECT *region=sh_slab_reg_virt_ref_to_ptr(virt_plane->slab_reg_virt,(sh_uint32)reg_idx);
if (region==SH_NULLPTR) return SH_STATUS_ERROR_NULLPTR_RETURNED;
if ((!should_be_first && region==reg) || (should_be_first && region!=reg)) {
return SH_STATUS_PEZ_CORRUPTED;
}
if (optional_is_first!=SH_NULLPTR) {
*optional_is_first=should_be_first;
}
if (optional_reg_idx!=SH_NULLPTR) {
*optional_reg_idx=boundary.region_index;
}
if (optional_prev_idx!=SH_NULLPTR) {
*optional_prev_idx=boundary.previous_index;
}
return SH_STATUS_SUCCESS;
}
static SH_STATUS sh_pez_internal_delete_free_region_virtual(sh_pez_VIRTUAL_PLANE *virt_plane,sh_pez_REGION_VIRTUAL_OBJECT *reg) {
if (virt_plane==SH_NULLPTR || reg==SH_NULLPTR) return SH_STATUS_INVALID_PARAMETER;
sh_bool is_first;
sh_slab_reg_virt_OBJECT_INDEX reg_idx;
sh_slab_reg_virt_OBJECT_INDEX prev_idx;
SH_STATUS status=sh_pez_internal_check_region_integrity_virtual(virt_plane,reg,&is_first,&reg_idx,&prev_idx);
if (sh_status_error(status)) return status;
if (is_first) {
// if region is the first of the list
if (reg->next_region_index==0) {
// if region was alone in his list
// delete radix entry
status=sh_radix_tree_delete_value(virt_plane->slab_radix_node,&virt_plane->region_radix_tree,reg->region_size_pages);
if (sh_status_error(status)) return status;
// delete left boundary
status=sh_radix_tree_delete_value(virt_plane->slab_radix_node,&virt_plane->boundary_radix_tree,reg->start_page_index);
if (sh_status_error(status)) return status;
// delete right boundary
if (reg->region_size_pages!=1) {
status=sh_radix_tree_delete_value(virt_plane->slab_radix_node,&virt_plane->boundary_radix_tree,reg->start_page_index+reg->region_size_pages-1);
if (sh_status_error(status)) return status;
}
// delete region object
status=sh_slab_reg_virt_dealloc(virt_plane->slab_reg_virt,reg_idx);
if (sh_status_error(status)) return status;
return SH_STATUS_SUCCESS;
} else {
// if region isn't alone in his list
// obtain next region informations
sh_slab_reg_virt_OBJECT_INDEX next_reg_idx=reg->next_region_index;
sh_pez_REGION_VIRTUAL_OBJECT *next_region=sh_slab_reg_virt_ref_to_ptr(virt_plane->slab_reg_virt,next_reg_idx);
if (next_region==SH_NULLPTR) return SH_STATUS_ERROR_NULLPTR_RETURNED;
// insert next region as first inside size list
status=sh_radix_tree_insert_value(virt_plane->slab_radix_node,virt_plane->kernel_ptp,&virt_plane->region_radix_tree,reg->region_size_pages,next_reg_idx);
if (sh_status_error(status)) return status;
// update left boundary of next region
sh_page_VIRTUAL_ADDRESS new_boundary_for_next_region=sh_pez_internal_pack_boundary(next_reg_idx,0);
status=sh_radix_tree_insert_value(virt_plane->slab_radix_node,virt_plane->kernel_ptp,&virt_plane->boundary_radix_tree,next_region->start_page_index,new_boundary_for_next_region);
if (sh_status_error(status)) return status;
// update right boundary of next region
status=sh_radix_tree_insert_value(virt_plane->slab_radix_node,virt_plane->kernel_ptp,&virt_plane->boundary_radix_tree,next_region->start_page_index+next_region->region_size_pages-1,new_boundary_for_next_region);
if (sh_status_error(status)) return status;
// delete left boundary
status=sh_radix_tree_delete_value(virt_plane->slab_radix_node,&virt_plane->boundary_radix_tree,reg->start_page_index);
if (sh_status_error(status)) return status;
// delete right boundary
if (reg->region_size_pages!=1) {
status=sh_radix_tree_delete_value(virt_plane->slab_radix_node,&virt_plane->boundary_radix_tree,reg->start_page_index+reg->region_size_pages-1);
if (sh_status_error(status)) return status;
}
// delete region object
status=sh_slab_reg_virt_dealloc(virt_plane->slab_reg_virt,reg_idx);
if (sh_status_error(status)) return status;
return SH_STATUS_SUCCESS;
}
} else {
// if region isn't the first of his list
// obtain information about prev region
sh_pez_REGION_VIRTUAL_OBJECT *prev_region=sh_slab_reg_virt_ref_to_ptr(virt_plane->slab_reg_virt,prev_idx);
if (prev_region==SH_NULLPTR) return SH_STATUS_ERROR_NULLPTR_RETURNED;
if (reg->next_region_index==0) {
// if region is at the end of the size list
// put next_idx of prev region to 0
prev_region->next_region_index=0;
// delete left boundary
status=sh_radix_tree_delete_value(virt_plane->slab_radix_node,&virt_plane->boundary_radix_tree,reg->start_page_index);
if (sh_status_error(status)) return status;
// delete right boundary
if (reg->region_size_pages!=1) {
status=sh_radix_tree_delete_value(virt_plane->slab_radix_node,&virt_plane->boundary_radix_tree,reg->start_page_index+reg->region_size_pages-1);
if (sh_status_error(status)) return status;
}
// delete region object
status=sh_slab_reg_virt_dealloc(virt_plane->slab_reg_virt,reg_idx);
if (sh_status_error(status)) return status;
return SH_STATUS_SUCCESS;
} else {
// if region is in the middle of the size list
// obtain information about next region
sh_slab_reg_virt_OBJECT_INDEX next_reg_idx=reg->next_region_index;
sh_pez_REGION_VIRTUAL_OBJECT *next_region=sh_slab_reg_virt_ref_to_ptr(virt_plane->slab_reg_virt,next_reg_idx);
if (next_region==SH_NULLPTR) return SH_STATUS_ERROR_NULLPTR_RETURNED;
// put next_idx of prev region to next_region_idx
prev_region->next_region_index=next_reg_idx;
// update left boundary of next region
sh_page_VIRTUAL_ADDRESS new_boundary_for_next_region=sh_pez_internal_pack_boundary(next_reg_idx,prev_idx);
status=sh_radix_tree_insert_value(virt_plane->slab_radix_node,virt_plane->kernel_ptp,&virt_plane->boundary_radix_tree,next_region->start_page_index,new_boundary_for_next_region);
if (sh_status_error(status)) return status;
// update right boundary of next region
status=sh_radix_tree_insert_value(virt_plane->slab_radix_node,virt_plane->kernel_ptp,&virt_plane->boundary_radix_tree,next_region->start_page_index+next_region->region_size_pages-1,new_boundary_for_next_region);
if (sh_status_error(status)) return status;
// delete left boundary
status=sh_radix_tree_delete_value(virt_plane->slab_radix_node,&virt_plane->boundary_radix_tree,reg->start_page_index);
if (sh_status_error(status)) return status;
// delete right boundary
if (reg->region_size_pages!=1) {
status=sh_radix_tree_delete_value(virt_plane->slab_radix_node,&virt_plane->boundary_radix_tree,reg->start_page_index+reg->region_size_pages-1);
if (sh_status_error(status)) return status;
}
// delete region object
status=sh_slab_reg_virt_dealloc(virt_plane->slab_reg_virt,reg_idx);
if (sh_status_error(status)) return status;
return SH_STATUS_SUCCESS;
}
}
}
SH_STATUS sh_pez_init_virtual_plane(sh_page_VIRTUAL_ADDRESS plane_offset,sh_slab_reg_virt_SLAB_ALLOCATOR *slab_reg_virt,struct sh_slab_radix_node_SLAB_ALLOCATOR *slab_radix_node,sh_page_PAGE_TABLE_POOL *kernel_ptp,sh_page_PAGE_TABLE_POOL *reference_ptp,sh_pez_VIRTUAL_PLANE *virt_plane) {
if (slab_reg_virt==SH_NULLPTR || slab_radix_node==SH_NULLPTR || kernel_ptp==SH_NULLPTR || reference_ptp==SH_NULLPTR || virt_plane==SH_NULLPTR) return SH_STATUS_INVALID_PARAMETER;
sh_radix_tree_init(slab_radix_node,kernel_ptp,&virt_plane->region_radix_tree,8);
sh_radix_tree_init(slab_radix_node,kernel_ptp,&virt_plane->boundary_radix_tree,8);
virt_plane->free_pages=0xFFFFFFFF-1;
virt_plane->used_pages=0;
virt_plane->slab_reg_virt=slab_reg_virt;
virt_plane->slab_radix_node=slab_radix_node;
virt_plane->kernel_ptp=kernel_ptp;
virt_plane->reference_ptp=reference_ptp;
virt_plane->plane_offset=plane_offset;
sh_pez_REGION_VIRTUAL_OBJECT *reg;
SH_STATUS status=sh_pez_internal_create_free_region_virtual(virt_plane,0,0xFFFFFFFF-1,&reg);
if (sh_status_error(status)) return status;
return SH_STATUS_SUCCESS;
}
SH_STATUS sh_pez_alloc_virtual_pages(sh_pez_VIRTUAL_PLANE *virt_plane,sh_uint32 pages_count,sh_page_VIRTUAL_ADDRESS *address) {
if (virt_plane==SH_NULLPTR || pages_count==0 || address==SH_NULLPTR) return SH_STATUS_INVALID_PARAMETER;
sh_page_VIRTUAL_ADDRESS reg_idx;
SH_STATUS status=sh_radix_tree_search_smallest_min_bound(virt_plane->slab_radix_node,&virt_plane->region_radix_tree,pages_count,&reg_idx);
if (sh_status_error(status) && status!=SH_STATUS_NOT_FOUND) return status;
if (status==SH_STATUS_NOT_FOUND) return SH_STATUS_OUT_OF_MEMORY;
sh_pez_REGION_VIRTUAL_OBJECT *reg=sh_slab_reg_virt_ref_to_ptr(virt_plane->slab_reg_virt,(sh_uint32)reg_idx);
if (reg==SH_NULLPTR) return SH_STATUS_ERROR_NULLPTR_RETURNED;
if (reg->region_size_pages<pages_count) {
// something has gone bad with successor function for finding a big enougth region
return SH_STATUS_PEZ_CORRUPTED;
} else if (reg->region_size_pages==pages_count) {
// exact fit case
// save metadata for later modifications
sh_uint32 start=reg->start_page_index;
// delete free region
status=sh_pez_internal_delete_free_region_virtual(virt_plane,reg);
if (sh_status_error(status)) return status;
// give the address
*address=((sh_page_VIRTUAL_ADDRESS)start)*SH_PAGE_SIZE+virt_plane->plane_offset;
} else if (reg->region_size_pages>pages_count) {
// best fit case
// save metadata for later modifications
sh_uint32 start=reg->start_page_index;
// compute new size and index
sh_uint32 new_start=reg->start_page_index+pages_count;
if (new_start==0) return SH_STATUS_PEZ_CORRUPTED;
sh_uint32 new_size=reg->region_size_pages-pages_count;
if (new_size==0) return SH_STATUS_PEZ_CORRUPTED;
// delete free region
status=sh_pez_internal_delete_free_region_virtual(virt_plane,reg);
if (sh_status_error(status)) return status;
// create new free region with splitted part
sh_pez_REGION_VIRTUAL_OBJECT *new_reg;
status=sh_pez_internal_create_free_region_virtual(virt_plane,new_start,new_size,&new_reg);
if (sh_status_error(status)) return status;
// give the address
*address=((sh_page_VIRTUAL_ADDRESS)start)*SH_PAGE_SIZE+virt_plane->plane_offset;
}
virt_plane->free_pages=virt_plane->free_pages-pages_count;
virt_plane->used_pages=virt_plane->used_pages+pages_count;
return SH_STATUS_SUCCESS;
}
SH_STATUS sh_pez_free_virtual_pages(sh_pez_VIRTUAL_PLANE *virt_plane,sh_page_VIRTUAL_ADDRESS *address,sh_uint32 pages_count) {
if (virt_plane==SH_NULLPTR || address==SH_NULLPTR || pages_count==0) return SH_STATUS_INVALID_PARAMETER;
// save freeed region data
sh_uint32 start_reg=(sh_uint32)((*address)/SH_PAGE_SIZE-virt_plane->plane_offset);
sh_uint32 size_reg=pages_count;
// identifying neighbours
// left
sh_page_VIRTUAL_ADDRESS left_neighbour;
SH_STATUS status=sh_radix_tree_get_value(&virt_plane->boundary_radix_tree,start_reg-1,&left_neighbour);
if (sh_status_error(status) && status!=SH_STATUS_NOT_FOUND) return status;
sh_bool left_fusion;
if (status==SH_STATUS_NOT_FOUND) {
left_fusion=SH_FALSE;
} else {
left_fusion=SH_TRUE;
}
// right
sh_page_VIRTUAL_ADDRESS right_neighbour;
status=sh_radix_tree_get_value(&virt_plane->boundary_radix_tree,start_reg+size_reg,&right_neighbour);
if (sh_status_error(status) && status!=SH_STATUS_NOT_FOUND) return status;
sh_bool right_fusion;
if (status==SH_STATUS_NOT_FOUND) {
right_fusion=SH_FALSE;
} else {
right_fusion=SH_TRUE;
}
// preparing fusion
sh_uint32 new_start=start_reg;
sh_uint32 new_size=size_reg;
// fusionning left region
if (left_fusion) {
// obtaining information about left region
sh_pez_internal_BOUNDARY_ENTRY left_boundary=sh_pez_internal_unpack_boundary(left_neighbour);
sh_slab_reg_virt_OBJECT_INDEX left_reg_idx=left_boundary.region_index;
sh_pez_REGION_VIRTUAL_OBJECT *left_reg=sh_slab_reg_virt_ref_to_ptr(virt_plane->slab_reg_virt,left_reg_idx);
if (left_reg==SH_NULLPTR) return SH_STATUS_ERROR_NULLPTR_RETURNED;
// updating new region informations
new_start=left_reg->start_page_index;
new_size=new_size+left_reg->region_size_pages;
if (new_size==0) return SH_STATUS_PEZ_CORRUPTED;
// deleting left region
status=sh_pez_internal_delete_free_region_virtual(virt_plane,left_reg);
if (sh_status_error(status)) return status;
}
// fusionning right region
if (right_fusion) {
// obtaining information about right region
sh_pez_internal_BOUNDARY_ENTRY right_boundary=sh_pez_internal_unpack_boundary(right_neighbour);
sh_slab_reg_virt_OBJECT_INDEX right_reg_idx=right_boundary.region_index;
sh_pez_REGION_VIRTUAL_OBJECT *right_reg=sh_slab_reg_virt_ref_to_ptr(virt_plane->slab_reg_virt,right_reg_idx);
if (right_reg==SH_NULLPTR) return SH_STATUS_ERROR_NULLPTR_RETURNED;
// updating new region informations
new_size=new_size+right_reg->region_size_pages;
if (new_size==0) return SH_STATUS_PEZ_CORRUPTED;
// deleting right region
status=sh_pez_internal_delete_free_region_virtual(virt_plane,right_reg);
if (sh_status_error(status)) return status;
}
// inserting new region
sh_pez_REGION_VIRTUAL_OBJECT *new_reg;
status=sh_pez_internal_create_free_region_virtual(virt_plane,new_start,new_size,&new_reg);
if (sh_status_error(status)) return status;
virt_plane->free_pages=virt_plane->free_pages+pages_count;
virt_plane->used_pages=virt_plane->used_pages-pages_count;
*address=0;
return SH_STATUS_SUCCESS;
}

View File

@@ -0,0 +1,113 @@
// SPDX-License-Identifier: MPL-2.0
#include "memory/pez/pez_debug.h"
#include "kernel/log.h"
SH_STATUS sh_pez_debug_send_alloc(sh_pez_debug_ALLOC *alloc) {
sh_log_uint8_hex(SH_PEZ_DEBUG_ALLOC_HEADER);
sh_log_byte('a');
sh_log_uint32_hex(alloc->size_asked);
sh_log_byte('a');
sh_log_uint32_hex(alloc->found_region_start_index);
sh_log_byte('a');
sh_log_uint32_hex(alloc->found_region_size);
sh_log_byte('a');
sh_log_uint8_hex(alloc->is_exact_fit);
sh_log_byte('a');
sh_log_uint32_hex(alloc->remaining_size);
sh_log_byte('a');
sh_log_uint32_hex(alloc->new_start);
sh_log_byte('a');
sh_log_uint32_hex(alloc->reg_idx);
sh_log_byte('\n');
return SH_STATUS_SUCCESS;
}
SH_STATUS sh_pez_debug_send_free(sh_pez_debug_FREE *free) {
sh_log_uint8_hex(SH_PEZ_DEBUG_FREE_HEADER);
sh_log_byte('a');
sh_log_uint32_hex(free->region_start_freeed);
sh_log_byte('a');
sh_log_uint32_hex(free->size_freeed);
sh_log_byte('a');
sh_log_uint32_hex(free->left_region_idx);
sh_log_byte('a');
sh_log_uint32_hex(free->right_region_idx);
sh_log_byte('a');
sh_log_uint32_hex(free->left_region_size);
sh_log_byte('a');
sh_log_uint32_hex(free->right_region_size);
sh_log_byte('a');
sh_log_uint32_hex(free->left_region_start);
sh_log_byte('a');
sh_log_uint32_hex(free->right_region_start);
sh_log_byte('a');
sh_log_uint32_hex(free->final_inserted_region_idx);
sh_log_byte('a');
sh_log_uint32_hex(free->final_inserted_region_start);
sh_log_byte('a');
sh_log_uint32_hex(free->final_inserted_region_size);
sh_log_byte('a');
sh_log_uint8_hex(free->was_right_region_object_freeed);
sh_log_byte('a');
sh_log_uint8_hex(free->was_new_region_object_allocated);
sh_log_byte('a');
sh_log_uint32_hex(free->new_reg_obj_start);
sh_log_byte('a');
sh_log_uint32_hex(free->new_reg_obj_size);
sh_log_byte('\n');
return SH_STATUS_SUCCESS;
}
SH_STATUS sh_pez_debug_send_size_list(sh_pez_debug_SIZE_LIST *size_list) {
sh_log_uint8_hex(SH_PEZ_DEBUG_SIZE_LIST_HEADER);
sh_log_byte('a');
sh_log_uint32_hex(size_list->size);
sh_log_byte('a');
sh_log_uint32_hex(size_list->count);
sh_log_byte('\n');
for (sh_iter64 i=0;i<size_list->count;i++) {
sh_log_uint32_hex(size_list->regions[i].start);
sh_log_byte('a');
sh_log_uint32_hex(size_list->regions[i].size);
sh_log_byte('a');
sh_log_uint32_hex(size_list->regions[i].idx);
sh_log_byte('a');
sh_log_uint32_hex(size_list->regions[i].next_idx);
sh_log_byte('\n');
}
sh_log_byte('\n');
return SH_STATUS_SUCCESS;
}
SH_STATUS sh_pez_debug_send_boundary_radix(sh_pez_debug_BOUNDARY_RADIX *boundary_radix) {
sh_log_uint8_hex(SH_PEZ_DEBUG_BOUNDARY_RADIX_HEADER);
sh_log_byte('a');
sh_log_uint32_hex(boundary_radix->count);
sh_log_byte('\n');
for (sh_iter64 i=0;i<boundary_radix->count;i++) {
sh_log_uint32_hex(boundary_radix->regions[i].pos_start);
sh_log_byte('a');
sh_log_uint32_hex(boundary_radix->regions[i].idx_start);
sh_log_byte('a');
sh_log_uint32_hex(boundary_radix->regions[i].prev_start);
sh_log_byte('a');
sh_log_uint32_hex(boundary_radix->regions[i].pos_end);
sh_log_byte('a');
sh_log_uint32_hex(boundary_radix->regions[i].idx_end);
sh_log_byte('a');
sh_log_uint32_hex(boundary_radix->regions[i].prev_end);
sh_log_byte('\n');
}
sh_log_byte('\n');
return SH_STATUS_SUCCESS;
}
SH_STATUS sh_pez_debug_send_bitmap(sh_pez_debug_BITMAP *bitmap) {
sh_log_uint8_hex(SH_PEZ_DEBUG_BITMAP_REGIONS_HEADER);
sh_log_byte('a');
sh_log_uint32_hex(bitmap->count);
sh_log_byte('\n');
for (sh_iter64 i=0;i<bitmap->count;i++) {
sh_log_uint32_hex(bitmap->regions[i].start);
sh_log_byte('a');
sh_log_uint32_hex(bitmap->regions[i].size);
sh_log_byte('\n');
}
sh_log_byte('\n');
return SH_STATUS_SUCCESS;
}

View File

@@ -0,0 +1,182 @@
// SPDX-License-Identifier: MPL-2.0
#include "memory/pez/radix.h"
#include "memory/slabs/slab_radix_node.h"
SH_STATUS sh_radix_node_read_value(sh_radix_NODE *node,sh_uint8 index,sh_page_VIRTUAL_ADDRESS *value) {
if (node==SH_NULLPTR || index>15 || value==SH_NULLPTR) return SH_STATUS_INVALID_PARAMETER;
sh_page_VIRTUAL_ADDRESS val=node->ptr[index];
if (val==0) return SH_STATUS_NOT_FOUND;
*value=val;
return SH_STATUS_SUCCESS;
}
SH_STATUS sh_radix_node_set_value(struct sh_slab_radix_node_SLAB_ALLOCATOR *alloc,sh_radix_NODE *node,sh_uint8 index,sh_page_VIRTUAL_ADDRESS value) {
if (node==SH_NULLPTR || alloc==SH_NULLPTR|| index>15) return SH_STATUS_INVALID_PARAMETER;
sh_uint16 *bitmap_ptr=sh_slab_radix_node_get_node_bitmap(alloc,node);
if (bitmap_ptr==SH_NULLPTR) return SH_STATUS_ERROR_NULLPTR_RETURNED;
if (value!=0) {
*bitmap_ptr|=(1<<index);
} else {
*bitmap_ptr&= (sh_uint16)(~(1<<index));
}
node->ptr[index]=value;
return SH_STATUS_SUCCESS;
}
SH_STATUS sh_radix_tree_init(struct sh_slab_radix_node_SLAB_ALLOCATOR *alloc,sh_page_PAGE_TABLE_POOL *ptp,sh_radix_TREE *tree, sh_uint8 depth) {
if (tree==SH_NULLPTR || alloc==SH_NULLPTR) return SH_STATUS_INVALID_PARAMETER;
if (depth>16) return SH_STATUS_INVALID_PARAMETER;
tree->depth=depth;
sh_radix_NODE *root_node;
SH_STATUS status=sh_slab_radix_node_alloc(alloc,ptp,&root_node);
if (sh_status_error(status)) return status;
for (sh_uint8 i=0;i<16;i++) root_node->ptr[i]=0;
tree->root_node=root_node;
return SH_STATUS_SUCCESS;
}
SH_STATUS sh_radix_tree_get_value(sh_radix_TREE *tree,sh_uint64 key,sh_page_VIRTUAL_ADDRESS *value) {
if (tree==SH_NULLPTR || tree->root_node==SH_NULLPTR || value==SH_NULLPTR) return SH_STATUS_INVALID_PARAMETER;
sh_radix_NODE *current_node=tree->root_node;
sh_page_VIRTUAL_ADDRESS current_val=0;
SH_STATUS status;
for (sh_uint8 level=0;level<tree->depth;level++) {
sh_uint8 shift=(sh_uint8)((tree->depth-1-level)*4);
sh_uint8 index=(sh_uint8)((key>>shift)&0x0F);
status=sh_radix_node_read_value(current_node,index,&current_val);
if (sh_status_error(status)) {
return status;
}
if (level<(tree->depth-1)) {
current_node=(sh_radix_NODE *)current_val;
}
}
*value=current_val;
return SH_STATUS_SUCCESS;
}
SH_STATUS sh_radix_tree_insert_value(struct sh_slab_radix_node_SLAB_ALLOCATOR *alloc,sh_page_PAGE_TABLE_POOL *ptp,sh_radix_TREE *tree,sh_uint64 key,sh_page_VIRTUAL_ADDRESS value) {
if (tree==SH_NULLPTR || tree->root_node==SH_NULLPTR || alloc==SH_NULLPTR || ptp==SH_NULLPTR) return SH_STATUS_INVALID_PARAMETER;
sh_radix_NODE *current_node=tree->root_node;
SH_STATUS status;
for (sh_uint8 level=0;level<tree->depth;level++) {
sh_uint8 shift=(sh_uint8)((tree->depth-1-level)*4);
sh_uint8 index=(sh_uint8)((key>>shift)&0x0F);
if (level==(tree->depth-1)) {
return sh_radix_node_set_value(alloc,current_node,index,value);
}
sh_page_VIRTUAL_ADDRESS next_node_va;
status=sh_radix_node_read_value(current_node,index,&next_node_va);
if (status==SH_STATUS_NOT_FOUND) {
sh_radix_NODE *new_node;
status=sh_slab_radix_node_alloc(alloc,ptp,&new_node);
if (sh_status_error(status)) return status;
sh_uint8 i=0;
while(i<16) {
new_node->ptr[i]=0;
i++;
}
status=sh_radix_node_set_value(alloc,current_node,index,(sh_page_VIRTUAL_ADDRESS)new_node);
if (sh_status_error(status)) return status;
current_node=new_node;
} else if (status==SH_STATUS_SUCCESS) {
current_node=(sh_radix_NODE *)next_node_va;
} else {
return status;
}
}
return SH_STATUS_SUCCESS;
}
static SH_STATUS sh_radix_tree_delete_recursive(struct sh_slab_radix_node_SLAB_ALLOCATOR *alloc,sh_radix_NODE *current_node,sh_uint64 key,sh_uint8 depth,sh_uint8 current_level,sh_bool *is_empty_out) {
sh_uint8 shift=(sh_uint8)((depth-1-current_level)*4);
sh_uint8 index=(sh_uint8)((key>>shift)&0x0F);
SH_STATUS status;
if (current_level==(depth-1)) {
status=sh_radix_node_set_value(alloc,current_node,index,0);
if (sh_status_error(status)) return status;
} else {
sh_page_VIRTUAL_ADDRESS next_node_va=current_node->ptr[index];
if (next_node_va==0) return SH_STATUS_NOT_FOUND;
sh_radix_NODE *next_node=(sh_radix_NODE *)next_node_va;
sh_bool child_is_empty=SH_FALSE;
status=sh_radix_tree_delete_recursive(alloc,next_node,key,depth,current_level+1,&child_is_empty);
if (sh_status_error(status)) return status;
if (child_is_empty) {
status=sh_slab_radix_node_dealloc(alloc,next_node);
if (sh_status_error(status)) return status;
status=sh_radix_node_set_value(alloc,current_node,index,0);
if (sh_status_error(status)) return status;
}
}
sh_bool empty=SH_TRUE;
for (sh_uint8 i=0;i<16;i++) {
if (current_node->ptr[i]!=0) {
empty=SH_FALSE;
break;
}
}
if (is_empty_out) *is_empty_out=empty;
return SH_STATUS_SUCCESS;
}
SH_STATUS sh_radix_tree_delete_value(struct sh_slab_radix_node_SLAB_ALLOCATOR *alloc,sh_radix_TREE *tree,sh_uint64 key) {
if (tree==SH_NULLPTR || tree->root_node==SH_NULLPTR || alloc==SH_NULLPTR) return SH_STATUS_INVALID_PARAMETER;
sh_bool root_is_empty=SH_FALSE;
return sh_radix_tree_delete_recursive(alloc,tree->root_node,key,tree->depth,0,&root_is_empty);
}
SH_STATUS sh_radix_tree_search_smallest_min_bound(struct sh_slab_radix_node_SLAB_ALLOCATOR *alloc,sh_radix_TREE *tree,sh_uint64 lower_bound_key,sh_page_VIRTUAL_ADDRESS *value){
if (tree==SH_NULLPTR || tree->root_node==SH_NULLPTR || alloc==SH_NULLPTR || value==SH_NULLPTR) return SH_STATUS_INVALID_PARAMETER;
sh_uint8 depth=tree->depth;
sh_radix_NODE *node_stack[16];
sh_uint8 idx_stack[16];
sh_uint8 level=0;
node_stack[0]=tree->root_node;
while (level<depth) {
sh_uint8 shift=(sh_uint8)((depth-1-level)*4);
sh_uint8 index=(sh_uint8)((lower_bound_key>>shift)&0x0F);
idx_stack[level]=index;
if (level==depth-1) {
sh_radix_NODE *node=node_stack[level];
sh_uint16 *bmp=sh_slab_radix_node_get_node_bitmap(alloc,node);
sh_uint16 mask=(sh_uint16)(0xFFFF<<index) & *bmp;
if (mask!=0) {
sh_uint8 best=(sh_uint8)__builtin_ctz(mask);
*value=node->ptr[best];
return SH_STATUS_SUCCESS;
}
goto backtrack;
}
sh_radix_NODE *node=node_stack[level];
sh_page_VIRTUAL_ADDRESS child_va=node->ptr[index];
if (child_va!=0) {
node_stack[level+1]=(sh_radix_NODE *)child_va;
level++;
continue;
}
goto try_next_sibling;
try_next_sibling:;
sh_uint16 *bmp=sh_slab_radix_node_get_node_bitmap(alloc,node);
sh_uint8 next_index=index+1;
if (next_index>15) goto backtrack;
sh_uint16 mask=(sh_uint16)(0xFFFF<<next_index) & *bmp;
if (mask==0) goto backtrack;
sh_uint8 best=(sh_uint8)__builtin_ctz(mask);
node_stack[level+1]=(sh_radix_NODE *)node->ptr[best];
idx_stack[level]=best;
level++;
while (level<depth) {
sh_radix_NODE *cur=node_stack[level];
sh_uint16 *b=sh_slab_radix_node_get_node_bitmap(alloc,cur);
if (*b==0) goto backtrack;
sh_uint8 min_idx=(sh_uint8)__builtin_ctz(*b);
idx_stack[level]=min_idx;
if (level==depth-1) {
*value=cur->ptr[min_idx];
return SH_STATUS_SUCCESS;
}
node_stack[level+1]=(sh_radix_NODE *)cur->ptr[min_idx];
level++;
}
backtrack:
if (level==0) return SH_STATUS_NOT_FOUND;
level--;
node=node_stack[level];
index=idx_stack[level];
goto try_next_sibling;
}
return SH_STATUS_NOT_FOUND;
}

View File

@@ -0,0 +1,27 @@
// SPDX-License-Identifier: MPL-2.0
#include "memory/ring.h"
SH_STATUS sh_ring_write_byte(sh_ring_RING_BUFFER_HEADER *ring_buffer,sh_uint8 byte) {
if (ring_buffer==SH_NULLPTR) return SH_STATUS_INVALID_PARAMETER;
if (ring_buffer->buffer_bytes_size==0 || ring_buffer->data_start==SH_NULLPTR) return SH_STATUS_SUCCESS;
sh_uint32 next_head=(ring_buffer->head+1)%ring_buffer->buffer_bytes_size;
if (next_head==ring_buffer->tail) {
ring_buffer->tail=(ring_buffer->tail+1)%ring_buffer->buffer_bytes_size;
}
ring_buffer->data_start[ring_buffer->head]=byte;
ring_buffer->head=next_head;
ring_buffer->total_bytes_written++;
return SH_STATUS_SUCCESS;
}
SH_STATUS sh_ring_write_string(sh_ring_RING_BUFFER_HEADER *ring_buffer,char *string) {
if (ring_buffer==SH_NULLPTR || string==SH_NULLPTR) return SH_STATUS_INVALID_PARAMETER;
if (ring_buffer->buffer_bytes_size==0 || ring_buffer->data_start==SH_NULLPTR) return SH_STATUS_SUCCESS;
for (sh_uint32 i=0;string[i]!='\0';i++) {
sh_uint32 next_head=(ring_buffer->head+1)%ring_buffer->buffer_bytes_size;
if (next_head==ring_buffer->tail) {
ring_buffer->tail=(ring_buffer->tail+1)%ring_buffer->buffer_bytes_size;
}
ring_buffer->data_start[ring_buffer->head]=(sh_uint8)string[i];
ring_buffer->head=next_head;
}
return SH_STATUS_SUCCESS;
}

View File

@@ -0,0 +1,205 @@
// SPDX-License-Identifier: MPL-2.0
#include "memory/slabs/slab_generic.h"
#include "std/mem.h"
#include "kernel/log.h"
static sh_uint8 sig[8]=SH_SLAB_GENERIC_SLAB_SIG;
static sh_uint64 object_size_bytes[8]=SH_SLAB_GENERIC_OBJECT_SIZE_BYTES;
static sh_uint64 actual_objects_per_slab[8]=SH_SLAB_GENERIC_ACTUAL_OBJECTS_PER_SLAB;
static sh_uint64 bitmap_init[8]=SH_SLAB_GENERIC_SLAB_BITMAP_INIT;
static sh_uint64 slab_data_pages[8]=SH_SLAB_GENERIC_SLAB_DATA_PAGES;
SH_STATUS sh_slab_generic_alloc_init(sh_uint8 level,struct sh_slab_generic_SLAB_ALLOCATOR* slab_alloc,sh_pba_PAGE_BLOCK_ALLOCATOR *pba) {
if (slab_alloc==SH_NULLPTR || pba==SH_NULLPTR) return SH_STATUS_INVALID_PARAMETER;
if (level>7) return SH_STATUS_INVALID_PARAMETER;
slab_alloc->first_slab=SH_NULLPTR;
slab_alloc->slab_count=0;
slab_alloc->partial_head=SH_NULLPTR;
slab_alloc->pba=pba;
slab_alloc->level=level;
slab_alloc->object_size_bytes=object_size_bytes[level];
slab_alloc->object_per_slab=SH_SLAB_GENERIC_OBJECTS_PER_SLAB;
slab_alloc->actual_object_per_slab=actual_objects_per_slab[level];
slab_alloc->bitmap_init=bitmap_init[level];
slab_alloc->slab_pages_count=slab_data_pages[level];
return SH_STATUS_SUCCESS;
}
SH_STATUS sh_slab_generic_add_slab(struct sh_slab_generic_SLAB_ALLOCATOR* alloc,sh_page_PAGE_TABLE_POOL *ptp,sh_slab_generic_SLAB** out_slab) {
if (alloc==SH_NULLPTR || out_slab==SH_NULLPTR) return SH_STATUS_INVALID_PARAMETER; // phys_plane isn't checked because it can be SH_NULLPTR
sh_page_VIRTUAL_ADDRESS slab_va;
SH_STATUS status=sh_pba_alloc(alloc->pba,ptp,&slab_va);
if (sh_status_error(status)) return status;
if (alloc->slab_count==0) {
sh_slab_generic_SLAB *new_slab=(sh_slab_generic_SLAB*)slab_va;
for (sh_iter64 i=0;i<sizeof(sig);i++) new_slab->sig[i]=sig[i];
new_slab->next_slab=SH_NULLPTR;
new_slab->prev_slab=SH_NULLPTR;
new_slab->next_partial=SH_NULLPTR;
new_slab->prev_partial=SH_NULLPTR;
new_slab->slab_index=alloc->slab_count;
new_slab->used_count=0;
for (sh_iter64 i=0;i<8;i++) new_slab->free_bitmap[i]=0;
new_slab->free_bitmap[0]|=alloc->bitmap_init;
alloc->first_slab=new_slab;
alloc->partial_head=new_slab;
alloc->slab_count++;
*out_slab=new_slab;
} else {
sh_slab_generic_SLAB *new_slab=(sh_slab_generic_SLAB*)slab_va;
for (sh_iter64 i=0;i<sizeof(sig);i++) new_slab->sig[i]=sig[i];
new_slab->next_slab=alloc->first_slab;
new_slab->prev_slab=SH_NULLPTR;
alloc->first_slab->prev_slab=new_slab;
alloc->first_slab=new_slab;
new_slab->next_partial=alloc->partial_head;
new_slab->prev_partial=SH_NULLPTR;
alloc->partial_head->prev_partial=new_slab;
alloc->partial_head=new_slab;
new_slab->slab_index=alloc->slab_count;
new_slab->used_count=0;
for (sh_iter64 i=0;i<8;i++) new_slab->free_bitmap[i]=0;
new_slab->free_bitmap[0]|=alloc->bitmap_init;
alloc->slab_count++;
*out_slab=new_slab;
}
return SH_STATUS_SUCCESS;
}
SH_STATUS sh_slab_generic_get_partial_slab(struct sh_slab_generic_SLAB_ALLOCATOR* alloc,sh_page_PAGE_TABLE_POOL* ptp,sh_slab_generic_SLAB** found_slab) {
if (alloc==SH_NULLPTR ||ptp==SH_NULLPTR || found_slab==SH_NULLPTR) return SH_STATUS_INVALID_PARAMETER;
if (alloc->partial_head==SH_NULLPTR) {
*found_slab=SH_NULLPTR;
return SH_STATUS_NOT_FOUND;
}
sh_slab_generic_SLAB *slab=alloc->partial_head;
if (slab->used_count>=alloc->actual_object_per_slab) {
if (slab->next_partial!=SH_NULLPTR && slab->next_partial->used_count<alloc->actual_object_per_slab) {
alloc->partial_head=slab->next_partial;
alloc->partial_head->prev_partial=SH_NULLPTR;
slab->next_partial=SH_NULLPTR;
slab->prev_partial=SH_NULLPTR;
*found_slab=alloc->partial_head;
return SH_STATUS_SUCCESS;
} else {
sh_slab_generic_SLAB *new_slab;
SH_STATUS status=sh_slab_generic_add_slab(alloc,ptp,&new_slab);
if (sh_status_error(status)) return status;
*found_slab=new_slab;
return SH_STATUS_NEW_SLAB_ADDED;
}
}
*found_slab=slab;
return SH_STATUS_SUCCESS;
}
SH_STATUS sh_slab_generic_scan_slabs(struct sh_slab_generic_SLAB_ALLOCATOR* alloc) {
if (alloc==SH_NULLPTR) return SH_STATUS_INVALID_PARAMETER;
sh_slab_generic_SLAB* current=alloc->first_slab;
sh_slab_generic_SLAB* last_partial=SH_NULLPTR;
alloc->partial_head=SH_NULLPTR;
sh_log_debug("Slabs rescan triggered.",SH_LOG_SOURCE_SLAB);
while (current!=SH_NULLPTR) {
if (*(sh_uint64*)current->sig!=SH_SLAB_GENERIC_MAGIC) {
return SH_STATUS_FOUND_CORRUPTED_SLAB;
}
current->next_partial=SH_NULLPTR;
current->prev_partial=SH_NULLPTR;
if (current->used_count<alloc->actual_object_per_slab) {
if (alloc->partial_head==SH_NULLPTR) {
alloc->partial_head=current;
last_partial=current;
} else {
last_partial->next_partial=current;
current->prev_partial=last_partial;
last_partial=current;
}
}
current=current->next_slab;
}
return SH_STATUS_SUCCESS;
}
SH_STATUS sh_slab_generic_find_free_object(struct sh_slab_generic_SLAB_ALLOCATOR* alloc,sh_page_PAGE_TABLE_POOL *ptp,void** out,sh_slab_generic_OBJECT_INDEX_IN_SLAB* index_in_slab) {
if (alloc==SH_NULLPTR || ptp==SH_NULLPTR || out==SH_NULLPTR || index_in_slab==SH_NULLPTR) return SH_STATUS_INVALID_PARAMETER;
sh_slab_generic_SLAB *partial_slab;
sh_slab_generic_SLAB *new_slab;
SH_STATUS status=sh_slab_generic_get_partial_slab(alloc,ptp,&partial_slab);
if (status==SH_STATUS_RESCAN_NEEDED) {
status=sh_slab_generic_scan_slabs(alloc);
if (sh_status_error(status)) {
return status;
}
status=sh_slab_generic_get_partial_slab(alloc,ptp,&partial_slab);
}
if (status==SH_STATUS_NOT_FOUND) {
status=sh_slab_generic_add_slab(alloc,ptp,&new_slab);
if (sh_status_error(status)) {
return status;
}
status=sh_slab_generic_get_partial_slab(alloc,ptp,&partial_slab);
if (sh_status_error(status)) {
return status;
}
} else if (sh_status_error(status) && status!=SH_STATUS_NEW_SLAB_ADDED) {
return status;
}
sh_uint16 found_index=0;
sh_bool found=SH_FALSE;
for (sh_iter64 w=0;w<8;w++) {
sh_uint64 word=partial_slab->free_bitmap[w];
sh_uint64 free_bits=(~word);
if (free_bits) {
sh_uint64 bit=(sh_uint64)__builtin_ctzll(free_bits);
found_index=(sh_uint16)((w<<6)+bit);
found=SH_TRUE;
break;
}
}
if (!found) {
return SH_STATUS_NOT_FOUND;
}
sh_uint8 *start_data=(sh_uint8*)partial_slab;
*out=start_data+found_index*alloc->object_size_bytes;
*index_in_slab=found_index;
return SH_STATUS_SUCCESS;
}
SH_STATUS sh_slab_generic_alloc(struct sh_slab_generic_SLAB_ALLOCATOR* alloc,sh_page_PAGE_TABLE_POOL *ptp,void** out_obj) {
if (alloc==SH_NULLPTR || ptp==SH_NULLPTR || out_obj==SH_NULLPTR) return SH_STATUS_INVALID_PARAMETER;
sh_uint8* object_ptr;
sh_slab_generic_OBJECT_INDEX_IN_SLAB index_in_slab;
SH_STATUS status=sh_slab_generic_find_free_object(alloc,ptp,(void*)&object_ptr,&index_in_slab);
if (sh_status_error(status)) return status;
if (object_ptr==SH_NULLPTR) return SH_STATUS_ERROR_NULLPTR_RETURNED;
for (sh_iter64 i=0;i<alloc->object_size_bytes;i++) object_ptr[i]=0;
sh_slab_generic_SLAB* slab=(sh_slab_generic_SLAB*)((sh_uint64)object_ptr & ~(0xFFFULL<<alloc->level));
if (*(sh_uint64*)slab->sig!=SH_SLAB_GENERIC_MAGIC) {
return SH_STATUS_FOUND_CORRUPTED_SLAB;
}
sh_uint16 word_idx=index_in_slab>>6;
sh_uint16 bit_idx=index_in_slab&63;
slab->free_bitmap[word_idx]|=(1ULL<<bit_idx);
slab->used_count++;
*out_obj=object_ptr;
return SH_STATUS_SUCCESS;
}
SH_STATUS sh_slab_generic_dealloc(struct sh_slab_generic_SLAB_ALLOCATOR* alloc,void *object_ptr) {
if (alloc==SH_NULLPTR || object_ptr==SH_NULLPTR) return SH_STATUS_INVALID_PARAMETER;
if ((sh_uint64)object_ptr%alloc->object_size_bytes!=0) return SH_STATUS_INVALID_PARAMETER;
sh_slab_generic_SLAB* slab=(sh_slab_generic_SLAB*)((sh_uint64)object_ptr & ~(0xFFFULL<<alloc->level));
if (*(sh_uint64*)slab->sig!=SH_SLAB_GENERIC_MAGIC) {
return SH_STATUS_FOUND_CORRUPTED_SLAB;
}
sh_uint16 object_idx=(sh_uint16)(((sh_uint64)object_ptr & (0xFFFULL<<alloc->level))/alloc->object_size_bytes);
sh_uint16 min_idx=(sh_uint16)(alloc->object_per_slab-alloc->actual_object_per_slab);
if (object_idx<min_idx) return SH_STATUS_INVALID_PARAMETER;
sh_uint16 word=object_idx>>6;
sh_uint16 bit=object_idx&63;
if (!(slab->free_bitmap[word] & (1ULL<<bit))) return SH_STATUS_SLAB_SLOT_ALREADY_FREE;
slab->free_bitmap[word]&= ~(1ULL<<bit);
if (slab->used_count==alloc->actual_object_per_slab) {
slab->prev_partial=SH_NULLPTR;
slab->next_partial=alloc->partial_head;
if (alloc->partial_head!=SH_NULLPTR) {
alloc->partial_head->prev_partial=slab;
}
alloc->partial_head=slab;
}
slab->used_count--;
for (sh_iter64 i=0;i<alloc->object_size_bytes;i++) ((sh_uint8*)object_ptr)[i]=0;
return SH_STATUS_SUCCESS;
}

View File

@@ -0,0 +1,227 @@
// SPDX-License-Identifier: MPL-2.0
#include "memory/slabs/slab_radix_node.h"
#include "std/mem.h"
#include "kernel/log.h"
#include "memory/pez/pez.h"
static sh_uint8 sig[8]=SH_SLAB_RADIX_NODE_SLAB_SIG;
SH_STATUS sh_slab_radix_node_alloc_init(struct sh_slab_radix_node_SLAB_ALLOCATOR* slab_alloc,sh_pba_PAGE_BLOCK_ALLOCATOR *pba) {
if (slab_alloc==SH_NULLPTR) return SH_STATUS_INVALID_PARAMETER;
slab_alloc->first_slab=SH_NULLPTR;
slab_alloc->slab_count=0;
slab_alloc->partial_head=SH_NULLPTR;
slab_alloc->pba=pba;
return SH_STATUS_SUCCESS;
}
SH_STATUS sh_slab_radix_node_add_slab(struct sh_slab_radix_node_SLAB_ALLOCATOR* alloc,sh_page_PAGE_TABLE_POOL *ptp,sh_slab_radix_node_SLAB** out_slab) {
if (alloc==SH_NULLPTR || out_slab==SH_NULLPTR) return SH_STATUS_INVALID_PARAMETER;
sh_page_VIRTUAL_ADDRESS slab_va;
SH_STATUS status=sh_pba_alloc(alloc->pba,ptp,&slab_va);
if (sh_status_error(status)) return status;
if (alloc->slab_count==0) {
sh_slab_radix_node_SLAB *new_slab=(sh_slab_radix_node_SLAB*)slab_va;
for (sh_iter64 i=0;i<sizeof(sig);i++) new_slab->sig[i]=sig[i];
new_slab->next_slab=SH_NULLPTR;
new_slab->prev_slab=SH_NULLPTR;
new_slab->next_partial=SH_NULLPTR;
new_slab->prev_partial=SH_NULLPTR;
new_slab->slab_index=alloc->slab_count;
new_slab->used_count=0;
for (sh_iter64 i=0;i<16;i++) new_slab->free_bitmap[i]=0;
new_slab->free_bitmap[0]|=0x3FFFFULL;
sh_mem_set_8(new_slab->padding,0x00,sizeof(new_slab->padding));
sh_mem_set_8((sh_uint8*)new_slab->node_bitmap,0x00,sizeof(new_slab->node_bitmap));
sh_mem_set_8((sh_uint8*)new_slab->nodes,0x00,sizeof(new_slab->nodes));
alloc->first_slab=new_slab;
alloc->partial_head=new_slab;
alloc->slab_count++;
*out_slab=new_slab;
} else {
sh_slab_radix_node_SLAB *new_slab=(sh_slab_radix_node_SLAB*)slab_va;
for (sh_iter64 i=0;i<sizeof(sig);i++) new_slab->sig[i]=sig[i];
new_slab->next_slab=alloc->first_slab;
new_slab->prev_slab=SH_NULLPTR;
alloc->first_slab->prev_slab=new_slab;
alloc->first_slab=new_slab;
new_slab->next_partial=alloc->partial_head;
new_slab->prev_partial=SH_NULLPTR;
alloc->partial_head->prev_partial=new_slab;
alloc->partial_head=new_slab;
new_slab->slab_index=alloc->slab_count;
new_slab->used_count=0;
for (sh_iter64 i=0;i<16;i++) new_slab->free_bitmap[i]=0;
new_slab->free_bitmap[0]|=0x3FFFFULL;
sh_mem_set_8(new_slab->padding,0x00,sizeof(new_slab->padding));
sh_mem_set_8((sh_uint8*)new_slab->node_bitmap,0x00,sizeof(new_slab->node_bitmap));
sh_mem_set_8((sh_uint8*)new_slab->nodes,0x00,sizeof(new_slab->nodes));
alloc->slab_count++;
*out_slab=new_slab;
}
return SH_STATUS_SUCCESS;
}
SH_STATUS sh_slab_radix_node_get_partial_slab(struct sh_slab_radix_node_SLAB_ALLOCATOR* alloc,sh_page_PAGE_TABLE_POOL* ptp,sh_slab_radix_node_SLAB** found_slab) {
if (alloc==SH_NULLPTR ||ptp==SH_NULLPTR || found_slab==SH_NULLPTR) return SH_STATUS_INVALID_PARAMETER;
if (alloc->partial_head==SH_NULLPTR) {
*found_slab=SH_NULLPTR;
return SH_STATUS_NOT_FOUND;
}
sh_slab_radix_node_SLAB *slab=alloc->partial_head;
if (slab->used_count>=SH_SLAB_RADIX_NODE_ACTUAL_OBJECTS_PER_SLAB) {
if (slab->next_partial!=SH_NULLPTR && slab->next_partial->used_count<SH_SLAB_RADIX_NODE_ACTUAL_OBJECTS_PER_SLAB) {
alloc->partial_head=slab->next_partial;
alloc->partial_head->prev_partial=SH_NULLPTR;
slab->next_partial=SH_NULLPTR;
slab->prev_partial=SH_NULLPTR;
*found_slab=alloc->partial_head;
return SH_STATUS_SUCCESS;
} else {
sh_slab_radix_node_SLAB *new_slab;
SH_STATUS status=sh_slab_radix_node_add_slab(alloc,ptp,&new_slab);
if (sh_status_error(status)) return status;
*found_slab=new_slab;
return SH_STATUS_NEW_SLAB_ADDED;
}
}
*found_slab=slab;
return SH_STATUS_SUCCESS;
}
SH_STATUS sh_slab_radix_node_scan_slabs(struct sh_slab_radix_node_SLAB_ALLOCATOR* alloc) {
if (alloc==SH_NULLPTR) return SH_STATUS_INVALID_PARAMETER;
sh_slab_radix_node_SLAB* current=alloc->first_slab;
sh_slab_radix_node_SLAB* last_partial=SH_NULLPTR;
alloc->partial_head=SH_NULLPTR;
sh_log_debug("Slabs rescan triggered.",SH_LOG_SOURCE_SLAB);
while (current!=SH_NULLPTR) {
if (*(sh_uint64*)current->sig!=SH_SLAB_RADIX_NODE_MAGIC) {
return SH_STATUS_FOUND_CORRUPTED_SLAB;
}
current->used_count=0;
for (sh_iter64 w=0;w<16;w++) current->free_bitmap[w]=0;
current->free_bitmap[0]|=0x3FFFFULL;
for (sh_uint16 obj_idx=18;obj_idx<SH_SLAB_RADIX_NODE_OBJECTS_PER_SLAB;obj_idx++) {
sh_uint8* node_ptr=(sh_uint8*)&current->nodes[obj_idx-18];
sh_bool is_free=SH_TRUE;
sh_uint64* check_ptr=(sh_uint64*)node_ptr;
for (sh_uint8 b=0;b<(SH_SLAB_RADIX_NODE_OBJECT_SIZE_BYTES/8);b++) {
if (check_ptr[b]!=0) {
is_free=SH_FALSE;
break;
}
}
sh_uint16 word=obj_idx>>6;
sh_uint16 bit=obj_idx&63;
if (!is_free) {
current->free_bitmap[word]|=(1ULL<<bit);
current->used_count++;
}
}
current->next_partial=SH_NULLPTR;
current->prev_partial=SH_NULLPTR;
if (current->used_count<SH_SLAB_RADIX_NODE_ACTUAL_OBJECTS_PER_SLAB) {
if (alloc->partial_head==SH_NULLPTR) {
alloc->partial_head=current;
last_partial=current;
} else {
last_partial->next_partial=current;
current->prev_partial=last_partial;
last_partial=current;
}
}
current=current->next_slab;
}
return SH_STATUS_SUCCESS;
}
SH_STATUS sh_slab_radix_node_find_free_object(struct sh_slab_radix_node_SLAB_ALLOCATOR* alloc,sh_page_PAGE_TABLE_POOL *ptp,sh_radix_NODE** out,sh_slab_radix_node_NODE_INDEX_IN_SLAB* index_in_slab) {
if (alloc==SH_NULLPTR || ptp==SH_NULLPTR || out==SH_NULLPTR || index_in_slab==SH_NULLPTR) return SH_STATUS_INVALID_PARAMETER;
sh_slab_radix_node_SLAB *partial_slab;
sh_slab_radix_node_SLAB *new_slab;
SH_STATUS status=sh_slab_radix_node_get_partial_slab(alloc,ptp,&partial_slab);
if (status==SH_STATUS_RESCAN_NEEDED) {
status=sh_slab_radix_node_scan_slabs(alloc);
if (sh_status_error(status)) return status;
status=sh_slab_radix_node_get_partial_slab(alloc,ptp,&partial_slab);
}
if (status==SH_STATUS_NOT_FOUND) {
status=sh_slab_radix_node_add_slab(alloc,ptp,&new_slab);
if (sh_status_error(status)) return status;
status=sh_slab_radix_node_get_partial_slab(alloc,ptp,&partial_slab);
if (sh_status_error(status)) return status;
} else if (sh_status_error(status) && status!=SH_STATUS_NEW_SLAB_ADDED) {
return status;
}
sh_uint16 found_idx=0;
sh_bool bit_found=SH_FALSE;
for (sh_uint8 w=0;w<16;w++) {
if (partial_slab->free_bitmap[w]!=0xFFFFFFFFFFFFFFFFULL) {
for (sh_uint8 b=0;b<64;b++) {
if (!(partial_slab->free_bitmap[w] & (1ULL<<b))) {
found_idx=(w<<6)|b;
if (found_idx<18) continue;
bit_found=SH_TRUE;
break;
}
}
}
if (bit_found) break;
}
if (!bit_found) return SH_STATUS_NOT_FOUND;
*out=&partial_slab->nodes[found_idx-18];
*index_in_slab=found_idx;
return SH_STATUS_SUCCESS;
}
SH_STATUS sh_slab_radix_node_alloc(struct sh_slab_radix_node_SLAB_ALLOCATOR* alloc,sh_page_PAGE_TABLE_POOL *ptp,sh_radix_NODE** out_obj) {
if (alloc==SH_NULLPTR || ptp==SH_NULLPTR || out_obj==SH_NULLPTR) return SH_STATUS_INVALID_PARAMETER;
sh_radix_NODE *object_ptr;
sh_slab_radix_node_NODE_INDEX_IN_SLAB index_in_slab;
SH_STATUS status=sh_slab_radix_node_find_free_object(alloc,ptp,&object_ptr,&index_in_slab);
if (sh_status_error(status)) return status;
if (object_ptr==SH_NULLPTR) return SH_STATUS_ERROR_NULLPTR_RETURNED;
for (sh_iter64 i=0;i<16;i++) object_ptr->ptr[i]=0x0;
sh_slab_radix_node_SLAB* slab=(sh_slab_radix_node_SLAB*)((sh_uint64)object_ptr & ~0x1FFFFULL);
if (*(sh_uint64*)slab->sig!=SH_SLAB_RADIX_NODE_MAGIC) {
return SH_STATUS_FOUND_CORRUPTED_SLAB;
}
sh_uint16 word_idx=index_in_slab>>6;
sh_uint16 bit_idx=index_in_slab&63;
slab->free_bitmap[word_idx]|=(1ULL<<bit_idx);
slab->node_bitmap[index_in_slab]=0;
slab->used_count++;
*out_obj=object_ptr;
return SH_STATUS_SUCCESS;
}
SH_STATUS sh_slab_radix_node_dealloc(struct sh_slab_radix_node_SLAB_ALLOCATOR* alloc,sh_radix_NODE *object_ptr) {
if (alloc==SH_NULLPTR || object_ptr==SH_NULLPTR) return SH_STATUS_INVALID_PARAMETER;
if ((sh_uint64)object_ptr%SH_SLAB_RADIX_NODE_OBJECT_SIZE_BYTES!=0) return SH_STATUS_INVALID_PARAMETER;
sh_slab_radix_node_SLAB* slab=(sh_slab_radix_node_SLAB*)((sh_uint64)object_ptr & ~0x1FFFFULL);
if (*(sh_uint64*)slab->sig!=SH_SLAB_RADIX_NODE_MAGIC) {
return SH_STATUS_FOUND_CORRUPTED_SLAB;
}
sh_uint16 object_idx=(sh_uint16)(((sh_uint64)object_ptr & 0x1FFFFULL)/SH_SLAB_RADIX_NODE_OBJECT_SIZE_BYTES);
if (object_idx<18) return SH_STATUS_INVALID_PARAMETER;
sh_uint16 word=object_idx>>6;
sh_uint16 bit=object_idx&63;
if (!(slab->free_bitmap[word] & (1ULL<<bit))) return SH_STATUS_SLAB_SLOT_ALREADY_FREE;
slab->free_bitmap[word]&= ~(1ULL<<bit);
if (slab->used_count==SH_SLAB_RADIX_NODE_ACTUAL_OBJECTS_PER_SLAB) {
slab->prev_partial=SH_NULLPTR;
slab->next_partial=alloc->partial_head;
if (alloc->partial_head!=SH_NULLPTR) {
alloc->partial_head->prev_partial=slab;
}
alloc->partial_head=slab;
}
slab->used_count--;
for (sh_iter64 i=0;i<16;i++) object_ptr->ptr[i]=0x0;
slab->node_bitmap[object_idx]=0;
return SH_STATUS_SUCCESS;
}
sh_uint16 *sh_slab_radix_node_get_node_bitmap(struct sh_slab_radix_node_SLAB_ALLOCATOR* alloc,sh_radix_NODE *object_ptr) {
if (alloc==SH_NULLPTR || object_ptr==SH_NULLPTR) return SH_NULLPTR;
if ((sh_uint64)object_ptr%SH_SLAB_RADIX_NODE_OBJECT_SIZE_BYTES!=0) return SH_NULLPTR;
sh_slab_radix_node_SLAB* slab=(sh_slab_radix_node_SLAB*)((sh_uint64)object_ptr & ~0x1FFFFULL);
if (*(sh_uint64*)slab->sig!=SH_SLAB_RADIX_NODE_MAGIC) {
return SH_NULLPTR;
}
sh_uint16 object_idx=(sh_uint16)(((sh_uint64)object_ptr & 0x1FFFFULL)/SH_SLAB_RADIX_NODE_OBJECT_SIZE_BYTES);
if (object_idx<18) return SH_NULLPTR;
return &slab->node_bitmap[object_idx];
}

View File

@@ -0,0 +1,274 @@
// SPDX-License-Identifier: MPL-2.0
#include "memory/slabs/slab_reg_phys.h"
#include "std/mem.h"
#include "kernel/log.h"
#include "memory/pez/pez.h"
SH_STATUS sh_slab_reg_phys_alloc_init(sh_slab_reg_phys_SLAB_ALLOCATOR* slab_alloc,sh_page_PAGE_TABLE_POOL *ptp) {
if (slab_alloc==SH_NULLPTR) return SH_STATUS_INVALID_PARAMETER;
slab_alloc->max_slabs=SH_SLAB_REG_PHYS_MAX_SLAB;
slab_alloc->slab_count=0;
slab_alloc->partial_head=SH_NULLPTR;
slab_alloc->slabs_data=SH_NULLPTR;
sh_page_VIRTUAL_ADDRESS header_va;
SH_STATUS status=sh_page_alloc_contiguous_extended(ptp,SH_SLAB_REG_PHYS_HEADER_LIST_SIZE_BYTES,&header_va,SH_PAGE_RW | SH_PAGE_PRESENT | SH_PAGE_NX,SH_PAGE_KERNEL_PERM_VA_BASE,(SH_PAGE_KERNEL_PERM_VA_END-SH_PAGE_KERNEL_PERM_VA_BASE+1-0x1000));
if (sh_status_error(status)) return status;
slab_alloc->slabs_header=(sh_slab_reg_phys_SLAB_STRUCT*)header_va;
status=sh_mem_set_8((sh_uint8*)(slab_alloc->slabs_header),0x00,SH_SLAB_REG_PHYS_HEADER_LIST_SIZE_BYTES);
if (sh_status_error(status)) return status;
return SH_STATUS_SUCCESS;
}
SH_STATUS sh_slab_reg_phys_add_slab(sh_slab_reg_phys_SLAB_ALLOCATOR* alloc,sh_page_PAGE_TABLE_POOL *ptp,sh_slab_reg_phys_SLAB_STRUCT** out_slab) {
if (alloc==SH_NULLPTR || out_slab==SH_NULLPTR) return SH_STATUS_INVALID_PARAMETER;
if (alloc->slab_count>=alloc->max_slabs) return SH_STATUS_SLAB_ALLOCATOR_FULL;
sh_page_PHYSICAL_ADDRESS slab_pa;
SH_STATUS status;
if (sh_pez_is_available()) {
sh_pez_PHYSICAL_PLANE *phys_plane=sh_pez_get_reference_phys_plane();
status=sh_pez_alloc_physical_pages(phys_plane,SH_SLAB_REG_PHYS_SLAB_DATA_PAGES,&slab_pa);
if (sh_status_error(status)) return status;
} else {
status=sh_page_search_physical_contiguous_block_na(SH_SLAB_REG_PHYS_SLAB_DATA_PAGES,&slab_pa);
if (sh_status_error(status)) return status;
}
if (alloc->slabs_data==SH_NULLPTR && alloc->slab_count==0) {
sh_page_VIRTUAL_ADDRESS alloc_slab_data_va_base=SH_SLAB_REG_PHYS_DATA_VA;
status=sh_page_is_va_range_mapped_ptp(ptp,alloc_slab_data_va_base,SH_SLAB_REG_PHYS_MAX_SLAB*SH_SLAB_REG_PHYS_SLAB_DATA_SIZE_BYTES);
if (status!=SH_STATUS_VA_NOT_MAPPED) return status;
status=sh_page_map_contiguous_pages_range_ptp(ptp,alloc_slab_data_va_base,slab_pa,SH_PAGE_PRESENT | SH_PAGE_NX | SH_PAGE_RW,SH_SLAB_REG_PHYS_SLAB_DATA_SIZE_BYTES);
if (sh_status_error(status)) return status;
alloc->slabs_data=(sh_uint8*)alloc_slab_data_va_base;
sh_slab_reg_phys_SLAB_STRUCT *new_slab_header=alloc->slabs_header;
new_slab_header->slab_index=alloc->slab_count;
new_slab_header->used_count=0;
new_slab_header->prev=SH_NULLPTR;
new_slab_header->next=SH_NULLPTR;
for (sh_iter64 i=0;i<16;i++) new_slab_header->free_bitmap[i]=0;
new_slab_header->free_bitmap[0]|=1ULL;
new_slab_header->used_count=0;
status=sh_mem_set_8(alloc->slabs_data,0x00,SH_SLAB_REG_PHYS_SLAB_DATA_SIZE_BYTES);
if (sh_status_error(status)) return status;
if (!sh_pez_is_available()) {
sh_page_MEM_STATS mem_stats;
status=sh_page_get_memory_stats(&mem_stats);
if (sh_status_error(status)) return status;
status=sh_page_set_pages_range_bitmap((sh_uint8*)sh_page_get_physical_bitmap_ptr(),mem_stats.memory_total_pages,slab_pa/SH_PAGE_SIZE,SH_SLAB_REG_PHYS_SLAB_DATA_PAGES,SH_TRUE);
if (sh_status_error(status)) return status;
}
alloc->partial_head=alloc->slabs_header;
*out_slab=new_slab_header;
alloc->slab_count++;
} else if (alloc->slabs_data!=SH_NULLPTR && alloc->slab_count!=0) {
sh_page_VIRTUAL_ADDRESS alloc_slab_data_va=SH_SLAB_REG_PHYS_DATA_VA+alloc->slab_count*SH_SLAB_REG_PHYS_SLAB_DATA_SIZE_BYTES;
status=sh_page_is_va_range_mapped_ptp(ptp,alloc_slab_data_va,SH_SLAB_REG_PHYS_SLAB_DATA_SIZE_BYTES);
if (status!=SH_STATUS_VA_NOT_MAPPED) return status;
status=sh_page_map_contiguous_pages_range_ptp(ptp,alloc_slab_data_va,slab_pa,SH_PAGE_PRESENT | SH_PAGE_NX | SH_PAGE_RW,SH_SLAB_REG_PHYS_SLAB_DATA_SIZE_BYTES);
if (sh_status_error(status)) return status;
sh_slab_reg_phys_SLAB_STRUCT *new_slab_header=alloc->slabs_header+alloc->slab_count;
new_slab_header->slab_index=alloc->slab_count;
new_slab_header->used_count=0;
new_slab_header->prev=SH_NULLPTR;
new_slab_header->next=alloc->partial_head;
sh_slab_reg_phys_SLAB_STRUCT *next_slab_header=new_slab_header->next;
next_slab_header->prev=new_slab_header;
alloc->partial_head=new_slab_header;
for (sh_iter64 i=0;i<16;i++) new_slab_header->free_bitmap[i]=0;
new_slab_header->free_bitmap[0]|=1ULL;
new_slab_header->used_count=0;
status=sh_mem_set_8(alloc->slabs_data+alloc->slab_count*SH_SLAB_REG_PHYS_SLAB_DATA_SIZE_BYTES,0x00,SH_SLAB_REG_PHYS_SLAB_DATA_SIZE_BYTES);
if (sh_status_error(status)) return status;
if (!sh_pez_is_available()) {
sh_page_MEM_STATS mem_stats;
status=sh_page_get_memory_stats(&mem_stats);
if (sh_status_error(status)) return status;
status=sh_page_set_pages_range_bitmap((sh_uint8*)sh_page_get_physical_bitmap_ptr(),mem_stats.memory_total_pages,slab_pa/SH_PAGE_SIZE,SH_SLAB_REG_PHYS_SLAB_DATA_PAGES,SH_TRUE);
if (sh_status_error(status)) return status;
}
*out_slab=new_slab_header;
alloc->slab_count++;
}
return SH_STATUS_SUCCESS;
}
SH_STATUS sh_slab_reg_phys_get_partial_slab(sh_slab_reg_phys_SLAB_ALLOCATOR* alloc,sh_page_PAGE_TABLE_POOL* ptp,sh_slab_reg_phys_SLAB_STRUCT** found_slab) {
if (alloc==SH_NULLPTR || ptp==SH_NULLPTR || found_slab==SH_NULLPTR) return SH_STATUS_INVALID_PARAMETER;
if (alloc->partial_head==SH_NULLPTR) {
*found_slab=SH_NULLPTR;
return SH_STATUS_NOT_FOUND;
}
sh_slab_reg_phys_SLAB_STRUCT* slab=alloc->partial_head;
if (slab->used_count>=SH_SLAB_REG_PHYS_ACTUAL_OBJECTS_PER_SLAB) {
if (slab->next!=SH_NULLPTR && slab->next->used_count<SH_SLAB_REG_PHYS_ACTUAL_OBJECTS_PER_SLAB) {
alloc->partial_head=slab->next;
alloc->partial_head->prev=SH_NULLPTR;
slab->next=SH_NULLPTR;
slab->prev=SH_NULLPTR;
*found_slab=alloc->partial_head;
return SH_STATUS_SUCCESS;
} else {
sh_slab_reg_phys_SLAB_STRUCT* new_slab;
SH_STATUS status=sh_slab_reg_phys_add_slab(alloc,ptp,&new_slab);
if (sh_status_error(status)) return status;
*found_slab=new_slab;
return SH_STATUS_NEW_SLAB_ADDED;
}
}
*found_slab=slab;
return SH_STATUS_SUCCESS;
}
SH_STATUS sh_slab_reg_phys_scan_slabs(sh_slab_reg_phys_SLAB_ALLOCATOR* alloc) {
if (alloc==SH_NULLPTR || alloc->slabs_data==SH_NULLPTR) return SH_STATUS_INVALID_PARAMETER;
sh_slab_reg_phys_SLAB_STRUCT* first_partial=SH_NULLPTR;
sh_slab_reg_phys_SLAB_STRUCT* last_partial=SH_NULLPTR;
sh_log_debug("Slabs rescan triggered.",SH_LOG_SOURCE_SLAB);
for (sh_uint16 i=0;i<alloc->slab_count;i++) {
sh_slab_reg_phys_SLAB_STRUCT* slab=alloc->slabs_header+i;
sh_uint8* slab_base=alloc->slabs_data+i*SH_SLAB_REG_PHYS_SLAB_DATA_SIZE_BYTES;
slab->used_count=0;
for (sh_iter64 w=0;w<16;w++) slab->free_bitmap[w]=0;
slab->free_bitmap[0]|=1ULL;
for (sh_uint16 obj_idx=1;obj_idx<SH_SLAB_REG_PHYS_OBJECTS_PER_SLAB;obj_idx++) {
sh_uint8* obj_ptr=slab_base+obj_idx*SH_SLAB_REG_PHYS_OBJECT_SIZE_BYTES;
int is_free=1;
for (sh_iter64 b=0;b<SH_SLAB_REG_PHYS_OBJECT_SIZE_BYTES;b++) {
if (obj_ptr[b]!=0) {
is_free=0;
break;
}
}
if (is_free) {
sh_uint16 word=obj_idx>>6;
sh_uint16 bit=obj_idx&63;
slab->free_bitmap[word]&= ~(1ULL<<bit);
} else {
sh_uint16 word=obj_idx>>6;
sh_uint16 bit=obj_idx&63;
slab->free_bitmap[word]|=(1ULL<<bit);
slab->used_count++;
}
}
sh_log_fdebug(SH_LOG_SOURCE_SLAB,"Slab index: %2u; used count: %2u\n",slab->slab_index,slab->used_count);
slab->prev=SH_NULLPTR;
slab->next=SH_NULLPTR;
if (slab->used_count>0 && slab->used_count<SH_SLAB_REG_PHYS_ACTUAL_OBJECTS_PER_SLAB) {
if (first_partial==SH_NULLPTR) {
first_partial=slab;
last_partial=slab;
} else {
slab->prev=last_partial;
last_partial->next=slab;
last_partial=slab;
}
}
}
alloc->partial_head=first_partial;
return SH_STATUS_SUCCESS;
}
SH_STATUS sh_slab_reg_phys_find_free_object(sh_slab_reg_phys_SLAB_ALLOCATOR* alloc,sh_page_PAGE_TABLE_POOL *ptp,sh_slab_reg_phys_OBJECT_INDEX* out_ref) {
if (alloc==SH_NULLPTR || ptp==SH_NULLPTR || out_ref==SH_NULLPTR) return SH_STATUS_INVALID_PARAMETER;
sh_slab_reg_phys_SLAB_STRUCT *partial_slab;
sh_slab_reg_phys_SLAB_STRUCT *new_slab;
SH_STATUS status=sh_slab_reg_phys_get_partial_slab(alloc,ptp,&partial_slab);
if (status==SH_STATUS_RESCAN_NEEDED) {
status=sh_slab_reg_phys_scan_slabs(alloc);
if (sh_status_error(status)) return status;
status=sh_slab_reg_phys_get_partial_slab(alloc,ptp,&partial_slab);
}
if (status==SH_STATUS_NOT_FOUND) {
status=sh_slab_reg_phys_add_slab(alloc,ptp,&new_slab);
if (sh_status_error(status)) return status;
status=sh_slab_reg_phys_get_partial_slab(alloc,ptp,&partial_slab);
if (sh_status_error(status)) return status;
} else if (sh_status_error(status) && status!=SH_STATUS_NEW_SLAB_ADDED) {
return status;
}
sh_uint64 obj;
sh_bool obj_found=SH_FALSE;
for (sh_uint8 w=0;w<16;w++) {
sh_uint64 word=partial_slab->free_bitmap[w];
if (word!=SH_UINT64_MAX) {
if (w==0) {
for (sh_uint8 bit=0;bit<64;bit++) {
if (!(word & (1ULL<<bit))) {
sh_uint64 candidate=(sh_uint64)w*64+bit;
if (candidate==0) continue;
obj=candidate;
obj_found=SH_TRUE;
break;
}
}
} else {
for (sh_uint8 bit=0;bit<64;bit++) {
if (!(word & (1ULL<<bit))) {
obj=(sh_uint64)w*64+bit;
obj_found=SH_TRUE;
break;
}
}
}
}
if (obj_found==SH_TRUE) break;
}
if (obj_found==SH_FALSE) {
return SH_STATUS_RESCAN_NEEDED;
}
*out_ref=SH_SLAB_REG_PHYS_MAKE_REF(partial_slab->slab_index,obj);
return SH_STATUS_SUCCESS;
}
void* sh_slab_reg_phys_ref_to_ptr(sh_slab_reg_phys_SLAB_ALLOCATOR* alloc,sh_slab_reg_phys_OBJECT_INDEX ref) {
if (alloc==SH_NULLPTR) {
return SH_NULLPTR;
}
if (SH_SLAB_REG_PHYS_REF_SLAB(ref)>=alloc->slab_count || SH_SLAB_REG_PHYS_REF_OBJECT(ref)==0) {
return SH_NULLPTR;
}
sh_uint16 slab=SH_SLAB_REG_PHYS_REF_SLAB(ref);
sh_uint16 object=SH_SLAB_REG_PHYS_REF_OBJECT(ref);
if (object==0) {
return SH_NULLPTR;
}
return alloc->slabs_data+slab*SH_SLAB_REG_PHYS_SLAB_DATA_SIZE_BYTES+object*SH_SLAB_REG_PHYS_OBJECT_SIZE_BYTES;
}
SH_STATUS sh_slab_reg_phys_alloc(sh_slab_reg_phys_SLAB_ALLOCATOR* alloc,sh_page_PAGE_TABLE_POOL *ptp,sh_slab_reg_phys_OBJECT_INDEX* out_index) {
if (alloc==SH_NULLPTR || ptp==SH_NULLPTR || out_index==SH_NULLPTR) return SH_STATUS_INVALID_PARAMETER;
sh_slab_reg_phys_OBJECT_INDEX ref;
SH_STATUS status=sh_slab_reg_phys_find_free_object(alloc,ptp,&ref);
if (sh_status_error(status)) return status;
sh_uint16 slab_idx=SH_SLAB_REG_PHYS_REF_SLAB(ref);
sh_uint16 obj_idx=SH_SLAB_REG_PHYS_REF_OBJECT(ref);
sh_slab_reg_phys_SLAB_STRUCT* slab=alloc->slabs_header+slab_idx;
sh_uint16 word=obj_idx>>6;
sh_uint16 bit=obj_idx&63;
slab->free_bitmap[word]|=(1ULL<<bit);
sh_pez_REGION_PHYSICAL_OBJECT* obj=(sh_pez_REGION_PHYSICAL_OBJECT*)sh_slab_reg_phys_ref_to_ptr(alloc,ref);
if (obj==SH_NULLPTR) return SH_STATUS_ERROR_NULLPTR_RETURNED;
obj->start_page_index=0;
obj->region_size_pages=0;
obj->next_region_index[0]=obj->next_region_index[1]=obj->next_region_index[2]=0;
obj->flags=0;
slab->used_count++;
*out_index=ref;
return SH_STATUS_SUCCESS;
}
SH_STATUS sh_slab_reg_phys_dealloc(sh_slab_reg_phys_SLAB_ALLOCATOR* alloc,sh_slab_reg_phys_OBJECT_INDEX index) {
if (alloc==SH_NULLPTR) return SH_STATUS_INVALID_PARAMETER;
if (SH_SLAB_REG_PHYS_REF_OBJECT(index)==0) return SH_STATUS_INVALID_PARAMETER;
if (SH_SLAB_REG_PHYS_REF_SLAB(index)>=alloc->slab_count) return SH_STATUS_INVALID_PARAMETER;
sh_uint16 obj_idx=SH_SLAB_REG_PHYS_REF_OBJECT(index);
sh_uint16 word=obj_idx>>6;
sh_uint16 bit=obj_idx&63;
sh_slab_reg_phys_SLAB_STRUCT* slab_header=alloc->slabs_header+SH_SLAB_REG_PHYS_REF_SLAB(index);
if (!(slab_header->free_bitmap[word] & (1ULL<<bit))) return SH_STATUS_SLAB_SLOT_ALREADY_FREE;
slab_header->free_bitmap[word]&= ~(1ULL<<bit);
if (slab_header->used_count==SH_SLAB_REG_PHYS_ACTUAL_OBJECTS_PER_SLAB) {
slab_header->prev=SH_NULLPTR;
slab_header->next=alloc->partial_head;
if (alloc->partial_head!=SH_NULLPTR) {
alloc->partial_head->prev=slab_header;
}
alloc->partial_head=slab_header;
}
slab_header->used_count--;
sh_uint8* obj_ptr=sh_slab_reg_phys_ref_to_ptr(alloc,index);
if (obj_ptr==SH_NULLPTR) return SH_STATUS_ERROR_NULLPTR_RETURNED;
sh_mem_set_8(obj_ptr,0x00,SH_SLAB_REG_PHYS_OBJECT_SIZE_BYTES);
return SH_STATUS_SUCCESS;
}

View File

@@ -0,0 +1,271 @@
// SPDX-License-Identifier: MPL-2.0
#include "memory/slabs/slab_reg_virt.h"
#include "std/mem.h"
#include "kernel/log.h"
#include "memory/pez/pez.h"
SH_STATUS sh_slab_reg_virt_alloc_init(sh_slab_reg_virt_SLAB_ALLOCATOR* slab_alloc,sh_page_PAGE_TABLE_POOL *ptp) {
if (slab_alloc==SH_NULLPTR) return SH_STATUS_INVALID_PARAMETER;
slab_alloc->max_slabs=SH_SLAB_REG_VIRT_MAX_SLAB;
slab_alloc->slab_count=0;
slab_alloc->partial_head=SH_NULLPTR;
slab_alloc->slabs_data=SH_NULLPTR;
sh_page_VIRTUAL_ADDRESS header_va;
SH_STATUS status=sh_page_alloc_contiguous_extended(ptp,SH_SLAB_REG_VIRT_HEADER_LIST_SIZE_BYTES,&header_va,SH_PAGE_RW | SH_PAGE_PRESENT | SH_PAGE_NX,SH_PAGE_KERNEL_PERM_VA_BASE,(SH_PAGE_KERNEL_PERM_VA_END-SH_PAGE_KERNEL_PERM_VA_BASE+1-0x1000));
if (sh_status_error(status)) return status;
slab_alloc->slabs_header=(sh_slab_reg_virt_SLAB_STRUCT*)header_va;
status=sh_mem_set_8((sh_uint8*)(slab_alloc->slabs_header),0x00,SH_SLAB_REG_VIRT_HEADER_LIST_SIZE_BYTES);
if (sh_status_error(status)) return status;
return SH_STATUS_SUCCESS;
}
SH_STATUS sh_slab_reg_virt_add_slab(sh_slab_reg_virt_SLAB_ALLOCATOR* alloc,sh_page_PAGE_TABLE_POOL *ptp,sh_slab_reg_virt_SLAB_STRUCT** out_slab) {
if (alloc==SH_NULLPTR || out_slab==SH_NULLPTR) return SH_STATUS_INVALID_PARAMETER;
if (alloc->slab_count>=alloc->max_slabs) return SH_STATUS_SLAB_ALLOCATOR_FULL;
sh_page_VIRTUAL_ADDRESS slab_pa;
SH_STATUS status;
if (sh_pez_is_available()) {
sh_pez_PHYSICAL_PLANE *phys_plane=sh_pez_get_reference_phys_plane();
status=sh_pez_alloc_physical_pages(phys_plane,SH_SLAB_REG_PHYS_SLAB_DATA_PAGES,&slab_pa);
if (sh_status_error(status)) return status;
} else {
status=sh_page_search_physical_contiguous_block_na(SH_SLAB_REG_PHYS_SLAB_DATA_PAGES,&slab_pa);
if (sh_status_error(status)) return status;
}
if (alloc->slabs_data==SH_NULLPTR && alloc->slab_count==0) {
sh_page_VIRTUAL_ADDRESS alloc_slab_data_va_base=SH_SLAB_REG_VIRT_DATA_VA;
status=sh_page_is_va_range_mapped_ptp(ptp,alloc_slab_data_va_base,SH_SLAB_REG_VIRT_MAX_SLAB*SH_SLAB_REG_VIRT_SLAB_DATA_SIZE_BYTES);
if (status!=SH_STATUS_VA_NOT_MAPPED) return status;
status=sh_page_map_contiguous_pages_range_ptp(ptp,alloc_slab_data_va_base,slab_pa,SH_PAGE_PRESENT | SH_PAGE_NX | SH_PAGE_RW,SH_SLAB_REG_VIRT_SLAB_DATA_SIZE_BYTES);
if (sh_status_error(status)) return status;
alloc->slabs_data=(sh_uint8*)alloc_slab_data_va_base;
sh_slab_reg_virt_SLAB_STRUCT *new_slab_header=alloc->slabs_header;
new_slab_header->slab_index=alloc->slab_count;
new_slab_header->used_count=0;
new_slab_header->prev=SH_NULLPTR;
new_slab_header->next=SH_NULLPTR;
for (sh_iter64 i=0;i<16;i++) new_slab_header->free_bitmap[i]=0;
new_slab_header->free_bitmap[0]|=1ULL;
new_slab_header->used_count=0;
status=sh_mem_set_8(alloc->slabs_data,0x00,SH_SLAB_REG_VIRT_SLAB_DATA_SIZE_BYTES);
if (sh_status_error(status)) return status;
if (!sh_pez_is_available()) {
sh_page_MEM_STATS mem_stats;
status=sh_page_get_memory_stats(&mem_stats);
if (sh_status_error(status)) return status;
status=sh_page_set_pages_range_bitmap((sh_uint8*)sh_page_get_physical_bitmap_ptr(),mem_stats.memory_total_pages,slab_pa/SH_PAGE_SIZE,SH_SLAB_REG_VIRT_SLAB_DATA_PAGES,SH_TRUE);
if (sh_status_error(status)) return status;
}
alloc->partial_head=alloc->slabs_header;
*out_slab=new_slab_header;
alloc->slab_count++;
} else if (alloc->slabs_data!=SH_NULLPTR && alloc->slab_count!=0) {
sh_page_VIRTUAL_ADDRESS alloc_slab_data_va=SH_SLAB_REG_VIRT_DATA_VA+alloc->slab_count*SH_SLAB_REG_VIRT_SLAB_DATA_SIZE_BYTES;
status=sh_page_is_va_range_mapped_ptp(ptp,alloc_slab_data_va,SH_SLAB_REG_VIRT_SLAB_DATA_SIZE_BYTES);
if (status!=SH_STATUS_VA_NOT_MAPPED) return status;
status=sh_page_map_contiguous_pages_range_ptp(ptp,alloc_slab_data_va,slab_pa,SH_PAGE_PRESENT | SH_PAGE_NX | SH_PAGE_RW,SH_SLAB_REG_VIRT_SLAB_DATA_SIZE_BYTES);
if (sh_status_error(status)) return status;
sh_slab_reg_virt_SLAB_STRUCT *new_slab_header=alloc->slabs_header+alloc->slab_count;
new_slab_header->slab_index=alloc->slab_count;
new_slab_header->used_count=0;
new_slab_header->prev=SH_NULLPTR;
new_slab_header->next=alloc->partial_head;
sh_slab_reg_virt_SLAB_STRUCT *next_slab_header=new_slab_header->next;
next_slab_header->prev=new_slab_header;
alloc->partial_head=new_slab_header;
for (sh_iter64 i=0;i<16;i++) new_slab_header->free_bitmap[i]=0;
new_slab_header->free_bitmap[0]|=1ULL;
new_slab_header->used_count=0;
status=sh_mem_set_8(alloc->slabs_data+alloc->slab_count*SH_SLAB_REG_VIRT_SLAB_DATA_SIZE_BYTES,0x00,SH_SLAB_REG_VIRT_SLAB_DATA_SIZE_BYTES);
if (sh_status_error(status)) return status;
if (!sh_pez_is_available()) {
sh_page_MEM_STATS mem_stats;
status=sh_page_get_memory_stats(&mem_stats);
if (sh_status_error(status)) return status;
status=sh_page_set_pages_range_bitmap((sh_uint8*)sh_page_get_physical_bitmap_ptr(),mem_stats.memory_total_pages,slab_pa/SH_PAGE_SIZE,SH_SLAB_REG_VIRT_SLAB_DATA_PAGES,SH_TRUE);
if (sh_status_error(status)) return status;
}
*out_slab=new_slab_header;
alloc->slab_count++;
}
return SH_STATUS_SUCCESS;
}
SH_STATUS sh_slab_reg_virt_get_partial_slab(sh_slab_reg_virt_SLAB_ALLOCATOR* alloc,sh_page_PAGE_TABLE_POOL* ptp,sh_slab_reg_virt_SLAB_STRUCT** found_slab) {
if (alloc==SH_NULLPTR || ptp==SH_NULLPTR || found_slab==SH_NULLPTR) return SH_STATUS_INVALID_PARAMETER;
if (alloc->partial_head==SH_NULLPTR) {
*found_slab=SH_NULLPTR;
return SH_STATUS_NOT_FOUND;
}
sh_slab_reg_virt_SLAB_STRUCT* slab=alloc->partial_head;
if (slab->used_count>=SH_SLAB_REG_VIRT_ACTUAL_OBJECTS_PER_SLAB) {
if (slab->next!=SH_NULLPTR && slab->next->used_count<SH_SLAB_REG_VIRT_ACTUAL_OBJECTS_PER_SLAB) {
alloc->partial_head=slab->next;
alloc->partial_head->prev=SH_NULLPTR;
slab->next=SH_NULLPTR;
slab->prev=SH_NULLPTR;
*found_slab=alloc->partial_head;
return SH_STATUS_SUCCESS;
} else {
sh_slab_reg_virt_SLAB_STRUCT* new_slab;
SH_STATUS status=sh_slab_reg_virt_add_slab(alloc,ptp,&new_slab);
if (sh_status_error(status)) return status;
*found_slab=new_slab;
return SH_STATUS_NEW_SLAB_ADDED;
}
}
*found_slab=slab;
return SH_STATUS_SUCCESS;
}
SH_STATUS sh_slab_reg_virt_scan_slabs(sh_slab_reg_virt_SLAB_ALLOCATOR* alloc) {
if (alloc==SH_NULLPTR || alloc->slabs_data==SH_NULLPTR) return SH_STATUS_INVALID_PARAMETER;
sh_slab_reg_virt_SLAB_STRUCT* first_partial=SH_NULLPTR;
sh_slab_reg_virt_SLAB_STRUCT* last_partial=SH_NULLPTR;
sh_log_debug("Slabs rescan triggered.",SH_LOG_SOURCE_SLAB);
for (sh_uint32 i=0;i<alloc->slab_count;i++) {
sh_slab_reg_virt_SLAB_STRUCT* slab=alloc->slabs_header+i;
sh_uint8* slab_base=alloc->slabs_data+i*SH_SLAB_REG_VIRT_SLAB_DATA_SIZE_BYTES;
slab->used_count=0;
for (sh_iter64 w=0;w<16;w++) slab->free_bitmap[w]=0;
slab->free_bitmap[0]|=1ULL;
for (sh_uint16 obj_idx=1;obj_idx<SH_SLAB_REG_VIRT_OBJECTS_PER_SLAB;obj_idx++) {
sh_uint8* obj_ptr=slab_base+obj_idx*SH_SLAB_REG_VIRT_OBJECT_SIZE_BYTES;
int is_free=1;
for (sh_iter64 b=0;b<SH_SLAB_REG_VIRT_OBJECT_SIZE_BYTES;b++) {
if (obj_ptr[b]!=0) {
is_free=0;
break;
}
}
if (is_free) {
sh_uint16 word=obj_idx>>6;
sh_uint16 bit=obj_idx&63;
slab->free_bitmap[word]&= ~(1ULL<<bit);
} else {
sh_uint16 word=obj_idx>>6;
sh_uint16 bit=obj_idx&63;
slab->free_bitmap[word]|=(1ULL<<bit);
slab->used_count++;
}
}
sh_log_fdebug(SH_LOG_SOURCE_SLAB,"Slab index: %4u; used count: %4u\n",slab->slab_index,slab->used_count);
slab->prev=SH_NULLPTR;
slab->next=SH_NULLPTR;
if (slab->used_count>0 && slab->used_count<SH_SLAB_REG_VIRT_ACTUAL_OBJECTS_PER_SLAB) {
if (first_partial==SH_NULLPTR) {
first_partial=slab;
last_partial=slab;
} else {
slab->prev=last_partial;
last_partial->next=slab;
last_partial=slab;
}
}
}
alloc->partial_head=first_partial;
return SH_STATUS_SUCCESS;
}
SH_STATUS sh_slab_reg_virt_find_free_object(sh_slab_reg_virt_SLAB_ALLOCATOR* alloc,sh_page_PAGE_TABLE_POOL *ptp,sh_slab_reg_virt_OBJECT_INDEX* out_ref) {
if (alloc==SH_NULLPTR || ptp==SH_NULLPTR || out_ref==SH_NULLPTR) return SH_STATUS_INVALID_PARAMETER;
sh_slab_reg_virt_SLAB_STRUCT *partial_slab;
sh_slab_reg_virt_SLAB_STRUCT *new_slab;
SH_STATUS status=sh_slab_reg_virt_get_partial_slab(alloc,ptp,&partial_slab);
if (status==SH_STATUS_RESCAN_NEEDED) {
status=sh_slab_reg_virt_scan_slabs(alloc);
if (sh_status_error(status)) return status;
status=sh_slab_reg_virt_get_partial_slab(alloc,ptp,&partial_slab);
}
if (status==SH_STATUS_NOT_FOUND) {
status=sh_slab_reg_virt_add_slab(alloc,ptp,&new_slab);
if (sh_status_error(status)) return status;
status=sh_slab_reg_virt_get_partial_slab(alloc,ptp,&partial_slab);
if (sh_status_error(status)) return status;
} else if (sh_status_error(status) && status!=SH_STATUS_NEW_SLAB_ADDED) {
return status;
}
sh_uint64 obj;
sh_bool obj_found=SH_FALSE;
for (sh_uint8 w=0;w<16;w++) {
sh_uint64 word=partial_slab->free_bitmap[w];
if (word!=SH_UINT64_MAX) {
if (w==0) {
for (sh_uint8 bit=0;bit<64;bit++) {
if (!(word & (1ULL<<bit))) {
sh_uint64 candidate=(sh_uint64)w*64+bit;
if (candidate==0) continue;
obj=candidate;
obj_found=SH_TRUE;
break;
}
}
} else {
for (sh_uint8 bit=0;bit<64;bit++) {
if (!(word & (1ULL<<bit))) {
obj=(sh_uint64)w*64+bit;
obj_found=SH_TRUE;
break;
}
}
}
}
if (obj_found==SH_TRUE) break;
}
if (obj_found==SH_FALSE) {
return SH_STATUS_RESCAN_NEEDED;
}
*out_ref=SH_SLAB_REG_VIRT_MAKE_REF(partial_slab->slab_index,obj);
return SH_STATUS_SUCCESS;
}
void* sh_slab_reg_virt_ref_to_ptr(sh_slab_reg_virt_SLAB_ALLOCATOR* alloc,sh_slab_reg_virt_OBJECT_INDEX ref) {
if (alloc==SH_NULLPTR) {
return SH_NULLPTR;
}
if (SH_SLAB_REG_VIRT_REF_SLAB(ref)>=alloc->slab_count || SH_SLAB_REG_VIRT_REF_OBJECT(ref)==0) {
return SH_NULLPTR;
}
sh_uint32 slab=SH_SLAB_REG_VIRT_REF_SLAB(ref);
sh_uint16 object=SH_SLAB_REG_VIRT_REF_OBJECT(ref);
if (object==0) {
return SH_NULLPTR;
}
return alloc->slabs_data+slab*SH_SLAB_REG_VIRT_SLAB_DATA_SIZE_BYTES+object*SH_SLAB_REG_VIRT_OBJECT_SIZE_BYTES;
}
SH_STATUS sh_slab_reg_virt_alloc(sh_slab_reg_virt_SLAB_ALLOCATOR* alloc,sh_page_PAGE_TABLE_POOL *ptp,sh_slab_reg_virt_OBJECT_INDEX* out_index) {
if (alloc==SH_NULLPTR || ptp==SH_NULLPTR || out_index==SH_NULLPTR) return SH_STATUS_INVALID_PARAMETER;
sh_slab_reg_virt_OBJECT_INDEX ref;
SH_STATUS status=sh_slab_reg_virt_find_free_object(alloc,ptp,&ref);
if (sh_status_error(status)) return status;
sh_uint32 slab_idx=SH_SLAB_REG_VIRT_REF_SLAB(ref);
sh_uint16 obj_idx=SH_SLAB_REG_VIRT_REF_OBJECT(ref);
sh_slab_reg_virt_SLAB_STRUCT* slab=alloc->slabs_header+slab_idx;
sh_uint16 word=obj_idx>>6;
sh_uint16 bit=obj_idx&63;
slab->free_bitmap[word]|=(1ULL<<bit);
sh_pez_REGION_VIRTUAL_OBJECT* obj=(sh_pez_REGION_VIRTUAL_OBJECT*)sh_slab_reg_virt_ref_to_ptr(alloc,ref);
if (obj==SH_NULLPTR) return SH_STATUS_ERROR_NULLPTR_RETURNED;
sh_mem_set_8((sh_uint8*)obj,0x0,SH_SLAB_REG_VIRT_OBJECT_SIZE_BYTES);
slab->used_count++;
*out_index=ref;
return SH_STATUS_SUCCESS;
}
SH_STATUS sh_slab_reg_virt_dealloc(sh_slab_reg_virt_SLAB_ALLOCATOR* alloc,sh_slab_reg_virt_OBJECT_INDEX index) {
if (alloc==SH_NULLPTR) return SH_STATUS_INVALID_PARAMETER;
if (SH_SLAB_REG_VIRT_REF_OBJECT(index)==0) return SH_STATUS_INVALID_PARAMETER;
if (SH_SLAB_REG_VIRT_REF_SLAB(index)>=alloc->slab_count) return SH_STATUS_INVALID_PARAMETER;
sh_uint16 obj_idx=SH_SLAB_REG_VIRT_REF_OBJECT(index);
sh_uint16 word=obj_idx>>6;
sh_uint16 bit=obj_idx&63;
sh_slab_reg_virt_SLAB_STRUCT* slab_header=alloc->slabs_header+SH_SLAB_REG_VIRT_REF_SLAB(index);
if (!(slab_header->free_bitmap[word] & (1ULL<<bit))) return SH_STATUS_SLAB_SLOT_ALREADY_FREE;
slab_header->free_bitmap[word]&= ~(1ULL<<bit);
if (slab_header->used_count==SH_SLAB_REG_VIRT_ACTUAL_OBJECTS_PER_SLAB) {
slab_header->prev=SH_NULLPTR;
slab_header->next=alloc->partial_head;
if (alloc->partial_head!=SH_NULLPTR) {
alloc->partial_head->prev=slab_header;
}
alloc->partial_head=slab_header;
}
slab_header->used_count--;
sh_uint8* obj_ptr=sh_slab_reg_virt_ref_to_ptr(alloc,index);
if (obj_ptr==SH_NULLPTR) return SH_STATUS_ERROR_NULLPTR_RETURNED;
sh_mem_set_8(obj_ptr,0x00,SH_SLAB_REG_VIRT_OBJECT_SIZE_BYTES);
return SH_STATUS_SUCCESS;
}

View File

@@ -0,0 +1,39 @@
// SPDX-License-Identifier: MPL-2.0
#include "std/malloc.h"
#include "memory/page.h"
#include "memory/heap.h"
#include "memory/vmem_layout.h"
#include "kernel/log.h"
SH_STATUS last_status=0;
SH_STATUS sh_malloc_get_last_status() {
return last_status;
}
void* sh_malloc(sh_uint64 size) {
if (size==0) return SH_NULLPTR;
sh_page_VIRTUAL_ADDRESS va=0;
SH_STATUS status;
if (size<=1024) {
status=sh_heap_allocate_object((sh_uint32)size,&va);
} else {
sh_uint32 pages=(sh_uint32)((size+4095LL)/4096LL);
status=sh_heap_allocate_pages(pages,&va);
}
last_status=status;
return (sh_status_error(status))?SH_NULLPTR:(void*)va;
}
void sh_free(void *ptr) {
if (ptr==SH_NULLPTR) return;
sh_page_VIRTUAL_ADDRESS va=(sh_page_VIRTUAL_ADDRESS)ptr;
if (va>=SH_VMEM_LAYOUT_HEAP_SLAB_LEVEL_0_VA && va<SH_VMEM_LAYOUT_HEAP_SLAB_LEVEL_7_VA+SH_VMEM_LAYOUT_HEAP_SLAB_LEVEL_7_SIZE_BYTES) {
last_status=sh_heap_free_object(va);
return;
}
if (va>=SH_VMEM_LAYOUT_HEAP_BIG_VA && va<SH_VMEM_LAYOUT_HEAP_SLAB_LEVEL_0_VA) {
last_status=sh_heap_free_pages(va);
if (sh_status_error(last_status)) {
sh_log_fcritical(SH_LOG_SOURCE_HEAP,"Couldn't free pages at va=0x%x\n",va);
}
return;
}
sh_log_fcritical(SH_LOG_SOURCE_HEAP,"va=0x%x doesn't came from heap\n",va);
}

35
shelter/lib/src/std/mem.c Normal file
View File

@@ -0,0 +1,35 @@
// SPDX-License-Identifier: MPL-2.0
#include "std/mem.h"
SH_STATUS sh_mem_compare(const void *a,const void *b,sh_uint64 size) {
if (a==SH_NULLPTR || b==SH_NULLPTR) {
return SH_STATUS_INVALID_PARAMETER;
}
const sh_uint8 *pa=(const sh_uint8 *)a;
const sh_uint8 *pb=(const sh_uint8 *)b;
for (sh_iter64 i=0;i<size;i++) {
if (pa[i]!=pb[i]) {
return SH_STATUS_MEM_NOT_EQUAL;
}
}
return SH_STATUS_SUCCESS;
}
SH_STATUS sh_mem_copy(const void *destination,const void *source,sh_uint64 size) {
if (destination==SH_NULLPTR || source==SH_NULLPTR) {
return SH_STATUS_INVALID_PARAMETER;
}
sh_uint8 *pa=( sh_uint8 *)destination;
const sh_uint8 *pb=(const sh_uint8 *)source;
for (sh_iter64 i=0;i<size;i++) {
pa[i]=pb[i];
}
return SH_STATUS_SUCCESS;
}
SH_STATUS sh_mem_set_8(sh_uint8 *ptr,const sh_uint8 byte,sh_uint64 count) {
if (ptr==SH_NULLPTR) {
return SH_STATUS_INVALID_PARAMETER;
}
for (sh_iter64 i=0;i<count;i++) {
ptr[i]=byte;
}
return SH_STATUS_SUCCESS;
}

260
shelter/main.c Normal file
View File

@@ -0,0 +1,260 @@
// SPDX-License-Identifier: MPL-2.0
#include "std/stdlib.h"
#include "kernel/test.h"
#include "kernel/log.h"
#include "kernel/conf.h"
#include "cpu/tsc.h"
#include "cpu/serial.h"
#include "memory/page.h"
#include "memory/slab.h"
#include "memory/pba.h"
#include "memory/heap.h"
#include "memory/pez/radix.h"
#include "memory/pez/pez.h"
int main() {
sh_tsc_init_tsc();
sh_log_string("\n---------------------------\n\n");
sh_log_log("Shelter v0.1",SH_LOG_SOURCE_MAIN);
sh_conf_BOOT_CONFIG *boot_config=SH_NULLPTR;
SH_STATUS status=sh_conf_get_boot_config(&boot_config);
if (status==SH_STATUS_INVALID_SIGNATURE) {
sh_log_critical("Boot config doesn't have signature on.",SH_LOG_SOURCE_CONF);
sh_log_fatal("Can't obtain boot config.",SH_LOG_SOURCE_MAIN);
while (SH_TRUE) {};
} else if (sh_status_error(status)) {
sh_log_error("Can't find boot config.",SH_LOG_SOURCE_CONF);
sh_log_fatal("Can't obtain boot config.",SH_LOG_SOURCE_MAIN);
while (SH_TRUE) {};
}
sh_log_log("Obtained boot config.",SH_LOG_SOURCE_CONF);
sh_log_log("Loading logging ring buffer setting...",SH_LOG_SOURCE_MAIN);
sh_log_load_logging_ring_size(boot_config->log_ring_size);
sh_log_log("Loading serial port setting...",SH_LOG_SOURCE_MAIN);
sh_log_load_serial_setting(boot_config->log_disable_serial_port);
sh_serial_load_serial_port_setting(boot_config->disable_serial_port);
sh_log_log("Loading PTP VA...",SH_LOG_SOURCE_MAIN);
sh_page_load_boot_ptp_va(boot_config->page_table_pool_va);
sh_log_log("Loading log level...",SH_LOG_SOURCE_MAIN);
sh_log_load_log_level(boot_config->log_level);
sh_log_string("[Shelter:Log @Log] ");
sh_log_uint64((sh_uint64)sh_tsc_get_kernel_current_tsc());
sh_log_string(" : Successfully set log level to ");
sh_log_uint64((sh_uint64)sh_log_get_log_level());
sh_log_string("\n");
sh_log_flog(SH_LOG_SOURCE_MAIN,"Set logging ring buffer to %2u pages.\n",boot_config->log_ring_size);
sh_log_log("Trying to obtain memory map...",SH_LOG_SOURCE_MAIN);
status=sh_page_copy_memory_map();
if (status==SH_STATUS_SUCCESS) {
sh_log_log("Successfully copied memory map.",SH_LOG_SOURCE_PAGE);
sh_log_log("Successfully obtained memory map.",SH_LOG_SOURCE_MAIN);
} else {
sh_log_error("Can't copy memory map.",SH_LOG_SOURCE_PAGE);
sh_log_fatal("Can't obtain memory map.",SH_LOG_SOURCE_MAIN);
while (SH_TRUE) {};
}
sh_log_log("Checking memory map...",SH_LOG_SOURCE_MAIN);
if (status==SH_STATUS_SUCCESS) {
sh_log_log("Successfully checked memory map.",SH_LOG_SOURCE_MAIN);
} else if (status==SH_STATUS_INVALID_SIGNATURE) {
sh_log_fatal("Can't check memory map.",SH_LOG_SOURCE_MAIN);
while (SH_TRUE) {};
} else if (status==SH_STATUS_MMAP_BUFFER_OVERFLOW) {
sh_log_fatal("Memory map is overflowing. Can't safely continue.",SH_LOG_SOURCE_MAIN);
while (SH_TRUE) {};
}
sh_log_log("Initializing current page table pool...",SH_LOG_SOURCE_MAIN);
sh_page_PAGE_TABLE_POOL kernel_ptp;
status=sh_page_init_ptp(boot_config->page_table_pool_pa,sh_page_get_boot_ptp_va(),boot_config->page_table_allocator_level,&kernel_ptp);
if (status==SH_STATUS_PT_POOL_NO_BITMAP_INIT) {
sh_log_fatal("Couldn't initialize current page table pool.",SH_LOG_SOURCE_MAIN);
while (SH_TRUE) {};
} else if (status==SH_STATUS_PT_POOL_NO_PAGE_SET) {
sh_log_fatal("Couldn't initialize current page table pool.",SH_LOG_SOURCE_MAIN);
while (SH_TRUE) {};
}
sh_log_log("Successfully initialized current page table pool.",SH_LOG_SOURCE_MAIN);
sh_log_log("Parsing memory map...",SH_LOG_SOURCE_MAIN);
status=sh_page_analyse_memory_map(&kernel_ptp);
if (sh_status_error(status)) {
sh_log_ffatal(SH_LOG_SOURCE_MAIN,"Couldn't parse memory map. Error code: %8s\n",status);
while (SH_TRUE) {};
}
sh_log_log("Successfully parsed memory map.",SH_LOG_SOURCE_MAIN);
sh_log_mem_stats(SH_LOG_SOURCE_MAIN);
sh_log_log("Page managment subsystem successfully initialized",SH_LOG_SOURCE_MAIN);
sh_slab_reg_phys_SLAB_ALLOCATOR slab_reg_phys;
status=sh_slab_reg_phys_alloc_init(&slab_reg_phys,&kernel_ptp);
if (sh_status_error(status)) {
sh_log_fatal("Couldn't initialize physical region object slab allocator.",SH_LOG_SOURCE_MAIN);
while (SH_TRUE) {};
}
sh_log_log("Successfully initialize physical region object slab allocator.",SH_LOG_SOURCE_MAIN);
sh_log_log("Allocating first slab...",SH_LOG_SOURCE_MAIN);
sh_slab_reg_phys_SLAB_STRUCT *first_slab_rp=SH_NULLPTR;
status=sh_slab_reg_phys_add_slab(&slab_reg_phys,&kernel_ptp,&first_slab_rp);
if (status!=SH_STATUS_SUCCESS) {
sh_log_ffatal(SH_LOG_SOURCE_MAIN,"Couldn't allocate first slab. Error code: %8s\n",status);
while (SH_TRUE) {};
} else {
sh_log_log("Successfully allocated first slab. Verifying data...",SH_LOG_SOURCE_MAIN);
if (first_slab_rp->free_bitmap[0]!=1 ||
first_slab_rp->slab_index!=0 ||
first_slab_rp->next!=SH_NULLPTR ||
first_slab_rp->prev!=SH_NULLPTR ||
first_slab_rp->used_count!=0) {
sh_log_error("One of the attributes inside first slab is wrong.",SH_LOG_SOURCE_MAIN);
sh_log_fatal("Stopping for safety.",SH_LOG_SOURCE_MAIN);
while (SH_TRUE) {};
} else {
sh_log_log("All attributes are good.",SH_LOG_SOURCE_MAIN);
}
}
sh_slab_reg_virt_SLAB_ALLOCATOR slab_reg_virt;
status=sh_slab_reg_virt_alloc_init(&slab_reg_virt,&kernel_ptp);
if (sh_status_error(status)) {
sh_log_fatal("Couldn't initialize virtual region object slab allocator.",SH_LOG_SOURCE_MAIN);
while (SH_TRUE) {};
}
sh_log_log("Successfully initialize virtual region object slab allocator.",SH_LOG_SOURCE_MAIN);
sh_log_log("Allocating first slab...",SH_LOG_SOURCE_MAIN);
sh_slab_reg_virt_SLAB_STRUCT *first_slab_rv=SH_NULLPTR;
status=sh_slab_reg_virt_add_slab(&slab_reg_virt,&kernel_ptp,&first_slab_rv);
if (status!=SH_STATUS_SUCCESS) {
sh_log_ffatal(SH_LOG_SOURCE_MAIN,"Couldn't allocate first slab. Error code: %8s\n",status);
while (SH_TRUE) {};
} else {
sh_log_log("Successfully allocated first slab. Verifying data...",SH_LOG_SOURCE_MAIN);
if (first_slab_rv->free_bitmap[0]!=1 ||
first_slab_rv->slab_index!=0 ||
first_slab_rv->next!=SH_NULLPTR ||
first_slab_rv->prev!=SH_NULLPTR ||
first_slab_rv->used_count!=0) {
sh_log_error("One of the attributes inside first slab is wrong.",SH_LOG_SOURCE_MAIN);
sh_log_fatal("Stopping for safety.",SH_LOG_SOURCE_MAIN);
while (SH_TRUE) {};
} else {
sh_log_log("All attributes are good.",SH_LOG_SOURCE_MAIN);
}
}
sh_pba_PAGE_BLOCK_ALLOCATOR slab_radix_node_pba;
status=sh_pba_init(&slab_radix_node_pba,SH_VMEM_LAYOUT_SLAB_RADIX_NODE_VA,SH_VMEM_LAYOUT_SLAB_RADIX_NODE_SIZE_BYTES/SH_PAGE_SIZE,SH_SLAB_RADIX_NODE_SLAB_DATA_PAGES);
if (sh_status_error(status)) {
sh_log_fatal("Couldn't initialize PBA for radix nodes slab allocator.",SH_LOG_SOURCE_MAIN);
while (SH_TRUE) {};
}
sh_log_log("Successfully initialize PBA for radix nodes slab allocator.",SH_LOG_SOURCE_MAIN);
struct sh_slab_radix_node_SLAB_ALLOCATOR slab_radix_node;
status=sh_slab_radix_node_alloc_init(&slab_radix_node,&slab_radix_node_pba);
if (sh_status_error(status)) {
sh_log_fatal("Couldn't initialize radix nodes slab allocator.",SH_LOG_SOURCE_MAIN);
while (SH_TRUE) {};
}
sh_log_log("Successfully initialize radix nodes slab allocator.",SH_LOG_SOURCE_MAIN);
sh_log_log("Allocating first slab...",SH_LOG_SOURCE_MAIN);
sh_slab_radix_node_SLAB *first_slab_rn=SH_NULLPTR;
status=sh_slab_radix_node_add_slab(&slab_radix_node,&kernel_ptp,&first_slab_rn);
if (status!=SH_STATUS_SUCCESS) {
sh_log_ffatal(SH_LOG_SOURCE_MAIN,"Couldn't allocate first slab. Error code: %8s\n",status);
while (SH_TRUE) {};
} else {
sh_log_log("Successfully allocated first slab. Verifying data...",SH_LOG_SOURCE_MAIN);
if (first_slab_rn->free_bitmap[0]!=0x3FFFF ||
first_slab_rn->slab_index!=0 ||
first_slab_rn->next_slab!=SH_NULLPTR ||
first_slab_rn->prev_slab!=SH_NULLPTR ||
first_slab_rn->next_partial!=SH_NULLPTR ||
first_slab_rn->prev_partial!=SH_NULLPTR ||
first_slab_rn->used_count!=0 ) {
sh_log_error("One of the attributes inside first slab is wrong.",SH_LOG_SOURCE_MAIN);
sh_log_fatal("Stopping for safety.",SH_LOG_SOURCE_MAIN);
while (SH_TRUE) {};
} else {
sh_log_log("All attributes are good.",SH_LOG_SOURCE_MAIN);
}
}
if (boot_config->test_benchmark) {
status=sh_test_slabs_benchmark(&slab_reg_phys,&slab_reg_virt,&slab_radix_node,&kernel_ptp);
if (status!=SH_STATUS_SUCCESS) {
sh_log_fatal("Couldn't benchmark one of the slab allocator.",SH_LOG_SOURCE_MAIN);
while (SH_TRUE) {};
}
status=sh_test_radix_benchmark(&slab_radix_node,&kernel_ptp);
if (status!=SH_STATUS_SUCCESS) {
sh_log_fatal("Couldn't benchmark radix trees subsystem.",SH_LOG_SOURCE_MAIN);
while (SH_TRUE) {};
}
}
sh_log_log("Creating Pez physical plane...",SH_LOG_SOURCE_MAIN);
sh_pez_PHYSICAL_PLANE physical_plane;
status=sh_pez_init_physical_plane((sh_uint8*)sh_page_get_physical_bitmap_ptr(),sh_page_get_physical_memory_amount_pages(),&slab_reg_phys,&slab_radix_node,&kernel_ptp,&physical_plane);
if (status!=SH_STATUS_SUCCESS) {
sh_log_ffatal(SH_LOG_SOURCE_MAIN,"Couldn't create Pez physical plane. Error code: %8s\n",status);
while (SH_TRUE) {};
}
sh_log_log("Succesfully created Pez physical plane.",SH_LOG_SOURCE_MAIN);
if (boot_config->test_benchmark) {
status=sh_test_pez_benchmark_physical(&physical_plane);
if (status!=SH_STATUS_SUCCESS) {
sh_log_fatal("Couldn't benchmark Pez physical plane.",SH_LOG_SOURCE_MAIN);
while (SH_TRUE) {};
}
}
sh_log_log("Creating Pez virtual plane for kernel heap...",SH_LOG_SOURCE_MAIN);
sh_pez_VIRTUAL_PLANE virtual_plane_kernel_heap;
status=sh_pez_init_virtual_plane(SH_VMEM_LAYOUT_HEAP_BIG_VA,&slab_reg_virt,&slab_radix_node,&kernel_ptp,&kernel_ptp,&virtual_plane_kernel_heap);
if (status!=SH_STATUS_SUCCESS) {
sh_log_ffatal(SH_LOG_SOURCE_MAIN,"Couldn't create Pez virtual plane for kernel heap. Error code: %8s\n",status);
while (SH_TRUE) {};
}
sh_log_log("Succesfully created Pez virtual plane for kernel heap.",SH_LOG_SOURCE_MAIN);
sh_pez_set_available();
sh_heap_KERNEL_HEAP kernel_heap;
status=sh_heap_init_heap(&physical_plane,&virtual_plane_kernel_heap,&kernel_ptp,&kernel_heap);
if (sh_status_error(status)) {
sh_log_ffatal(SH_LOG_SOURCE_MAIN,"Couldn't initialize kernel heap. Error code: %8s",status);
while (SH_TRUE) {};
}
sh_uint64 slab_data_pages[8]=SH_SLAB_GENERIC_SLAB_DATA_PAGES;
for (sh_iter64 i=0;i<8;i++) {
status=sh_pba_init(&kernel_heap.pba[i],SH_VMEM_LAYOUT_HEAP_SLAB_LEVEL_0_VA+i*SH_VMEM_LAYOUT_HEAP_SLAB_SPACING,((SH_VMEM_LAYOUT_HEAP_SLAB_LEVEL_0_SIZE_BYTES/SH_PAGE_SIZE)/slab_data_pages[i])*slab_data_pages[i],slab_data_pages[i]);
if (sh_status_error(status)) {
sh_log_ffatal(SH_LOG_SOURCE_MAIN,"Couldn't create PBA for heap allocations level %8u. Error code: %8s\n",i,status);
while (SH_TRUE);
}
status=sh_slab_generic_alloc_init((sh_uint8)i,&kernel_heap.slabs_allocator[i],&kernel_heap.pba[i]);
if (sh_status_error(status)) {
sh_log_ffatal(SH_LOG_SOURCE_MAIN,"Couldn't create slab allocator for heap allocations level %8u. Error code: %8s\n",i,status);
while (SH_TRUE);
}
sh_slab_generic_SLAB *first_slab_generic;
status=sh_slab_generic_add_slab(&kernel_heap.slabs_allocator[i],&kernel_ptp,&first_slab_generic);
if (status!=SH_STATUS_SUCCESS) {
sh_log_ffatal(SH_LOG_SOURCE_MAIN,"Couldn't allocate first slab for heap allocations level %8u. Error code: %8s\n",i,status);
while (SH_TRUE) {};
} else {
if (first_slab_generic->free_bitmap[0]!=kernel_heap.slabs_allocator[i].bitmap_init ||
first_slab_generic->slab_index!=0 ||
first_slab_generic->next_slab!=SH_NULLPTR ||
first_slab_generic->prev_slab!=SH_NULLPTR ||
first_slab_generic->next_partial!=SH_NULLPTR ||
first_slab_generic->prev_partial!=SH_NULLPTR ||
first_slab_generic->used_count!=0 ) {
sh_log_error("One of the attributes inside first slab is wrong.",SH_LOG_SOURCE_MAIN);
sh_log_fatal("Stopping for safety.",SH_LOG_SOURCE_MAIN);
while (SH_TRUE) {};
}
}
sh_log_flog(SH_LOG_SOURCE_MAIN,"Succesfully created heap slab allocator with level %8u.\n",i);
}
sh_heap_load_default_heap(&kernel_heap);
sh_log_log("Succesfully created kernel heap.",SH_LOG_SOURCE_MAIN);
if (boot_config->test_benchmark) {
status=sh_test_malloc_benchmark();
if (status!=SH_STATUS_SUCCESS) {
sh_log_fatal("Couldn't benchmark Pez physical plane.",SH_LOG_SOURCE_MAIN);
while (SH_TRUE) {};
}
}
while (1) {};
return 0;
}

View File

@@ -0,0 +1,119 @@
# SPDX-License-Identifier: MPL-2.0
import os
import sys
import subprocess
class VirtualRegion:
def __init__(self,start,size):
self.start=start
self.size=size
def compute_end(self):
self.end=self.start+self.size
args=sys.argv
if len(args)!=2:
print("[VMLC] Error: not enough arguments")
exit(-1)
hfile=args[1]
if not os.path.exists(hfile):
print("[VMLC] Error: provided .h file doesn't exist")
exit(-1)
hfile=os.path.abspath(hfile)
print("[VMLC] Provided file: "+hfile)
incomplete_region_va=[]
incomplete_region_size_bytes=[]
region_name=[]
fileslines=open(hfile,"r").readlines()
macros=[]
for i in range(len(fileslines)):
if fileslines[i].startswith("#define"):
macros.append(fileslines[i])
for i in range(len(macros)):
macroname=str(str(macros[i]).strip(" ").split(" ")[1])
if macroname.endswith("_VA"):
if not macroname in incomplete_region_va:
incomplete_region_va.append(macroname)
else:
print("[VMLC] Error: found duplicate macro: "+macroname)
exit(-1)
elif macroname.endswith("_SIZE_BYTES"):
if not macroname in incomplete_region_size_bytes:
incomplete_region_size_bytes.append(macroname)
else:
print("[VMLC] Error: found duplicate macro: "+macroname)
exit(-1)
for i in range(len(incomplete_region_va)):
macronamesize=str(incomplete_region_va[i]).removesuffix("_VA")+"_SIZE_BYTES"
if not macronamesize in incomplete_region_size_bytes:
print("[VMLC] Error: for region \""+str(incomplete_region_va[i]).removesuffix("_VA")+"\", corresponding size wasn't found.")
exit(-1)
for i in range(len(incomplete_region_size_bytes)):
macronameva=str(incomplete_region_size_bytes[i]).removesuffix("_SIZE_BYTES")+"_VA"
if not macronameva in incomplete_region_va:
print("[VMLC] Warning: for region \""+str(incomplete_region_size_bytes[i]).removesuffix("_SIZE_BYTES")+"\", corresponding VA wasn't found. Skipping")
print("[VMLC] Found "+str(len(incomplete_region_va))+" valid virtual regions: ",end="")
for i in range(len(incomplete_region_va)):
if i!=len(incomplete_region_va)-1:
print(incomplete_region_va[i].removesuffix("_VA")+", ",end="")
else:
print(incomplete_region_va[i].removesuffix("_VA"))
region_name.append(incomplete_region_va[i].removesuffix("_VA"))
os.chdir(os.path.dirname(__file__))
try:
os.remove("cfile.c")
except FileNotFoundError:
pass
tmpcfile=open("cfile.c","w")
tmpcfile.write("#include <string.h>\n#include <stdio.h>\n#include <inttypes.h>\n#include \""+hfile+"\"\n")
tmpcfile.write("int main() {\n char buf[256];\n FILE *f=fopen(\"reg.txt\",\"w\");\n")
tmpcfile.write(" if (!f) return -1;\n")
for i in range(len(region_name)):
tmpcfile.write(" snprintf(buf,256,\"%\" PRIu64 \" %\" PRIu64 \"\\n\",(uint64_t)"+region_name[i]+"_VA,(uint64_t)"+region_name[i]+"_SIZE_BYTES);\n")
tmpcfile.write(" fwrite(buf,1,strlen(buf),f);\n")
tmpcfile.write(" fclose(f);\n return 0;\n}")
tmpcfile.close()
try:
os.remove("cfile")
os.remove("reg.txt")
except FileNotFoundError:
pass
r=subprocess.run(["gcc","cfile.c","-o","cfile"])
if r.returncode!=0:
print("[VMLC] Error: can't compile generated cfile.c")
exit(-1)
r=subprocess.run(["./cfile"])
if r.returncode!=0:
print("[VMLC] Error: can't run compiled cfile")
exit(-1)
if not os.path.exists("reg.txt"):
print("[VMLC] Error: reg.txt doesn't exist")
exit(-1)
reglist={}
regstart=[]
with open("reg.txt") as f:
for line in f:
va,size=line.strip().split()
vr=VirtualRegion(int(va),int(size))
vr.compute_end()
reglist[int(va)]=vr
if not vr.start in regstart:
regstart.append(vr.start)
else:
print("[VMLC] Error: found two regions starting at the same VA: "+str(vr.start)+" / 0x"+str(hex(vr.start)))
exit(-1)
print("[VMLC] Obtained region decimal VA and size.")
regstart.sort()
regboundaries=[]
for i in range(len(regstart)):
regboundaries.append(reglist[regstart[i]].start)
regboundaries.append(reglist[regstart[i]].end)
print("[VMLC] Checking for overlaps...")
for i in range(1,len(regboundaries)-1,2):
if regboundaries[i]>regboundaries[i+1]:
print("[VMLC] Error: found overlap between region ending at "+str(regboundaries[i])+" / 0x"+str(hex(regboundaries[i]))+" and region starting at "+str(regboundaries[i+1])+" / 0x"+str(hex(regboundaries[i+1])))
exit(-1)
print("[VMLC] No overlaps found.")
try:
os.remove("reg.txt")
os.remove("cfile.c")
os.remove("cfile")
except FileNotFoundError:
pass

View File

@@ -0,0 +1,43 @@
# SPDX-License-Identifier: MPL-2.0
import random
print("// SPDX-License-Identifier: MPL-2.0\n// This file contain the values to use as alloc size for the benchmark of sh_malloc and sh_free\n// It's autogenerated by tools/generator/malloc_payload_gen.py\n// Copy the output of this script in this file to regenerate it.")
print("#ifndef SH_LIB_PAYLOADS_TEST_MALLOC\n#define SH_LIB_PAYLOADS_TEST_MALLOC\n#include \"std/type.h\"")
print("__attribute__((section(\".data\"))) sh_uint32 test_malloc_small_size[10000]={",end="")
out=[]
lambd=0.006
while len(out)<10000:
val=int(random.expovariate(lambd))+2
if val<=1024:
out.append(val)
random.shuffle(out)
for i in range(len(out)):
print(out[i],end="")
if i!=(len(out)-1):
print(",",end="")
print("};")
print("__attribute__((section(\".data\"))) sh_uint32 test_malloc_big_size[1000]={",end="")
out=[]
lambd=0.006
while len(out)<1000:
val=int(random.expovariate(lambd))+2
if val<=25:
out.append(val)
random.shuffle(out)
for i in range(len(out)):
print(out[i],end="")
if i!=(len(out)-1):
print(",",end="")
print("};")
print("__attribute__((section(\".data\"))) sh_uint16 test_malloc_big_alloc[2000]={",end="")
out=[]
for i in range(0,1000):
out.append(i)
for i in range(0,1000):
out.append(i)
random.shuffle(out)
for i in range(len(out)):
print(out[i],end="")
if i!=(len(out)-1):
print(",",end="")
print("};")
print("#endif")

View File

@@ -0,0 +1,34 @@
# SPDX-License-Identifier: MPL-2.0
import random
print("// SPDX-License-Identifier: MPL-2.0\n// This file contain the values to use as pages count for the benchmark of allocs and free with Pez\n// It's autogenerated by tools/generator/pez_alloc_free_payload_gen.py\n// Copy the output of this script in this file to regenerate it.")
print("#ifndef SH_LIB_PAYLOADS_TEST_PEZ\n#define SH_LIB_PAYLOADS_TEST_PEZ\n#include \"std/type.h\"")
print("__attribute__((section(\".data\"))) sh_uint64 test_pez_physical_size[2000]={",end="")
out=[]
for i in range(1000):
out.append(1)
rand_list=[]
lambd=0.006
while len(rand_list)<1000:
val=int(random.expovariate(lambd))+2
if val<=1000:
rand_list.append(val)
out=out+rand_list
random.shuffle(out)
for i in range(len(out)):
print(out[i],end="")
if i!=(len(out)-1):
print(",",end="")
print("};")
print("__attribute__((section(\".data\"))) sh_uint64 test_pez_physical_alloc[4000]={",end="")
out=[]
for i in range(0,2000):
out.append(i)
for i in range(0,2000):
out.append(i)
random.shuffle(out)
for i in range(len(out)):
print(out[i],end="")
if i!=(len(out)-1):
print(",",end="")
print("};")
print("#endif")

View File

@@ -0,0 +1,18 @@
# SPDX-License-Identifier: MPL-2.0
import random
print("// SPDX-License-Identifier: MPL-2.0\n// This file contain the values to use as keys, values and search for the benchmarks of the radix trees subsystem\n// It's autogenerated by tools/generator/radix_tree_payload_gen.py\n// Copy the output of this script in this file to regenerate it.")
print("#ifndef SH_LIB_PAYLOADS_TEST_RADIX\n#define SH_LIB_PAYLOADS_TEST_RADIX\n#include \"std/type.h\"")
hex_char=["1","2","3","4","5","6","7","8","9","0","A","B","C","D","E","F"];
def randlist(num:int,hex_char_num:int,name:str):
print("__attribute__((section(\".data\"))) sh_uint64 "+name+"["+str(num)+"]={",end="")
for i in range(num):
print("0x",end="")
for y in range(hex_char_num):
print(hex_char[random.randint(0,15)],end="")
if i!=(num-1):
print(",",end="")
print("};")
randlist(10000,16,"test_keys")
randlist(10000,16,"test_values")
randlist(10000,16,"test_search")
print("#endif")