#include "../include/page.h" #include __attribute__((section(".bss"))) static sh_uint8 memory_map_buffer[64*1024]; static sh_uint8 *physical_bitmap; __attribute__((section(".bss"))) static sh_uint64 physical_memory_pages_count=0; __attribute__((section(".bss"))) static sh_uint64 physical_memory_bytes_count=0; __attribute__((section(".bss"))) static sh_uint64 physical_bitmap_size_bytes=0; __attribute__((section(".bss"))) static sh_uint64 physical_bitmap_size_pages=0; static sh_page_VIRTUAL_ADRESS page_table_pool_va_ptr=SH_PAGE_NULL_VA; SH_STATUS sh_page_load_boot_ptp_va(sh_page_VIRTUAL_ADRESS pt_pool_va) { page_table_pool_va_ptr=pt_pool_va; sh_log_ldebug("Page table pool VA: 0x",SH_LOG_SOURCE_PAGE); sh_log_send_uintn_hex((sh_uint64)page_table_pool_va_ptr); sh_log_send_string("\n"); sh_uint8 first_byte=*(sh_uint8*)(page_table_pool_va_ptr); sh_log_debug("If you can see this message, no fault happened.",SH_LOG_SOURCE_PAGE); return SH_STATUS_SUCCESS; } sh_page_VIRTUAL_ADRESS sh_page_get_boot_ptp_va() { return page_table_pool_va_ptr; } SH_STATUS sh_page_copy_memory_map() { return sh_mem_copy(memory_map_buffer,(void*)SH_PAGE_MEMORY_MAP_VA,sizeof(memory_map_buffer)); } SH_STATUS sh_page_check_memory_map() { static const sh_uint8 memory_map_sig[8]={'S','h','e','M','m','a','p','B'}; if (sh_mem_compare(memory_map_sig,memory_map_buffer,sizeof(memory_map_sig))==SH_STATUS_MEM_NOT_EQUAL) { sh_log_critical("Memory map doesn't have signature on.",SH_LOG_SOURCE_PAGE); return SH_STATUS_INVALID_SIGNATURE; } sh_page_MEMORY_MAP_HEADER *memory_map_header=(sh_page_MEMORY_MAP_HEADER *)memory_map_buffer; sh_log_ldebug("Memory map entry count: ",SH_LOG_SOURCE_PAGE); sh_log_send_uintn((sh_uint64)memory_map_header->entry_count); sh_log_send_string("\n"); sh_log_ldebug("Memory map entry size: ",SH_LOG_SOURCE_PAGE); sh_log_send_uintn((sh_uint64)memory_map_header->entry_size); sh_log_send_string("\n"); sh_log_ldebug("Memory map syntax version: ",SH_LOG_SOURCE_PAGE); sh_log_send_uintn((sh_uint64)memory_map_header->mmap_syntax_version); sh_log_send_string("\n"); if (memory_map_header->entry_count*memory_map_header->entry_size+sizeof(sh_page_MEMORY_MAP_HEADER)>sizeof(memory_map_buffer)) { sh_log_error("Memory map overflow allocated buffer.",SH_LOG_SOURCE_PAGE); return SH_STATUS_MMAP_BUFFER_OVERFLOW; } return SH_STATUS_SUCCESS; } void sh_page_dump_memory_map() { sh_page_MEMORY_MAP_HEADER *memory_map_header=(sh_page_MEMORY_MAP_HEADER *)memory_map_buffer; sh_log_send_string("Memory map dump:\n"); sh_log_send_string("Header:\n"); for (sh_uint64 i=0;ientry_count;++i) { sh_log_send_string("Entry number "); sh_log_send_uintn(i); sh_log_send_string(" : "); for (sh_uint64 y=0;y=page_count) { return 0; } if ((value & (1ULL<page_count_in_bitmap) { return SH_STATUS_INVALID_PARAMETER; } for (sh_uint64 i=0;ipage_table_pa=ptp_pa; page_table_pool->page_table_va=ptp_va; page_table_pool->ptp_pages_count=SH_PAGE_PTP_ALLOCATOR_PAGES_COUNT; page_table_pool->ptp_alloc_bitmap_uint64_count=SH_PAGE_PTP_ALLOCATOR_BITMAP_UINT64; SH_STATUS status=sh_mem_set_8((sh_uint8*)page_table_pool->ptp_alloc_bitmap,SH_FALSE,sizeof(page_table_pool->ptp_alloc_bitmap)); if (sh_status_error(status)) { sh_log_error("Error: couldn't initialize page table pool bitmap.",SH_LOG_SOURCE_PAGE); return SH_STATUS_PT_POOL_NO_BITMAP_INIT; } if (initial_fill_level!=0) { status=sh_page_set_pages_range_bitmap((sh_uint8*)page_table_pool->ptp_alloc_bitmap,page_table_pool->ptp_pages_count,0,initial_fill_level,SH_TRUE); if (sh_status_error(status)) { sh_log_error("Error: couldn't initialize pages tables already alocated.",SH_LOG_SOURCE_PAGE); return SH_STATUS_PT_POOL_NO_PAGE_SET; } } return SH_STATUS_SUCCESS; } SH_STATUS sh_page_dump_ptp_bitmap(sh_page_PAGE_TABLE_POOL *ptp) { for (sh_uint64 i=0;iptp_alloc_bitmap_uint64_count;++i) { sh_log_send_string(" 0x"); sh_log_send_uintn_hex(ptp->ptp_alloc_bitmap[i]); } sh_log_send_string("\n"); return SH_STATUS_SUCCESS; } sh_page_PHYSICAL_ADRESS sh_page_ptp_alloc_one_page(sh_page_PAGE_TABLE_POOL *pt_pool) { if (pt_pool==SH_NULLPTR) { return SH_STATUS_INVALID_PARAMETER; } sh_uint64 page_count=pt_pool->ptp_pages_count; sh_uint64 bitmap_word_count=(page_count+63)/64; for (sh_uint64 word=0;wordptp_alloc_bitmap[word]; if (value==0xFFFFFFFFFFFFFFFFULL) { continue; } for (sh_uint64 bit=0;bit<64;bit++) { sh_uint64 page_index=(word*64)+bit; if (page_index>=page_count) { return 0; } if ((value & (1ULL<ptp_alloc_bitmap[word]|=(1ULL<page_table_pa+page_index*SH_PAGE_SIZE; return pa; } } } return 0; } SH_STATUS sh_page_map_one_page_ptp(sh_page_PAGE_TABLE_POOL *ptp,sh_page_VIRTUAL_ADRESS va,sh_page_PHYSICAL_ADRESS pa,sh_uint64 flags) { if (ptp==SH_NULLPTR) return SH_STATUS_INVALID_PARAMETER; if (va%SH_PAGE_SIZE!=0 || pa%SH_PAGE_SIZE!=0) return SH_STATUS_INVALID_PARAMETER; sh_uint64 pml4_i=(va>>39) & 0x1FF; sh_uint64 pdpt_i=(va>>30) & 0x1FF; sh_uint64 pd_i=(va>>21) & 0x1FF; sh_uint64 pt_i=(va>>12) & 0x1FF; sh_uint64 *pdpt; sh_uint64 *pd; sh_uint64 *pt; sh_uint64 *pml4=(sh_uint64*)ptp->page_table_va; if (!(pml4[pml4_i] & SH_PAGE_PRESENT)) { sh_page_PHYSICAL_ADRESS pdpt_pa=sh_page_ptp_alloc_one_page(ptp); if (!pdpt_pa) return SH_STATUS_OUT_OF_MEMORY; pdpt=sh_page_ptp_pa_to_va(ptp,pdpt_pa); if (!pdpt) return SH_STATUS_INVALID_INTERNAL_PA; sh_mem_set_8((sh_uint8*)pdpt,0,SH_PAGE_SIZE); pml4[pml4_i]=pdpt_pa | SH_PAGE_TABLE_FLAGS | SH_PAGE_PRESENT; } else { pdpt=sh_page_ptp_pa_to_va(ptp,(pml4[pml4_i] & ~0xFFFULL)); if (!pdpt) return SH_STATUS_INVALID_INTERNAL_PA; } if (!(pdpt[pdpt_i] & SH_PAGE_PRESENT)) { sh_page_PHYSICAL_ADRESS pd_pa=sh_page_ptp_alloc_one_page(ptp); if (!pd_pa) return SH_STATUS_OUT_OF_MEMORY; pd=sh_page_ptp_pa_to_va(ptp,pd_pa); if (!pd) return SH_STATUS_INVALID_INTERNAL_PA; sh_mem_set_8((sh_uint8*)pd,0,SH_PAGE_SIZE); pdpt[pdpt_i]=pd_pa | SH_PAGE_TABLE_FLAGS | SH_PAGE_PRESENT; } else { pd=sh_page_ptp_pa_to_va(ptp,(pdpt[pdpt_i] & ~0xFFFULL)); if (!pd) return SH_STATUS_INVALID_INTERNAL_PA; } if (!(pd[pd_i] & SH_PAGE_PRESENT)) { sh_page_PHYSICAL_ADRESS pt_pa=sh_page_ptp_alloc_one_page(ptp); if (!pt_pa) return SH_STATUS_OUT_OF_MEMORY; pt=sh_page_ptp_pa_to_va(ptp,pt_pa); if (!pt) return SH_STATUS_INVALID_INTERNAL_PA; sh_mem_set_8((sh_uint8*)pt,0,SH_PAGE_SIZE); pd[pd_i]=pt_pa | SH_PAGE_TABLE_FLAGS | SH_PAGE_PRESENT; } else { pt=sh_page_ptp_pa_to_va(ptp,pd[pd_i] & ~0xFFFULL); if (!pt) return SH_STATUS_INVALID_INTERNAL_PA; } pt[pt_i]=(pa & ~0xFFFULL) | flags | SH_PAGE_PRESENT; return SH_STATUS_SUCCESS; } SH_STATUS sh_page_is_va_mapped_ptp(sh_page_PAGE_TABLE_POOL *ptp,sh_page_VIRTUAL_ADRESS va) { if (ptp==SH_NULLPTR) return SH_STATUS_INVALID_PARAMETER; sh_uint64 pml4_i=(va>>39) & 0x1FF; sh_uint64 pdpt_i=(va>>30) & 0x1FF; sh_uint64 pd_i=(va>>21) & 0x1FF; sh_uint64 pt_i=(va>>12) & 0x1FF; sh_uint64 *pdpt; sh_uint64 *pd; sh_uint64 *pt; sh_uint64 *pml4=(sh_uint64*)ptp->page_table_va; if (!(pml4[pml4_i] & SH_PAGE_PRESENT)) { return SH_STATUS_VA_NOT_MAPPED; } else { pdpt=sh_page_ptp_pa_to_va(ptp,(pml4[pml4_i] & ~0xFFFULL)); if (pdpt==0) return SH_STATUS_INVALID_INTERNAL_PA; } if (!(pdpt[pdpt_i] & SH_PAGE_PRESENT)) { return SH_STATUS_VA_NOT_MAPPED; } else { pd=sh_page_ptp_pa_to_va(ptp,(pdpt[pdpt_i] & ~0xFFFULL)); if (pd==0) return SH_STATUS_INVALID_INTERNAL_PA; } if (!(pd[pd_i] & SH_PAGE_PRESENT)) { return SH_STATUS_VA_NOT_MAPPED; } else { pt=sh_page_ptp_pa_to_va(ptp,(pd[pd_i] & ~0xFFFULL)); if (pt==0) return SH_STATUS_INVALID_INTERNAL_PA; } if (!(pt[pt_i] & SH_PAGE_PRESENT)) { return SH_STATUS_VA_NOT_MAPPED; } else { return SH_STATUS_VA_MAPPED; } } SH_STATUS sh_page_is_va_range_mapped_ptp(sh_page_PAGE_TABLE_POOL *ptp,sh_page_VIRTUAL_ADRESS va,sh_uint64 size_bytes) { if (ptp==SH_NULLPTR) return SH_STATUS_INVALID_PARAMETER; if (va%SH_PAGE_SIZE!=0 || size_bytes%SH_PAGE_SIZE!=0 || size_bytes==0) return SH_STATUS_INVALID_PARAMETER; sh_uint64 counter=0; for (sh_uint64 i=0;i>39) & 0x1FF; sh_uint64 pdpt_i=(va>>30) & 0x1FF; sh_uint64 pd_i=(va>>21) & 0x1FF; sh_uint64 pt_i=(va>>12) & 0x1FF; sh_uint64 *pdpt; sh_uint64 *pd; sh_uint64 *pt; sh_uint64 *pml4=(sh_uint64*)ptp->page_table_va; if (!(pml4[pml4_i] & SH_PAGE_PRESENT)) { return SH_STATUS_ERROR_VA_NOT_MAPPED; } else { pdpt=sh_page_ptp_pa_to_va(ptp,(pml4[pml4_i] & ~0xFFFULL)); if (!pdpt) return SH_STATUS_INVALID_INTERNAL_PA; } if (!(pdpt[pdpt_i] & SH_PAGE_PRESENT)) { return SH_STATUS_ERROR_VA_NOT_MAPPED; } else { pd=sh_page_ptp_pa_to_va(ptp,(pdpt[pdpt_i] & ~0xFFFULL)); if (!pd) return SH_STATUS_INVALID_INTERNAL_PA; } if (!(pd[pd_i] & SH_PAGE_PRESENT)) { return SH_STATUS_ERROR_VA_NOT_MAPPED; } else { pt=sh_page_ptp_pa_to_va(ptp,pd[pd_i] & ~0xFFFULL); if (!pt) return SH_STATUS_INVALID_INTERNAL_PA; } pt[pt_i]=0x0ULL; __asm__ volatile("invlpg (%0)" :: "r"(va) : "memory"); return SH_STATUS_SUCCESS; } SH_STATUS sh_page_unmap_contiguous_pages_range_ptp(sh_page_PAGE_TABLE_POOL *ptp,sh_page_VIRTUAL_ADRESS va,sh_uint64 size_bytes) { if (ptp==SH_NULLPTR) return SH_STATUS_INVALID_PARAMETER; if (va%SH_PAGE_SIZE!=0 || size_bytes==0 || size_bytes%SH_PAGE_SIZE!=0) return SH_STATUS_INVALID_PARAMETER; sh_uint64 pages=size_bytes/SH_PAGE_SIZE; SH_STATUS status=sh_page_is_va_range_mapped_ptp(ptp,va,size_bytes); if (status==SH_STATUS_VA_PARTIALLY_MAPPED) return SH_STATUS_ERROR_VA_PARTIALLY_MAPPED; if (status==SH_STATUS_VA_NOT_MAPPED) return SH_STATUS_ERROR_VA_NOT_MAPPED; for (sh_uint64 i=0;i>39) & 0x1FF; sh_uint64 pdpt_i=(va>>30) & 0x1FF; sh_uint64 pd_i=(va>>21) & 0x1FF; sh_uint64 pt_i=(va>>12) & 0x1FF; sh_uint64 *pdpt; sh_uint64 *pd; sh_uint64 *pt; sh_uint64 *pml4=(sh_uint64*)ptp->page_table_va; if (!(pml4[pml4_i] & SH_PAGE_PRESENT)) { return SH_STATUS_ERROR_VA_NOT_MAPPED; } else { pdpt=sh_page_ptp_pa_to_va(ptp,(pml4[pml4_i] & ~0xFFFULL)); if (!pdpt) return SH_STATUS_INVALID_INTERNAL_PA; } if (!(pdpt[pdpt_i] & SH_PAGE_PRESENT)) { return SH_STATUS_ERROR_VA_NOT_MAPPED; } else { pd=sh_page_ptp_pa_to_va(ptp,(pdpt[pdpt_i] & ~0xFFFULL)); if (!pd) return SH_STATUS_INVALID_INTERNAL_PA; } if (!(pd[pd_i] & SH_PAGE_PRESENT)) { return SH_STATUS_ERROR_VA_NOT_MAPPED; } else { pt=sh_page_ptp_pa_to_va(ptp,pd[pd_i] & ~0xFFFULL); if (!pt) return SH_STATUS_INVALID_INTERNAL_PA; } if (!(pt[pt_i] & SH_PAGE_PRESENT)) return SH_STATUS_ERROR_VA_NOT_MAPPED; *pa=pt[pt_i] & 0x000FFFFFFFFFF000; return SH_STATUS_SUCCESS; } SH_STATUS sh_page_unalloc_one_page(sh_page_PAGE_TABLE_POOL *ptp,sh_page_VIRTUAL_ADRESS va) { if (ptp==SH_NULLPTR) return SH_STATUS_INVALID_PARAMETER; if (va%SH_PAGE_SIZE!=0) return SH_STATUS_INVALID_PARAMETER; sh_page_PHYSICAL_ADRESS equivalent_pa; SH_STATUS status=sh_page_ptp_va_to_pa(ptp,va,&equivalent_pa); if (status!=SH_STATUS_SUCCESS) return status; status=sh_page_unmap_one_page_ptp(ptp,va); // If this call return SH_STATUS_ERROR_VA_NOT_MAPPED, there is a severe bug that should cause kernel panic because sh_page_ptp_va_to_pa should already have returned exact same error code. if (status!=SH_STATUS_SUCCESS) return status; status=sh_page_set_pages_range_bitmap(physical_bitmap,physical_memory_pages_count,(sh_uint64)(equivalent_pa/SH_PAGE_SIZE),1,SH_FALSE); if (status!=SH_STATUS_SUCCESS) return status; return SH_STATUS_SUCCESS; } SH_STATUS sh_page_unalloc_contiguous(sh_page_PAGE_TABLE_POOL *ptp,sh_page_VIRTUAL_ADRESS va,sh_uint64 size_bytes) { if (ptp==SH_NULLPTR) return SH_STATUS_INVALID_PARAMETER; if (va%SH_PAGE_SIZE!=0 || size_bytes==0 || size_bytes%SH_PAGE_SIZE!=0) return SH_STATUS_INVALID_PARAMETER; SH_STATUS status=sh_page_is_va_range_mapped_ptp(ptp,va,size_bytes); if (status==SH_STATUS_VA_NOT_MAPPED) return SH_STATUS_ERROR_VA_NOT_MAPPED; if (status==SH_STATUS_VA_PARTIALLY_MAPPED) return SH_STATUS_ERROR_VA_PARTIALLY_MAPPED; sh_uint64 pages=size_bytes/SH_PAGE_SIZE; for (sh_uint64 i=0;ientry_count;i++) { sh_uint64 start_page=memory_map_cursor[i].physical_start/4096; sh_uint64 end_page=start_page+memory_map_cursor[i].pages_count; if (memory_map_cursor[i].type==SH_PAGE_CONVENTIONAL_MEMORY && memory_map_cursor[i].pages_count>biggest_segment_pages) { biggest_segment_pages=memory_map_cursor[i].pages_count; biggest_segment_index=i; } if (verbose) { sh_log_ldebug("Found memory map segment #",SH_LOG_SOURCE_PAGE); sh_log_send_uintn(i); sh_log_send_string(": [0x"); sh_log_send_uintn_hex(start_page*4096); sh_log_send_string(" - 0x"); sh_log_send_uintn_hex(end_page*4096); sh_log_send_string("] Memory type: "); sh_log_send_uintn(memory_map_cursor[i].type); if (memory_map_cursor[i].type==SH_PAGE_CONVENTIONAL_MEMORY) { sh_log_send_string(" --> usable\n"); } else { sh_log_send_string(" --> not usable\n"); } if (!(end_page<=SH_PAGE_MAX_PAGES_COUNT)) { sh_log_lwarning("Memory map segment #",SH_LOG_SOURCE_PAGE); sh_log_send_uintn(i); sh_log_send_string(" isn't usable because it overflow over max page count. Enable debug log channel to see more.\n"); } } if (memory_map_cursor[i].type==SH_PAGE_CONVENTIONAL_MEMORY && end_page<=SH_PAGE_MAX_PAGES_COUNT) { if (end_page>highest_usable_page) { highest_usable_segment=i; highest_usable_page=end_page; } } } physical_memory_pages_count=highest_usable_page; physical_memory_bytes_count=physical_memory_pages_count*SH_PAGE_SIZE; if (verbose) { sh_log_ldebug("Total memory was given by memory map segment #",SH_LOG_SOURCE_PAGE); sh_log_send_uintn(highest_usable_segment); sh_log_send_string("\n"); sh_log_ldebug("Total memory (pages): 0x",SH_LOG_SOURCE_PAGE); sh_log_send_uintn_hex(physical_memory_pages_count); sh_log_send_string(". Total memory (bytes) : 0x"); sh_log_send_uintn_hex(physical_memory_bytes_count); sh_log_send_string("\n"); } if (biggest_segment_pages==0) { sh_log_error("No suitable conventional memory segment found.",SH_LOG_SOURCE_PAGE); return SH_STATUS_OUT_OF_MEMORY; } if (memory_map_cursor[biggest_segment_index].pages_count<(physical_memory_pages_count/8)) { sh_log_error("Memory is too low or too fragmented to allocate physical bitmap.",SH_LOG_SOURCE_PAGE); return SH_STATUS_OUT_OF_MEMORY; } sh_page_PHYSICAL_ADRESS pa=memory_map_cursor[biggest_segment_index].physical_start; sh_page_VIRTUAL_ADRESS va; physical_bitmap_size_bytes=physical_memory_pages_count/8; if (physical_memory_pages_count%8!=0) physical_bitmap_size_bytes++; physical_bitmap_size_pages=physical_bitmap_size_bytes/SH_PAGE_SIZE; if (physical_bitmap_size_bytes%SH_PAGE_SIZE!=0) physical_bitmap_size_pages++; SH_STATUS status=sh_page_search_available_va_range(ptp,SH_PAGE_KERNEL_PERM_VA_BASE,(SH_PAGE_KERNEL_PERM_VA_END-SH_PAGE_KERNEL_PERM_VA_BASE+1-0x1000),physical_bitmap_size_pages*SH_PAGE_SIZE,&va); if (status!=SH_STATUS_SUCCESS) { sh_log_error("Memory is too low or too fragmented to allocate physical bitmap.",SH_LOG_SOURCE_PAGE); return status; } status=sh_page_map_contiguous_pages_range_ptp(ptp,va,pa,SH_PAGE_PRESENT | SH_PAGE_NX | SH_PAGE_RW,physical_bitmap_size_pages*SH_PAGE_SIZE); if (status==SH_STATUS_OUT_OF_MEMORY) { sh_log_error("Memory is too low or too fragmented to allocate physical bitmap.",SH_LOG_SOURCE_PAGE); return status; } else if (status!=SH_STATUS_SUCCESS) { sh_log_error("An unknow error happened during physical bitmap pages mapping. See error below",SH_LOG_SOURCE_PAGE); return status; } physical_bitmap=(sh_uint8*)va; status=sh_mem_set_8(physical_bitmap,0xFF,physical_bitmap_size_bytes); if (sh_status_error(status)) { sh_log_error("An unknow error happened during physical bitmap filling with 0xFF. See error below.",SH_LOG_SOURCE_PAGE); return status; } // second loop : actually set all free regions into physical bitmap for (sh_uint64 i=0;ientry_count;i++) { sh_uint64 start_page=memory_map_cursor[i].physical_start/4096; sh_uint64 end_page=start_page+memory_map_cursor[i].pages_count; if (end_page<=SH_PAGE_MAX_PAGES_COUNT) { if (memory_map_cursor[i].type==SH_PAGE_CONVENTIONAL_MEMORY) { SH_STATUS status=sh_page_set_pages_range_bitmap(physical_bitmap,physical_memory_pages_count,memory_map_cursor[i].physical_start/SH_PAGE_SIZE,memory_map_cursor[i].pages_count,SH_FALSE); if (sh_status_error(status)) { sh_log_error("Couldn't set this memory map segment to usable.",SH_LOG_SOURCE_PAGE); return SH_STATUS_PMAP_NO_PAGES_SET; } } } } sh_page_set_pages_range_bitmap(physical_bitmap,physical_memory_pages_count,pa/SH_PAGE_SIZE,physical_bitmap_size_pages,SH_TRUE); return SH_STATUS_SUCCESS; } sh_page_VIRTUAL_ADRESS sh_page_get_physical_bitmap_ptr() { return (sh_page_VIRTUAL_ADRESS)physical_bitmap; } static sh_uint64 popcount64(sh_uint64 x) { x=x-((x>>1) & 0x5555555555555555ULL); x=(x & 0x3333333333333333ULL)+((x>>2) & 0x3333333333333333ULL); x=(x+(x>>4)) & 0x0F0F0F0F0F0F0F0FULL; x=x+(x>>8); x=x+(x>>16); x=x+(x>>32); return x & 0x7F; } SH_STATUS sh_page_get_memory_stats(sh_page_MEM_STATS *mem_stats) { if (mem_stats==SH_NULLPTR) return SH_STATUS_INVALID_PARAMETER; mem_stats->memory_total_pages=physical_memory_pages_count; mem_stats->memory_total_bytes=physical_memory_bytes_count; sh_uint64 free_pages=0; sh_uint64 used_pages=0; sh_uint64 largest_free_block=0; sh_uint64 largest_used_block=0; sh_uint64 free_blocks_count=0; sh_uint64 used_blocks_count=0; sh_uint64 current_free_block=0; sh_uint64 current_used_block=0; sh_uint64 full_uint64_count=physical_memory_pages_count/64; sh_uint64 remaining_bits=physical_memory_pages_count%64; sh_uint64 *bitmap64=(sh_uint64*)physical_bitmap; for (sh_uint64 i=0;i>b) & 1; if (bit_set) { current_used_block++; if (current_free_block) { free_blocks_count++; if (current_free_block>largest_free_block) { largest_free_block=current_free_block; } current_free_block=0; } } else { current_free_block++; if (current_used_block) { used_blocks_count++; if (current_used_block>largest_used_block) { largest_used_block=current_used_block; } current_used_block=0; } } } } if (remaining_bits) { sh_uint64 val=bitmap64[full_uint64_count] & ((1ULL<>b) & 1; if (bit_set) { current_used_block++; if (current_free_block) { free_blocks_count++; if (current_free_block>largest_free_block) { largest_free_block=current_free_block; } current_free_block=0; } } else { current_free_block++; if (current_used_block) { used_blocks_count++; if (current_used_block>largest_used_block) { largest_used_block=current_used_block; } current_used_block=0; } } } } if (current_free_block) { free_blocks_count++; if (current_free_block>largest_free_block) { largest_free_block=current_free_block; } } if (current_used_block) { used_blocks_count++; if (current_used_block>largest_used_block) { largest_used_block=current_used_block; } } mem_stats->free_pages=free_pages; mem_stats->used_pages=used_pages; mem_stats->free_ratio=(double)free_pages/(double)physical_memory_pages_count; mem_stats->used_ratio=(double)used_pages/(double)physical_memory_pages_count; mem_stats->largest_free_block=largest_free_block; mem_stats->largest_used_block=largest_used_block; mem_stats->free_blocks_count=free_blocks_count; mem_stats->used_blocks_count=used_blocks_count; mem_stats->physical_bitmap_size_bytes=(physical_memory_pages_count+7)/8; mem_stats->physical_bitmap_size_pages=(mem_stats->physical_bitmap_size_bytes+4095)/4096; return SH_STATUS_SUCCESS; }