First commit, Vystem v0.1
This commit is contained in:
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;
|
||||
}
|
||||
Reference in New Issue
Block a user