libkernaux/src/pfa.c

161 lines
4.1 KiB
C
Raw Normal View History

2020-12-07 04:46:37 +00:00
#ifdef HAVE_CONFIG_H
2020-11-30 11:40:33 +00:00
#include "config.h"
2020-12-07 04:46:37 +00:00
#endif
2020-11-30 11:40:33 +00:00
2021-12-17 23:43:19 +00:00
#include <kernaux/assert.h>
#include <kernaux/macro.h>
#include <kernaux/pfa.h>
#include "libc.h"
2021-12-14 18:50:27 +00:00
#define PAGE_INDEX(page_addr) ((page_addr) / KERNAUX_PFA_PAGE_SIZE)
#define FLAG_INDEX_FROM_INDEX(page_index) ((page_index) / 8)
#define FLAG_MASK_FROM_INDEX(page_index) KERNAUX_BITS((page_index) % 8)
2021-12-14 18:50:27 +00:00
#define FLAG_INDEX_FROM_ADDR(page_addr) \
(FLAG_INDEX_FROM_INDEX(PAGE_INDEX(page_addr)))
#define FLAG_MASK_FROM_ADDR(page_addr) \
(FLAG_MASK_FROM_INDEX(PAGE_INDEX(page_addr)))
2021-12-14 18:54:47 +00:00
#define GET_FLAG_FROM_INDEX(pfa, page_index) \
(!!((pfa)->flags[FLAG_INDEX_FROM_INDEX(page_index)] & \
FLAG_MASK_FROM_INDEX(page_index)))
#define GET_FLAG_FROM_ADDR(pfa, page_addr) \
(!!((pfa)->flags[FLAG_INDEX_FROM_ADDR(page_addr)] & \
FLAG_MASK_FROM_ADDR(page_addr)))
2021-12-14 19:01:23 +00:00
#define FLAG_TRUE_FROM_INDEX(pfa, page_index) \
((pfa)->flags[FLAG_INDEX_FROM_INDEX(page_index)] |= \
FLAG_MASK_FROM_INDEX(page_index))
#define FLAG_FALSE_FROM_INDEX(pfa, page_index) \
((pfa)->flags[FLAG_INDEX_FROM_INDEX(page_index)] &= \
~FLAG_MASK_FROM_INDEX(page_index))
static void KernAux_PFA_mark(
2021-12-13 23:03:13 +00:00
KernAux_PFA pfa,
2020-12-06 10:16:15 +00:00
bool status,
size_t start,
size_t end
2021-12-14 22:10:28 +00:00
);
2021-12-13 23:03:13 +00:00
void KernAux_PFA_initialize(const KernAux_PFA pfa)
{
KERNAUX_ASSERT(pfa);
2021-12-15 10:45:40 +00:00
memset(pfa->flags, 0, sizeof(pfa->flags));
}
2021-12-13 23:10:05 +00:00
bool KernAux_PFA_is_available(const KernAux_PFA pfa, const size_t page_addr)
{
KERNAUX_ASSERT(pfa);
KERNAUX_ASSERT(page_addr % KERNAUX_PFA_PAGE_SIZE == 0);
2021-12-13 23:10:05 +00:00
2021-12-14 18:54:47 +00:00
return GET_FLAG_FROM_ADDR(pfa, page_addr);
2021-12-13 23:10:05 +00:00
}
void KernAux_PFA_mark_available(
2021-12-13 23:03:13 +00:00
const KernAux_PFA pfa,
const size_t start,
const size_t end
) {
2020-12-06 10:16:15 +00:00
KernAux_PFA_mark(pfa, true, start, end);
}
void KernAux_PFA_mark_unavailable(
2021-12-13 23:03:13 +00:00
const KernAux_PFA pfa,
const size_t start,
const size_t end
) {
2020-12-06 10:16:15 +00:00
KernAux_PFA_mark(pfa, false, start, end);
}
void KernAux_PFA_mark(
2021-12-13 23:03:13 +00:00
const KernAux_PFA pfa,
2020-12-06 10:16:15 +00:00
const bool status,
size_t start,
size_t end
) {
KERNAUX_ASSERT(pfa);
KERNAUX_ASSERT(start < end);
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) {
2021-12-14 18:41:11 +00:00
if (status) {
2021-12-14 19:01:23 +00:00
FLAG_TRUE_FROM_INDEX(pfa, index);
2021-12-14 18:41:11 +00:00
} else {
2021-12-14 19:01:23 +00:00
FLAG_FALSE_FROM_INDEX(pfa, index);
2021-12-14 18:41:11 +00:00
}
}
}
2020-11-30 23:38:55 +00:00
size_t KernAux_PFA_alloc_pages(const KernAux_PFA pfa, size_t mem_size)
{
KERNAUX_ASSERT(pfa);
2021-12-14 21:01:27 +00:00
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;
}
2021-12-14 01:21:47 +00:00
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;
2021-12-14 01:21:47 +00:00
for (size_t index = 1, start = 0;
index < KERNAUX_PFA_PAGES_COUNT_MAX;
++index)
{
2021-12-14 18:54:47 +00:00
if (!GET_FLAG_FROM_INDEX(pfa, index)) {
2021-12-14 01:21:47 +00:00
start = 0;
continue;
}
2021-12-14 01:21:47 +00:00
if (start == 0) start = index;
if (index - start + 1 == pages_count) {
for (; index >= start; --index) {
2021-12-14 19:01:23 +00:00
FLAG_FALSE_FROM_INDEX(pfa, index);
}
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
) {
KERNAUX_ASSERT(pfa);
KERNAUX_ASSERT(page_addr % KERNAUX_PFA_PAGE_SIZE == 0);
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) {
2021-12-14 19:01:23 +00:00
FLAG_TRUE_FROM_INDEX(pfa, start_index + index);
}
}