#ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include static void KernAux_PFA_mark( KernAux_PFA pfa, bool status, size_t start, size_t end ) __attribute__((nonnull)); void KernAux_PFA_initialize(const KernAux_PFA pfa) { kernaux_memset(pfa->flags, 0, sizeof(pfa->flags)); } bool KernAux_PFA_is_available(const KernAux_PFA pfa, const size_t page_addr) { if (page_addr % KERNAUX_PFA_PAGE_SIZE != 0) return false; const size_t page_index = page_addr / KERNAUX_PFA_PAGE_SIZE; const size_t flag_index = page_index / 8; const unsigned char flag_mask = 1 << (page_index % 8); return pfa->flags[flag_index] & flag_mask; } void KernAux_PFA_mark_available( const KernAux_PFA pfa, const size_t start, const size_t end ) { KernAux_PFA_mark(pfa, true, start, end); } void KernAux_PFA_mark_unavailable( const KernAux_PFA pfa, const size_t start, const size_t end ) { KernAux_PFA_mark(pfa, false, start, end); } void KernAux_PFA_mark( const KernAux_PFA pfa, const bool status, size_t start, size_t end ) { if (start >= end) return; const size_t start_rem = start % KERNAUX_PFA_PAGE_SIZE; const size_t end_rem = (end + 1) % KERNAUX_PFA_PAGE_SIZE; if (start_rem != 0) { start = start - start_rem + KERNAUX_PFA_PAGE_SIZE; } if (end_rem != 0) { end = end - end_rem; } const size_t start_index = start / KERNAUX_PFA_PAGE_SIZE; const size_t end_index = end / KERNAUX_PFA_PAGE_SIZE; for (size_t index = start_index; index <= end_index; ++index) { const size_t flag_index = index / 8; const unsigned char flag_mask = 1 << (index % 8); if (status) { pfa->flags[flag_index] |= flag_mask; } else { pfa->flags[flag_index] &= ~flag_mask; } } } size_t KernAux_PFA_alloc_pages(const KernAux_PFA pfa, size_t mem_size) { const size_t mem_rem = mem_size % KERNAUX_PFA_PAGE_SIZE; if (mem_rem != 0) { mem_size = mem_size - mem_rem + KERNAUX_PFA_PAGE_SIZE; } const size_t pages_count = mem_size / KERNAUX_PFA_PAGE_SIZE; // We start from 1 because 0 indicates failure. // It is not very useful to alloc page at address 0; for (size_t index = 1, start = 0; index < KERNAUX_PFA_PAGES_COUNT_MAX; ++index) { const size_t flag_index = index / 8; const unsigned char flag_mask = 1 << (index % 8); if (!(pfa->flags[flag_index] & flag_mask)) { start = 0; continue; } if (start == 0) start = index; if (index - start + 1 == pages_count) { for (; index >= start; --index) { const size_t flag_index = index / 8; const unsigned char flag_mask = 1 << (index % 8); pfa->flags[flag_index] &= ~flag_mask; } return start * KERNAUX_PFA_PAGE_SIZE; } } return 0; } void KernAux_PFA_free_pages( const KernAux_PFA pfa, const size_t page_addr, size_t mem_size ) { if (page_addr % KERNAUX_PFA_PAGE_SIZE != 0) return; const size_t mem_rem = mem_size % KERNAUX_PFA_PAGE_SIZE; if (mem_rem != 0) { mem_size = mem_size - mem_rem + KERNAUX_PFA_PAGE_SIZE; } const size_t start_index = page_addr / KERNAUX_PFA_PAGE_SIZE; const size_t pages_count = mem_size / KERNAUX_PFA_PAGE_SIZE; for (size_t index = 0; index < pages_count; ++index) { const size_t flag_index = (start_index + index) / 8; const unsigned char flag_mask = 1 << ((start_index + index) % 8); pfa->flags[flag_index] |= flag_mask; } }