mirror of
https://github.com/tailix/libkernaux.git
synced 2024-11-20 11:06:41 -05:00
Rewrite memory map (#156)
This commit is contained in:
parent
46bd3f1c8e
commit
b812b52a9c
19 changed files with 597 additions and 458 deletions
1
.github/workflows/main.yml
vendored
1
.github/workflows/main.yml
vendored
|
@ -94,6 +94,7 @@ jobs:
|
|||
- without: 'ntoa'
|
||||
dependencies: '--without-printf --without-units'
|
||||
- without: 'printf'
|
||||
- without: 'memmap'
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: autogen
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 \
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
]
|
||||
|
|
|
@ -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
|
||||
}
|
||||
]
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
346
src/memmap.c
346
src/memmap.c
|
@ -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("}");
|
||||
}
|
||||
}
|
||||
|
|
71
src/multiboot2/info_convert.c
Normal file
71
src/multiboot2/info_convert.c
Normal 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
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
2
tests/.gitignore
vendored
|
@ -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
|
||||
|
|
|
@ -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 #
|
||||
################################
|
||||
|
|
|
@ -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);
|
||||
}
|
128
tests/test_multiboot2_info_convert_memmap.c
Normal file
128
tests/test_multiboot2_info_convert_memmap.c
Normal 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);
|
||||
}
|
Loading…
Reference in a new issue