Rewrite memory map (#156)

This commit is contained in:
Alex Kotov 2022-12-22 20:01:54 +04:00 committed by GitHub
parent 46bd3f1c8e
commit b812b52a9c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
19 changed files with 597 additions and 458 deletions

View File

@ -94,6 +94,7 @@ jobs:
- without: 'ntoa'
dependencies: '--without-printf --without-units'
- without: 'printf'
- without: 'memmap'
steps:
- uses: actions/checkout@v2
- name: autogen

View File

@ -101,6 +101,11 @@ Use **cppcheck**.
* Name public (*defined in the headers*) methods with the prefix `KernAux_` and
with the prefix of the type name (example: `KernAux_FooBar_car_cdr`).
* Use postfix `size` for a byte size.
* Use postfix `slen` for C string length without terminating `\0` character
(size - 1).
* Use postfix `count` for a number of elements in an array.
* Create `typedef`s with the names of related `struct`s. Use this name with a
prefix `struct` to declare the data itself, withoth the prefix to declare
a pointer or an array:

View File

@ -1,3 +1,7 @@
2022-12-22 Alex Kotov <kotovalexarian@gmail.com>
* include/kernaux/memmap.h: Complete rewrite
2022-12-21 Alex Kotov <kotovalexarian@gmail.com>
* configure.ac: Rename feature "--(enable|disable)-debug" to

View File

@ -97,6 +97,7 @@ libkernaux_la_SOURCES += \
src/multiboot2/header_helpers.c \
src/multiboot2/header_is_valid.c \
src/multiboot2/header_print.c \
src/multiboot2/info_convert.c \
src/multiboot2/info_enums.c \
src/multiboot2/info_helpers.c \
src/multiboot2/info_is_valid.c \

View File

@ -69,7 +69,7 @@ zero). Work-in-progress APIs can change at any time.
* Utilities
* [Measurement units utils](/include/kernaux/units.h) (*work in progress*)
* [Example: To human](/examples/units_human.c)
* [Memory map](/include/kernaux/memmap.h) (*non-breaking since* **0.4.0**)
* [Memory map](/include/kernaux/memmap.h) (*non-breaking since* **?.?.?**)
* [Example](/examples/memmap.c)
* [printf format parser](/include/kernaux/printf_fmt.h) (*non-breaking since* **0.6.0**)
* [Example](/examples/printf_fmt.c)

View File

@ -1,45 +1,60 @@
#define KERNAUX_ACCESS_PROTECTED
#include <kernaux/free_list.h>
#include <kernaux/generic/display.h>
#include <kernaux/macro.h>
#include <kernaux/memmap.h>
#include <assert.h>
#include <stdbool.h>
#include <stddef.h>
#include <string.h>
#include <stdio.h>
#define SIZE_256MiB ( 256 * 1024 * 1024)
#define SIZE_512MiB ( 512 * 1024 * 1024)
#define SIZE_1GiB (1024 * 1024 * 1024)
static char malloc_memory[8192];
static void my_putc(void *const display KERNAUX_UNUSED, const char c)
{
putchar(c);
}
static void my_vprintf(
void *const display KERNAUX_UNUSED,
const char *const format,
va_list va
) {
vprintf(format, va);
}
static const struct KernAux_Display display = {
.putc = my_putc,
.vprintf = my_vprintf,
};
void example_main()
{
KernAux_MemMap memmap = { KernAux_MemMap_create(SIZE_1GiB) };
struct KernAux_FreeList malloc = KernAux_FreeList_create(NULL);
KernAux_FreeList_add_zone(&malloc, malloc_memory, sizeof(malloc_memory));
assert(KernAux_MemMap_add_entry(memmap, true, NULL, 0, SIZE_256MiB));
assert(KernAux_MemMap_add_entry(memmap, false, "foo", SIZE_256MiB, SIZE_256MiB));
assert(KernAux_MemMap_add_entry(memmap, true, "bar", SIZE_512MiB, SIZE_512MiB));
KernAux_Memmap_Builder memmap_builder =
KernAux_Memmap_Builder_new(&malloc.malloc);
assert(memmap_builder);
assert(KernAux_MemMap_finish(memmap));
assert(KernAux_Memmap_Builder_add(memmap_builder, NULL, 0x0, 654336, "available"));
assert(KernAux_Memmap_Builder_add(memmap_builder, NULL, 0x9fc00, 1024, "reserved"));
assert(KernAux_Memmap_Builder_add(memmap_builder, NULL, 0xf0000, 65536, "reserved"));
KernAux_Memmap_Node kernel_node =
KernAux_Memmap_Builder_add (memmap_builder, NULL, 0x100000, 133038080, "available");
assert(kernel_node);
assert(KernAux_Memmap_Builder_add(memmap_builder, NULL, 0x7fe0000, 131072, "reserved"));
assert(KernAux_Memmap_Builder_add(memmap_builder, NULL, 0xfffc0000, 262144, "reserved"));
// You can get the entry by it's index:
assert( KernAux_MemMap_entry_by_index(memmap, 0)->is_available == true);
assert(strcmp(KernAux_MemMap_entry_by_index(memmap, 0)->tag, "") == 0);
assert( KernAux_MemMap_entry_by_index(memmap, 0)->start == 0);
assert( KernAux_MemMap_entry_by_index(memmap, 0)->size == SIZE_256MiB);
assert( KernAux_MemMap_entry_by_index(memmap, 0)->end == SIZE_256MiB - 1);
assert( KernAux_MemMap_entry_by_index(memmap, 0)->limit == SIZE_256MiB);
assert(KernAux_Memmap_Builder_add(memmap_builder, kernel_node, 0x400000, 8192, "kernel code"));
assert(KernAux_Memmap_Builder_add(memmap_builder, kernel_node, 0x402000, 4096, "kernel data"));
// You can get the entry by it's start address:
assert( KernAux_MemMap_entry_by_start(memmap, SIZE_256MiB)->is_available == false);
assert(strcmp(KernAux_MemMap_entry_by_start(memmap, SIZE_256MiB)->tag, "foo") == 0);
assert( KernAux_MemMap_entry_by_start(memmap, SIZE_256MiB)->start == SIZE_256MiB);
assert( KernAux_MemMap_entry_by_start(memmap, SIZE_256MiB)->size == SIZE_256MiB);
assert( KernAux_MemMap_entry_by_start(memmap, SIZE_256MiB)->end == SIZE_512MiB - 1);
assert( KernAux_MemMap_entry_by_start(memmap, SIZE_256MiB)->limit == SIZE_512MiB);
KernAux_Memmap memmap =
KernAux_Memmap_Builder_finish_and_free(memmap_builder);
assert(memmap);
// You can get the entry by any address inside it:
assert( KernAux_MemMap_entry_by_addr(memmap, SIZE_512MiB )->is_available == true);
assert(strcmp(KernAux_MemMap_entry_by_addr(memmap, SIZE_512MiB + 1 )->tag, "bar") == 0);
assert( KernAux_MemMap_entry_by_addr(memmap, SIZE_512MiB + SIZE_256MiB)->start == SIZE_512MiB);
assert( KernAux_MemMap_entry_by_addr(memmap, SIZE_1GiB - 3 )->size == SIZE_512MiB);
assert( KernAux_MemMap_entry_by_addr(memmap, SIZE_1GiB - 2 )->end == SIZE_1GiB - 1);
assert( KernAux_MemMap_entry_by_addr(memmap, SIZE_1GiB - 1 )->limit == SIZE_1GiB);
KernAux_Memmap_print(memmap, &display);
KERNAUX_MEMMAP_FREE(memmap);
}

View File

@ -53,37 +53,37 @@ Multiboot 2 info tag {
[0]: {
u64 base_addr: 0x0
u64 length: 654336
u32 type: 1
u32 type: 1 (available)
u32 reserved: 0x0
}
[1]: {
u64 base_addr: 0x9fc00
u64 length: 1024
u32 type: 2
u32 type: 2 (reserved)
u32 reserved: 0x0
}
[2]: {
u64 base_addr: 0xf0000
u64 length: 65536
u32 type: 2
u32 type: 2 (reserved)
u32 reserved: 0x0
}
[3]: {
u64 base_addr: 0x100000
u64 length: 133038080
u32 type: 1
u32 type: 1 (available)
u32 reserved: 0x0
}
[4]: {
u64 base_addr: 0x7fe0000
u64 length: 131072
u32 type: 2
u32 type: 2 (reserved)
u32 reserved: 0x0
}
[5]: {
u64 base_addr: 0xfffc0000
u64 length: 262144
u32 type: 2
u32 type: 2 (reserved)
u32 reserved: 0x0
}
]

View File

@ -48,37 +48,37 @@ Multiboot 2 info tag {
[0]: {
u64 base_addr: 0x0
u64 length: 654336
u32 type: 1
u32 type: 1 (available)
u32 reserved: 0x0
}
[1]: {
u64 base_addr: 0x9fc00
u64 length: 1024
u32 type: 2
u32 type: 2 (reserved)
u32 reserved: 0x0
}
[2]: {
u64 base_addr: 0xf0000
u64 length: 65536
u32 type: 2
u32 type: 2 (reserved)
u32 reserved: 0x0
}
[3]: {
u64 base_addr: 0x100000
u64 length: 133038080
u32 type: 1
u32 type: 1 (available)
u32 reserved: 0x0
}
[4]: {
u64 base_addr: 0x7fe0000
u64 length: 131072
u32 type: 2
u32 type: 2 (reserved)
u32 reserved: 0x0
}
[5]: {
u64 base_addr: 0xfffc0000
u64 length: 262144
u32 type: 2
u32 type: 2 (reserved)
u32 reserved: 0x0
}
]

View File

@ -5,55 +5,60 @@
extern "C" {
#endif
#include <kernaux/generic/display.h>
#include <kernaux/generic/malloc.h>
#include <kernaux/macro.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#define KERNAUX_MEMMAP_ENTRIES_MAX 100
#define KERNAUX_MEMMAP_FREE(memmap) do { \
KernAux_Memmap_free(memmap); \
memmap = NULL; \
} while (0)
#define KERNAUX_MEMMAP_ENTRY_TAG_SLEN_MAX 24
#define KERNAUX_MEMMAP_ENTRY_TAG_SIZE_MAX (KERNAUX_MEMMAP_ENTRY_TAG_SLEN_MAX + 1)
/*********
* Types *
*********/
typedef const struct KernAux_MemMap_Entry {
bool is_available;
char tag[KERNAUX_MEMMAP_ENTRY_TAG_SIZE_MAX];
size_t start, size, end, limit;
} *KernAux_MemMap_Entry;
typedef const struct KernAux_Memmap_Node {
uint64_t mem_start, mem_end, mem_size;
const char *tag;
const struct KernAux_Memmap_Node *next, *children;
} *KernAux_Memmap_Node;
typedef struct KernAux_MemMap {
bool KERNAUX_PRIVATE_FIELD(is_finished);
size_t KERNAUX_PRIVATE_FIELD(memory_size);
size_t KERNAUX_PRIVATE_FIELD(entries_count);
struct KernAux_MemMap_Entry KERNAUX_PRIVATE_FIELD(entries)[KERNAUX_MEMMAP_ENTRIES_MAX];
} KernAux_MemMap[1];
typedef const struct KernAux_Memmap {
KernAux_Memmap_Node root_node;
struct KernAux_MemMap KernAux_MemMap_create(size_t memory_size);
void KernAux_MemMap_init(KernAux_MemMap memmap, size_t memory_size);
KernAux_Malloc KERNAUX_PRIVATE_FIELD(malloc);
} *KernAux_Memmap;
/// @warning Must only be called with NOT finished memmap, otherwise panics.
bool KernAux_MemMap_add_entry(
KernAux_MemMap memmap,
bool is_available,
const char *tag,
size_t start,
size_t size
typedef struct KernAux_Memmap_Builder {
KernAux_Memmap KERNAUX_PRIVATE_FIELD(memmap);
} *KernAux_Memmap_Builder;
/*************
* Functions *
*************/
KernAux_Memmap_Builder
KernAux_Memmap_Builder_new(KernAux_Malloc malloc);
KernAux_Memmap_Node
KernAux_Memmap_Builder_add(
KernAux_Memmap_Builder builder,
KernAux_Memmap_Node parent_node,
uint64_t mem_start,
uint64_t mem_size,
const char *tag
);
/// @warning Must only be called with NOT finished memmap, otherwise panics.
bool KernAux_MemMap_finish(KernAux_MemMap memmap);
KernAux_Memmap
KernAux_Memmap_Builder_finish_and_free(KernAux_Memmap_Builder builder);
/// @warning Must only be called with finished memmap, otherwise panics.
KernAux_MemMap_Entry
KernAux_MemMap_entry_by_index(KernAux_MemMap memmap, size_t index);
/// @warning Must only be called with finished memmap, otherwise panics.
KernAux_MemMap_Entry
KernAux_MemMap_entry_by_start(KernAux_MemMap memmap, size_t start);
/// @warning Must only be called with finished memmap, otherwise panics.
KernAux_MemMap_Entry
KernAux_MemMap_entry_by_addr(KernAux_MemMap memmap, size_t addr);
void KernAux_Memmap_free(KernAux_Memmap memmap);
void KernAux_Memmap_print(KernAux_Memmap memmap, KernAux_Display display);
#ifdef __cplusplus
}

View File

@ -5,8 +5,10 @@
extern "C" {
#endif
#include <kernaux/macro.h>
#include <kernaux/generic/display.h>
#include <kernaux/generic/malloc.h>
#include <kernaux/macro.h>
#include <kernaux/memmap.h>
#include <kernaux/multiboot2/header_macro.h>
#include <stdint.h>
@ -559,6 +561,15 @@ KERNAUX_STATIC_TEST_STRUCT_SIZE(
#include <kernaux/multiboot2/header_print.h>
#include <kernaux/multiboot2/info_print.h>
/*******************
* Other functions *
*******************/
KernAux_Memmap_Builder KernAux_Multiboot2_Info_to_memmap_builder(
const struct KernAux_Multiboot2_Info *multiboot2_info,
KernAux_Malloc malloc
);
#ifdef __cplusplus
}
#endif

View File

@ -32,7 +32,15 @@ extern "C" {
#define KERNAUX_MULTIBOOT2_ITAG_EFI_64BIT_IMAGE_HANDLE_PTR 20
#define KERNAUX_MULTIBOOT2_ITAG_IMAGE_LOAD_BASE_PHYS_ADDR 21
#define KERNAUX_MULTIBOOT2_MEMMAP_AVAILABLE 1
#define KERNAUX_MULTIBOOT2_MEMMAP_RESERVED 2
#define KERNAUX_MULTIBOOT2_MEMMAP_ACPI_RECLAIMABLE 3
#define KERNAUX_MULTIBOOT2_MEMMAP_NVS 4
#define KERNAUX_MULTIBOOT2_MEMMAP_BADRAM 5
const char *KernAux_Multiboot2_ITag_to_str(uint32_t tag_type);
const char*
KernAux_Multiboot2_ITag_MemoryMap_EntryBase_Type_to_str(uint32_t type);
#ifdef __cplusplus
}

View File

@ -4,6 +4,9 @@
#include "assert.h"
#include <kernaux/generic/display.h>
#include <kernaux/generic/malloc.h>
#include <kernaux/macro.h>
#include <kernaux/memmap.h>
#include <stdbool.h>
@ -11,144 +14,245 @@
#include <stdint.h>
#include <string.h>
#define MEMMAP (*memmap)
static void free_node(KernAux_Malloc malloc, struct KernAux_Memmap_Node *node);
static void print_nodes(
KernAux_Memmap_Node node,
KernAux_Display display,
unsigned indentation
);
struct KernAux_MemMap KernAux_MemMap_create(const size_t memory_size)
KernAux_Memmap_Builder
KernAux_Memmap_Builder_new(const KernAux_Malloc malloc)
{
struct KernAux_MemMap memmap;
KernAux_MemMap_init(&memmap, memory_size);
KERNAUX_NOTNULL(malloc);
struct KernAux_Memmap_Builder *const builder =
KernAux_Malloc_malloc(malloc, sizeof(*builder));
if (!builder) {
return NULL;
}
struct KernAux_Memmap *const memmap =
KernAux_Malloc_malloc(malloc, sizeof(*memmap));
if (!memmap) {
KernAux_Malloc_free(malloc, builder);
return NULL;
}
struct KernAux_Memmap_Node *const root_node =
KernAux_Malloc_malloc(malloc, sizeof(*root_node));
if (!root_node) {
KernAux_Malloc_free(malloc, memmap);
KernAux_Malloc_free(malloc, builder);
return NULL;
}
*root_node = (struct KernAux_Memmap_Node){
.mem_start = 0x0,
.mem_end = 0xffffffffffffffff, // 2**64 - 1
.mem_size = 0xffffffffffffffff, // 2**64 - 1
.tag = NULL,
.next = NULL,
.children = NULL,
};
*memmap = (struct KernAux_Memmap){
.malloc = malloc,
.root_node = root_node,
};
*builder = (struct KernAux_Memmap_Builder){
.memmap = memmap,
};
return builder;
}
KernAux_Memmap_Node KernAux_Memmap_Builder_add(
const KernAux_Memmap_Builder builder,
KernAux_Memmap_Node parent_node,
const uint64_t mem_start,
const uint64_t mem_size,
const char *tag
) {
KERNAUX_NOTNULL(builder);
KERNAUX_ASSERT(builder->memmap);
KERNAUX_ASSERT(builder->memmap->root_node);
KERNAUX_ASSERT(builder->memmap->malloc);
if (mem_size == 0) goto fail;
char *tag_copy = NULL;
if (tag) {
tag_copy =
KernAux_Malloc_malloc(builder->memmap->malloc, strlen(tag) + 1);
if (!tag_copy) goto fail;
strcpy(tag_copy, tag);
}
struct KernAux_Memmap_Node *const new_node =
KernAux_Malloc_malloc(builder->memmap->malloc, sizeof(*new_node));
if (!new_node) goto fail_after_tag;
new_node->mem_start = mem_start;
new_node->mem_size = mem_size;
new_node->mem_end = mem_start + mem_size - 1;
new_node->tag = tag_copy;
if (!parent_node) {
parent_node = (struct KernAux_Memmap_Node*)builder->memmap->root_node;
}
if (new_node->mem_start < parent_node->mem_start ||
new_node->mem_end > parent_node->mem_end)
{
goto fail_after_new_node;
}
if (parent_node->children) {
for (
struct KernAux_Memmap_Node *curr_node =
(struct KernAux_Memmap_Node*)parent_node->children;
curr_node;
curr_node = (struct KernAux_Memmap_Node*)curr_node->next
) {
if (!curr_node->next ||
curr_node->next->mem_start > new_node->mem_start)
{
if (new_node->next &&
new_node->mem_end >= new_node->next->mem_start)
{
goto fail_after_new_node;
}
new_node->next = curr_node->next;
curr_node->next = new_node;
break;
}
}
} else {
new_node->next = NULL;
((struct KernAux_Memmap_Node*)parent_node)->children = new_node;
}
return new_node;
fail_after_new_node:
KernAux_Malloc_free(builder->memmap->malloc, new_node);
fail_after_tag:
if (tag_copy) KernAux_Malloc_free(builder->memmap->malloc, tag_copy);
fail:
return NULL;
}
KernAux_Memmap
KernAux_Memmap_Builder_finish_and_free(const KernAux_Memmap_Builder builder)
{
KERNAUX_NOTNULL(builder);
KERNAUX_ASSERT(builder->memmap);
KERNAUX_ASSERT(builder->memmap->root_node);
KERNAUX_ASSERT(builder->memmap->malloc);
KernAux_Memmap memmap = builder->memmap;
builder->memmap = NULL;
KernAux_Malloc_free(memmap->malloc, builder);
return memmap;
}
void KernAux_MemMap_init(KernAux_MemMap memmap, const size_t memory_size)
void KernAux_Memmap_free(const KernAux_Memmap memmap)
{
MEMMAP.is_finished = false;
MEMMAP.memory_size = memory_size;
MEMMAP.entries_count = 0;
memset(MEMMAP.entries, 0, sizeof(MEMMAP.entries));
KERNAUX_NOTNULL(memmap);
KERNAUX_ASSERT(memmap->root_node);
KERNAUX_ASSERT(memmap->malloc);
KERNAUX_ASSERT(memmap->root_node->next == NULL);
free_node(memmap->malloc, (struct KernAux_Memmap_Node*)memmap->root_node);
KernAux_Malloc malloc = memmap->malloc;
((struct KernAux_Memmap*)memmap)->root_node = NULL;
((struct KernAux_Memmap*)memmap)->malloc = NULL;
KernAux_Malloc_free(malloc, (void*)memmap);
}
bool KernAux_MemMap_add_entry(
KernAux_MemMap memmap,
const bool is_available,
const char *const tag,
const size_t start,
const size_t size
void KernAux_Memmap_print(
const KernAux_Memmap memmap,
const KernAux_Display display
) {
if (MEMMAP.is_finished) {
KERNAUX_PANIC("memmap is finished");
return false;
}
KERNAUX_NOTNULL(memmap);
KERNAUX_ASSERT(memmap->root_node);
KERNAUX_ASSERT(memmap->malloc);
KERNAUX_ASSERT(memmap->root_node->next == NULL);
if (MEMMAP.entries_count >= KERNAUX_MEMMAP_ENTRIES_MAX) return false;
if (SIZE_MAX - start < size) return false;
if (size == 0) return false;
const size_t index = MEMMAP.entries_count++;
memset(&MEMMAP.entries[index], 0, sizeof(MEMMAP.entries[index]));
MEMMAP.entries[index].is_available = is_available;
MEMMAP.entries[index].start = start;
MEMMAP.entries[index].size = size;
MEMMAP.entries[index].end = start + size - 1;
MEMMAP.entries[index].limit = start + size;
if (tag) {
strncpy(
MEMMAP.entries[index].tag,
tag,
KERNAUX_MEMMAP_ENTRY_TAG_SLEN_MAX
);
}
return true;
print_nodes(memmap->root_node, display, 0);
}
bool KernAux_MemMap_finish(KernAux_MemMap memmap)
{
if (MEMMAP.is_finished) {
KERNAUX_PANIC("memmap is finished");
return false;
void free_node(
const KernAux_Malloc malloc,
struct KernAux_Memmap_Node *const node
) {
KERNAUX_NOTNULL(malloc);
KERNAUX_NOTNULL(node);
for (
struct KernAux_Memmap_Node *child_node =
(struct KernAux_Memmap_Node*)node->children;
child_node;
child_node = (struct KernAux_Memmap_Node*)child_node->next
) {
free_node(malloc, child_node);
}
if ((MEMMAP.entries_count == 0 && MEMMAP.memory_size != 0) ||
MEMMAP.entries_count > KERNAUX_MEMMAP_ENTRIES_MAX ||
MEMMAP.entries[0].start != 0 ||
MEMMAP.entries[MEMMAP.entries_count - 1].limit != MEMMAP.memory_size)
{
return false;
}
if (node->tag) KernAux_Malloc_free(malloc, (void*)node->tag);
KernAux_Malloc_free(malloc, node);
}
// At first, let's validate the individual entries.
for (size_t index = 0; index < MEMMAP.entries_count; ++index) {
if (SIZE_MAX - MEMMAP.entries[index].start <
MEMMAP.entries[index].size
||
MEMMAP.entries[index].end !=
MEMMAP.entries[index].start + MEMMAP.entries[index].size - 1
||
MEMMAP.entries[index].limit !=
MEMMAP.entries[index].start + MEMMAP.entries[index].size)
{
return false;
#define PRINT(s) do { KernAux_Display_print (display, s); } while (0)
#define PRINTLN(s) do { KernAux_Display_println(display, s); } while (0)
#define PRINTLNF(format, ...) \
do { KernAux_Display_printlnf(display, format, __VA_ARGS__); } while (0)
#define INDENT do { \
for (unsigned index = 0; index < indentation; ++index) PRINT(" "); \
} while (0)
void print_nodes(
KernAux_Memmap_Node node,
const KernAux_Display display,
const unsigned indentation
) {
for (; node; node = node->next) {
INDENT;
PRINTLN("{");
KERNAUX_CAST_CONST(unsigned long long, mem_start, node->mem_start);
KERNAUX_CAST_CONST(unsigned long long, mem_size, node->mem_size);
KERNAUX_CAST_CONST(unsigned long long, mem_end, node->mem_end);
INDENT;
PRINTLNF(" u64 mem_start: 0x%llx", mem_start);
INDENT;
PRINTLNF(" u64 mem_size: %llu", mem_size);
INDENT;
PRINTLNF(" u64 mem_end: 0x%llx", mem_end);
INDENT;
if (node->tag) {
PRINTLNF(" char* tag: \"%s\"", node->tag);
} else {
PRINTLN(" char* tag: NULL");
}
}
// TODO: Next, let's sort the entries.
// Finally, let's validate that the entries fit each other properly.
for (size_t index = 1; index < MEMMAP.entries_count; ++index) {
if (MEMMAP.entries[index - 1].limit != MEMMAP.entries[index].start) {
return false;
if (node->children) {
INDENT;
PRINTLN(" struct* children: [");
print_nodes(node->children, display, indentation + 2);
INDENT;
PRINTLN(" ]");
} else {
INDENT;
PRINTLN(" struct* children: []");
}
}
return MEMMAP.is_finished = true;
}
KernAux_MemMap_Entry
KernAux_MemMap_entry_by_index(KernAux_MemMap memmap, const size_t index)
{
if (!MEMMAP.is_finished) {
KERNAUX_PANIC("memmap is not finished");
return NULL;
}
if (index >= MEMMAP.entries_count) return NULL;
return &MEMMAP.entries[index];
}
KernAux_MemMap_Entry
KernAux_MemMap_entry_by_start(KernAux_MemMap memmap, const size_t start)
{
if (!MEMMAP.is_finished) {
KERNAUX_PANIC("memmap is not finished");
return NULL;
}
for (size_t index = 0; index < MEMMAP.entries_count; ++index) {
if (MEMMAP.entries[index].start == start) return &MEMMAP.entries[index];
}
return NULL;
}
KernAux_MemMap_Entry
KernAux_MemMap_entry_by_addr(KernAux_MemMap memmap, const size_t addr)
{
if (!MEMMAP.is_finished) {
KERNAUX_PANIC("memmap is not finished");
return NULL;
}
for (size_t index = 0; index < MEMMAP.entries_count; ++index) {
if (addr >= MEMMAP.entries[index].start &&
addr <= MEMMAP.entries[index].end)
{
return &MEMMAP.entries[index];
}
}
return NULL;
INDENT;
PRINTLN("}");
}
}

View File

@ -0,0 +1,71 @@
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "../assert.h"
#include <kernaux/generic/malloc.h>
#include <kernaux/macro.h>
#include <kernaux/memmap.h>
#include <kernaux/multiboot2.h>
#include <stddef.h>
#ifdef WITH_MEMMAP
KernAux_Memmap_Builder KernAux_Multiboot2_Info_to_memmap_builder(
const struct KernAux_Multiboot2_Info *const multiboot2_info,
const KernAux_Malloc malloc
) {
KERNAUX_NOTNULL(multiboot2_info);
KERNAUX_NOTNULL(malloc);
if (!KernAux_Multiboot2_Info_is_valid(multiboot2_info)) return NULL;
const struct KernAux_Multiboot2_ITag_MemoryMap *const memory_map_tag =
(const struct KernAux_Multiboot2_ITag_MemoryMap*)
KernAux_Multiboot2_Info_first_tag_with_type(
multiboot2_info,
KERNAUX_MULTIBOOT2_ITAG_MEMORY_MAP
);
if (!memory_map_tag) return NULL;
const void *const data = KERNAUX_MULTIBOOT2_DATA(memory_map_tag);
size_t data_size = memory_map_tag->base.size - sizeof(*memory_map_tag);
const void *const data_end = ((const char*)data) + data_size;
if (memory_map_tag->entry_size <
sizeof(struct KernAux_Multiboot2_ITag_MemoryMap_EntryBase))
{
return NULL;
}
KernAux_Memmap_Builder builder =
KernAux_Memmap_Builder_new(malloc);
if (!builder) return NULL;
for (
const struct KernAux_Multiboot2_ITag_MemoryMap_EntryBase *entry = data;
(const char*)entry < (const char*)data_end;
entry =
(const struct KernAux_Multiboot2_ITag_MemoryMap_EntryBase*)
(((const char*)entry) + memory_map_tag->entry_size)
) {
const void *const node = KernAux_Memmap_Builder_add(
builder,
NULL,
entry->base_addr,
entry->length,
KernAux_Multiboot2_ITag_MemoryMap_EntryBase_Type_to_str(
entry->type
)
);
if (!node) {
KernAux_Memmap_Builder_finish_and_free(builder);
return NULL;
}
}
return builder;
}
#endif

View File

@ -58,3 +58,22 @@ const char *KernAux_Multiboot2_ITag_to_str(const uint32_t tag_type)
return NULL;
}
}
const char*
KernAux_Multiboot2_ITag_MemoryMap_EntryBase_Type_to_str(const uint32_t type)
{
switch (type) {
case KERNAUX_MULTIBOOT2_MEMMAP_AVAILABLE:
return "available";
case KERNAUX_MULTIBOOT2_MEMMAP_RESERVED:
return "reserved";
case KERNAUX_MULTIBOOT2_MEMMAP_ACPI_RECLAIMABLE:
return "ACPI reclaimable";
case KERNAUX_MULTIBOOT2_MEMMAP_NVS:
return "ACPI Non-Volatile Storage";
case KERNAUX_MULTIBOOT2_MEMMAP_BADRAM:
return "bad RAM";
default:
return NULL;
}
}

View File

@ -378,7 +378,12 @@ void KernAux_Multiboot2_ITag_MemoryMap_print(
PRINTLNF(" [%zu]: {", index);
PRINTLNF(" u64 base_addr: 0x%llx", base_addr);
PRINTLNF(" u64 length: %llu", length);
PRINTLNF(" u32 type: %lu", type);
PRINTLNF(" u32 type: %lu (%s)",
type,
KernAux_Multiboot2_ITag_MemoryMap_EntryBase_Type_to_str(
entries[index].type
)
);
PRINTLNF(" u32 reserved: 0x%lx", reserved);
PRINTLN (" }");
}

2
tests/.gitignore vendored
View File

@ -11,12 +11,12 @@
/test_elf
/test_free_list
/test_mbr
/test_memmap
/test_multiboot2_common_packing
/test_multiboot2_header_helpers
/test_multiboot2_header_print
/test_multiboot2_header_print.c
/test_multiboot2_header_validation
/test_multiboot2_info_convert_memmap
/test_multiboot2_info_helpers
/test_multiboot2_info_print
/test_multiboot2_info_print.c

View File

@ -168,18 +168,6 @@ test_mbr_SOURCES = \
test_mbr.c
endif
###############
# test_memmap #
###############
if WITH_MEMMAP
TESTS += test_memmap
test_memmap_LDADD = $(top_builddir)/libkernaux.la
test_memmap_SOURCES = \
main.c \
test_memmap.c
endif
##################################
# test_multiboot2_common_packing #
##################################
@ -241,6 +229,22 @@ test_multiboot2_header_validation_SOURCES = \
../fixtures/multiboot2_header_example2.h
endif
#######################################
# test_multiboot2_info_convert_memmap #
#######################################
if WITH_MULTIBOOT2
if WITH_MEMMAP
TESTS += test_multiboot2_info_convert_memmap
test_multiboot2_info_convert_memmap_LDADD = $(top_builddir)/libkernaux.la
test_multiboot2_info_convert_memmap_SOURCES = \
main.c \
test_multiboot2_info_convert_memmap.c \
../fixtures/multiboot2_header_example2.h \
../fixtures/multiboot2_info_example2.h
endif
endif
################################
# test_multiboot2_info_helpers #
################################

View File

@ -1,242 +0,0 @@
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#define KERNAUX_ACCESS_PRIVATE
#include <kernaux/macro.h>
#include <kernaux/memmap.h>
#include <kernaux/runtime.h>
#include <assert.h>
#include <setjmp.h>
#include <stdbool.h>
#include <stddef.h>
#include <string.h>
static KernAux_MemMap memmap;
static jmp_buf jmpbuf;
static unsigned int assert_count_exp = 0;
static unsigned int assert_count_ctr = 0;
static const char *assert_last_file = NULL;
static void assert_cb(
const char *const file,
const int line KERNAUX_UNUSED,
const char *const msg KERNAUX_UNUSED
) {
++assert_count_ctr;
assert_last_file = file;
longjmp(jmpbuf, 1);
}
static void before_assert()
{
assert(assert_count_ctr == assert_count_exp);
}
static void expect_assert()
{
#ifdef ENABLE_ASSERT
// cppcheck-suppress assignmentInAssert
assert(assert_count_ctr == ++assert_count_exp);
assert(strstr(assert_last_file, "src/memmap.c") != NULL);
assert_last_file = NULL;
#else
assert(assert_count_ctr == 0);
assert(assert_last_file == NULL);
#endif
}
#define MEMSET memset(memmap, 0xff, sizeof(memmap))
#define MEMMAP (*memmap)
void test_main()
{
assert(setjmp(jmpbuf) == 0);
kernaux_assert_cb = assert_cb;
{
MEMSET;
KernAux_MemMap_init(memmap, 0);
assert(MEMMAP.is_finished == false);
assert(MEMMAP.memory_size == 0);
assert(MEMMAP.entries_count == 0);
assert(KernAux_MemMap_finish(memmap));
assert(MEMMAP.is_finished);
assert(MEMMAP.memory_size == 0);
assert(MEMMAP.entries_count == 0);
assert(KernAux_MemMap_entry_by_index(memmap, 0) == NULL);
before_assert();
if (setjmp(jmpbuf) == 0) {
assert(!KernAux_MemMap_finish(memmap));
}
expect_assert();
}
{
MEMSET;
KernAux_MemMap_init(memmap, 0);
assert(MEMMAP.is_finished == false);
assert(MEMMAP.memory_size == 0);
assert(MEMMAP.entries_count == 0);
assert(!KernAux_MemMap_add_entry(memmap, false, NULL, 0, 0));
assert(MEMMAP.is_finished == false);
assert(MEMMAP.memory_size == 0);
assert(MEMMAP.entries_count == 0);
assert(KernAux_MemMap_finish(memmap));
assert(MEMMAP.is_finished);
assert(MEMMAP.memory_size == 0);
assert(MEMMAP.entries_count == 0);
assert(KernAux_MemMap_entry_by_index(memmap, 0) == NULL);
}
{
MEMSET;
KernAux_MemMap_init(memmap, 1);
assert(MEMMAP.is_finished == false);
assert(MEMMAP.memory_size == 1);
assert(MEMMAP.entries_count == 0);
assert(KernAux_MemMap_add_entry(memmap, false, NULL, 0, 1));
assert(MEMMAP.is_finished == false);
assert(MEMMAP.memory_size == 1);
assert(MEMMAP.entries_count == 1);
assert(KernAux_MemMap_finish(memmap));
assert(MEMMAP.is_finished);
assert(MEMMAP.memory_size == 1);
assert(MEMMAP.entries_count == 1);
assert(MEMMAP.entries[0].is_available == false);
assert(MEMMAP.entries[0].tag[0] == '\0');
assert(MEMMAP.entries[0].start == 0);
assert(MEMMAP.entries[0].size == 1);
assert(MEMMAP.entries[0].end == 0);
assert(MEMMAP.entries[0].limit == 1);
assert(KernAux_MemMap_entry_by_index(memmap, 0) == &MEMMAP.entries[0]);
}
{
MEMSET;
KernAux_MemMap_init(memmap, 2);
assert(MEMMAP.is_finished == false);
assert(MEMMAP.memory_size == 2);
assert(MEMMAP.entries_count == 0);
assert(KernAux_MemMap_add_entry(memmap, false, NULL, 0, 2));
assert(MEMMAP.is_finished == false);
assert(MEMMAP.memory_size == 2);
assert(MEMMAP.entries_count == 1);
assert(KernAux_MemMap_finish(memmap));
assert(MEMMAP.is_finished);
assert(MEMMAP.memory_size == 2);
assert(MEMMAP.entries_count == 1);
assert(MEMMAP.entries[0].is_available == false);
assert(MEMMAP.entries[0].tag[0] == '\0');
assert(MEMMAP.entries[0].start == 0);
assert(MEMMAP.entries[0].size == 2);
assert(MEMMAP.entries[0].end == 1);
assert(MEMMAP.entries[0].limit == 2);
assert(KernAux_MemMap_entry_by_index(memmap, 0) == &MEMMAP.entries[0]);
}
{
MEMSET;
KernAux_MemMap_init(memmap, 1);
assert(MEMMAP.is_finished == false);
assert(MEMMAP.memory_size == 1);
assert(MEMMAP.entries_count == 0);
assert(KernAux_MemMap_add_entry(memmap, false, NULL, 0, 2));
assert(MEMMAP.is_finished == false);
assert(MEMMAP.memory_size == 1);
assert(MEMMAP.entries_count == 1);
assert(!KernAux_MemMap_finish(memmap));
assert(MEMMAP.is_finished == false);
assert(MEMMAP.memory_size == 1);
assert(MEMMAP.entries_count == 1);
assert(MEMMAP.entries[0].is_available == false);
assert(MEMMAP.entries[0].tag[0] == '\0');
assert(MEMMAP.entries[0].start == 0);
assert(MEMMAP.entries[0].size == 2);
assert(MEMMAP.entries[0].end == 1);
assert(MEMMAP.entries[0].limit == 2);
before_assert();
if (setjmp(jmpbuf) == 0) {
assert(KernAux_MemMap_entry_by_index(memmap, 0) == NULL);
}
expect_assert();
}
{
MEMSET;
KernAux_MemMap_init(memmap, 2);
assert(MEMMAP.is_finished == false);
assert(MEMMAP.memory_size == 2);
assert(MEMMAP.entries_count == 0);
assert(KernAux_MemMap_add_entry(memmap, false, NULL, 0, 1));
assert(MEMMAP.is_finished == false);
assert(MEMMAP.memory_size == 2);
assert(MEMMAP.entries_count == 1);
assert(KernAux_MemMap_add_entry(memmap, false, NULL, 1, 1));
assert(MEMMAP.is_finished == false);
assert(MEMMAP.memory_size == 2);
assert(MEMMAP.entries_count == 2);
assert(KernAux_MemMap_finish(memmap));
assert(MEMMAP.is_finished);
assert(MEMMAP.memory_size == 2);
assert(MEMMAP.entries_count == 2);
assert(MEMMAP.entries[0].is_available == false);
assert(MEMMAP.entries[0].tag[0] == '\0');
assert(MEMMAP.entries[0].start == 0);
assert(MEMMAP.entries[0].size == 1);
assert(MEMMAP.entries[0].end == 0);
assert(MEMMAP.entries[0].limit == 1);
assert(MEMMAP.entries[1].is_available == false);
assert(MEMMAP.entries[1].tag[0] == '\0');
assert(MEMMAP.entries[1].start == 1);
assert(MEMMAP.entries[1].size == 1);
assert(MEMMAP.entries[1].end == 1);
assert(MEMMAP.entries[1].limit == 2);
assert(KernAux_MemMap_entry_by_index(memmap, 0) == &MEMMAP.entries[0]);
assert(KernAux_MemMap_entry_by_index(memmap, 1) == &MEMMAP.entries[1]);
}
assert(assert_count_ctr == assert_count_exp);
}

View File

@ -0,0 +1,128 @@
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <kernaux/free_list.h>
#include <kernaux/memmap.h>
#include <kernaux/multiboot2.h>
#include <assert.h>
#include <stddef.h>
#include <string.h>
#include "../fixtures/multiboot2_info_example0.h"
#include "../fixtures/multiboot2_info_example1.h"
#include "../fixtures/multiboot2_info_example2.h"
static char buffer[4096];
static void test_examples_1_and_2(KernAux_Memmap_Node node);
void test_main()
{
struct KernAux_FreeList malloc = KernAux_FreeList_create(NULL);
KernAux_FreeList_add_zone(&malloc, buffer, sizeof(buffer));
{
const KernAux_Memmap_Builder builder =
KernAux_Multiboot2_Info_to_memmap_builder(
&multiboot2_info_example0.multiboot2_info,
&malloc.malloc
);
assert(builder == NULL);
}
{
const KernAux_Memmap_Builder builder =
KernAux_Multiboot2_Info_to_memmap_builder(
(const struct KernAux_Multiboot2_Info*)
&multiboot2_info_example1,
&malloc.malloc
);
assert(builder);
const KernAux_Memmap memmap =
KernAux_Memmap_Builder_finish_and_free(builder);
assert(memmap);
test_examples_1_and_2(memmap->root_node);
KernAux_Memmap_free(memmap);
}
{
const KernAux_Memmap_Builder builder =
KernAux_Multiboot2_Info_to_memmap_builder(
&multiboot2_info_example2.multiboot2_info,
&malloc.malloc
);
assert(builder);
const KernAux_Memmap memmap =
KernAux_Memmap_Builder_finish_and_free(builder);
assert(memmap);
test_examples_1_and_2(memmap->root_node);
KernAux_Memmap_free(memmap);
}
}
void test_examples_1_and_2(KernAux_Memmap_Node node)
{
assert(node);
assert(node->mem_start == 0x0);
assert(node->mem_size == 0xffffffffffffffff);
assert(node->mem_end == 0xffffffffffffffff);
assert(node->tag == NULL);
assert(node->next == NULL);
node = node->children;
assert(node);
assert(node->mem_start == 0x0);
assert(node->mem_size == 654336);
assert(node->mem_end == 0x9fbff);
assert(strcmp(node->tag, "available") == 0);
assert(node->children == NULL);
node = node->next;
assert(node);
assert(node->mem_start == 0x9fc00);
assert(node->mem_size == 1024);
assert(node->mem_end == 0x9ffff);
assert(strcmp(node->tag, "reserved") == 0);
assert(node->children == NULL);
node = node->next;
assert(node);
assert(node->mem_start == 0xf0000);
assert(node->mem_size == 65536);
assert(node->mem_end == 0xfffff);
assert(strcmp(node->tag, "reserved") == 0);
assert(node->children == NULL);
node = node->next;
assert(node);
assert(node->mem_start == 0x100000);
assert(node->mem_size == 133038080);
assert(node->mem_end == 0x7fdffff);
assert(strcmp(node->tag, "available") == 0);
assert(node->children == NULL);
node = node->next;
assert(node);
assert(node->mem_start == 0x7fe0000);
assert(node->mem_size == 131072);
assert(node->mem_end == 0x7ffffff);
assert(strcmp(node->tag, "reserved") == 0);
assert(node->children == NULL);
node = node->next;
assert(node);
assert(node->mem_start == 0xfffc0000);
assert(node->mem_size == 262144);
assert(node->mem_end == 0xffffffff);
assert(strcmp(node->tag, "reserved") == 0);
assert(node->children == NULL);
node = node->next;
assert(node == NULL);
}