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;
|
||||
}
|
||||
Reference in New Issue
Block a user