First commit, Vystem v0.1
This commit is contained in:
26
shelter/lib/include/cpu/asm.h
Normal file
26
shelter/lib/include/cpu/asm.h
Normal 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
|
||||
11
shelter/lib/include/cpu/serial.h
Normal file
11
shelter/lib/include/cpu/serial.h
Normal 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
|
||||
18
shelter/lib/include/cpu/tsc.h
Normal file
18
shelter/lib/include/cpu/tsc.h
Normal 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
|
||||
25
shelter/lib/include/kernel/conf.h
Normal file
25
shelter/lib/include/kernel/conf.h
Normal 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
|
||||
146
shelter/lib/include/kernel/log.h
Normal file
146
shelter/lib/include/kernel/log.h
Normal 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
|
||||
7
shelter/lib/include/kernel/test.h
Normal file
7
shelter/lib/include/kernel/test.h
Normal 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"
|
||||
9
shelter/lib/include/kernel/tests/test_malloc.h
Normal file
9
shelter/lib/include/kernel/tests/test_malloc.h
Normal 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
|
||||
11
shelter/lib/include/kernel/tests/test_pez.h
Normal file
11
shelter/lib/include/kernel/tests/test_pez.h
Normal 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
|
||||
14
shelter/lib/include/kernel/tests/test_radix.h
Normal file
14
shelter/lib/include/kernel/tests/test_radix.h
Normal 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
|
||||
19
shelter/lib/include/kernel/tests/test_slabs.h
Normal file
19
shelter/lib/include/kernel/tests/test_slabs.h
Normal 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
|
||||
13
shelter/lib/include/kernel/tests/test_utils.h
Normal file
13
shelter/lib/include/kernel/tests/test_utils.h
Normal 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
|
||||
34
shelter/lib/include/memory/heap.h
Normal file
34
shelter/lib/include/memory/heap.h
Normal 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
|
||||
159
shelter/lib/include/memory/page.h
Normal file
159
shelter/lib/include/memory/page.h
Normal 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
|
||||
20
shelter/lib/include/memory/pba.h
Normal file
20
shelter/lib/include/memory/pba.h
Normal 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
|
||||
71
shelter/lib/include/memory/pez/pez.h
Normal file
71
shelter/lib/include/memory/pez/pez.h
Normal 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
|
||||
103
shelter/lib/include/memory/pez/pez_debug.h
Normal file
103
shelter/lib/include/memory/pez/pez_debug.h
Normal 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);
|
||||
31
shelter/lib/include/memory/pez/radix.h
Normal file
31
shelter/lib/include/memory/pez/radix.h
Normal 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
|
||||
18
shelter/lib/include/memory/ring.h
Normal file
18
shelter/lib/include/memory/ring.h
Normal 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
|
||||
6
shelter/lib/include/memory/slab.h
Normal file
6
shelter/lib/include/memory/slab.h
Normal 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"
|
||||
60
shelter/lib/include/memory/slabs/slab_generic.h
Normal file
60
shelter/lib/include/memory/slabs/slab_generic.h
Normal 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
|
||||
59
shelter/lib/include/memory/slabs/slab_radix_node.h
Normal file
59
shelter/lib/include/memory/slabs/slab_radix_node.h
Normal 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
|
||||
58
shelter/lib/include/memory/slabs/slab_reg_phys.h
Normal file
58
shelter/lib/include/memory/slabs/slab_reg_phys.h
Normal 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
|
||||
58
shelter/lib/include/memory/slabs/slab_reg_virt.h
Normal file
58
shelter/lib/include/memory/slabs/slab_reg_virt.h
Normal 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
|
||||
93
shelter/lib/include/memory/vmem_layout.h
Normal file
93
shelter/lib/include/memory/vmem_layout.h
Normal 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
|
||||
12
shelter/lib/include/std/malloc.h
Normal file
12
shelter/lib/include/std/malloc.h
Normal 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
|
||||
12
shelter/lib/include/std/mem.h
Normal file
12
shelter/lib/include/std/mem.h
Normal 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
|
||||
43
shelter/lib/include/std/status.h
Normal file
43
shelter/lib/include/std/status.h
Normal 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
|
||||
7
shelter/lib/include/std/stdlib.h
Normal file
7
shelter/lib/include/std/stdlib.h
Normal 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"
|
||||
35
shelter/lib/include/std/type.h
Normal file
35
shelter/lib/include/std/type.h
Normal 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
|
||||
14
shelter/lib/src/cpu/serial.c
Normal file
14
shelter/lib/src/cpu/serial.c
Normal 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
13
shelter/lib/src/cpu/tsc.c
Normal 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;
|
||||
}
|
||||
19
shelter/lib/src/kernel/conf.c
Normal file
19
shelter/lib/src/kernel/conf.c
Normal 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;
|
||||
}
|
||||
720
shelter/lib/src/kernel/log.c
Normal file
720
shelter/lib/src/kernel/log.c
Normal 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;
|
||||
}
|
||||
92
shelter/lib/src/kernel/tests/test_malloc.c
Normal file
92
shelter/lib/src/kernel/tests/test_malloc.c
Normal 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;
|
||||
}
|
||||
77
shelter/lib/src/kernel/tests/test_pez.c
Normal file
77
shelter/lib/src/kernel/tests/test_pez.c
Normal 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;
|
||||
}
|
||||
92
shelter/lib/src/kernel/tests/test_radix.c
Normal file
92
shelter/lib/src/kernel/tests/test_radix.c
Normal 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;
|
||||
}
|
||||
147
shelter/lib/src/kernel/tests/test_slabs.c
Normal file
147
shelter/lib/src/kernel/tests/test_slabs.c
Normal 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,®_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,®_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;
|
||||
}
|
||||
59
shelter/lib/src/kernel/tests/test_utils.c
Normal file
59
shelter/lib/src/kernel/tests/test_utils.c
Normal 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];
|
||||
}
|
||||
95
shelter/lib/src/memory/heap.c
Normal file
95
shelter/lib/src/memory/heap.c
Normal 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);
|
||||
}
|
||||
669
shelter/lib/src/memory/page.c
Normal file
669
shelter/lib/src/memory/page.c
Normal 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;
|
||||
}
|
||||
71
shelter/lib/src/memory/pba.c
Normal file
71
shelter/lib/src/memory/pba.c
Normal 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;
|
||||
}
|
||||
860
shelter/lib/src/memory/pez/pez.c
Normal file
860
shelter/lib/src/memory/pez/pez.c
Normal 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,®_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,®_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,®_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,®);
|
||||
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,®_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,®_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,®_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,®_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,®);
|
||||
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,®_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;
|
||||
}
|
||||
113
shelter/lib/src/memory/pez/pez_debug.c
Normal file
113
shelter/lib/src/memory/pez/pez_debug.c
Normal 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;
|
||||
}
|
||||
182
shelter/lib/src/memory/pez/radix.c
Normal file
182
shelter/lib/src/memory/pez/radix.c
Normal 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,¤t_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;
|
||||
}
|
||||
27
shelter/lib/src/memory/ring.c
Normal file
27
shelter/lib/src/memory/ring.c
Normal 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;
|
||||
}
|
||||
205
shelter/lib/src/memory/slabs/slab_generic.c
Normal file
205
shelter/lib/src/memory/slabs/slab_generic.c
Normal 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;
|
||||
}
|
||||
227
shelter/lib/src/memory/slabs/slab_radix_node.c
Normal file
227
shelter/lib/src/memory/slabs/slab_radix_node.c
Normal 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*)¤t->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];
|
||||
}
|
||||
274
shelter/lib/src/memory/slabs/slab_reg_phys.c
Normal file
274
shelter/lib/src/memory/slabs/slab_reg_phys.c
Normal 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;
|
||||
}
|
||||
271
shelter/lib/src/memory/slabs/slab_reg_virt.c
Normal file
271
shelter/lib/src/memory/slabs/slab_reg_virt.c
Normal 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;
|
||||
}
|
||||
39
shelter/lib/src/std/malloc.c
Normal file
39
shelter/lib/src/std/malloc.c
Normal 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
35
shelter/lib/src/std/mem.c
Normal 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;
|
||||
}
|
||||
Reference in New Issue
Block a user