mirror of https://github.com/tailix/libkernaux.git
Rewrite memory map (#156)
This commit is contained in:
parent
46bd3f1c8e
commit
b812b52a9c
|
@ -94,6 +94,7 @@ jobs:
|
||||||
- without: 'ntoa'
|
- without: 'ntoa'
|
||||||
dependencies: '--without-printf --without-units'
|
dependencies: '--without-printf --without-units'
|
||||||
- without: 'printf'
|
- without: 'printf'
|
||||||
|
- without: 'memmap'
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v2
|
||||||
- name: autogen
|
- name: autogen
|
||||||
|
|
|
@ -101,6 +101,11 @@ Use **cppcheck**.
|
||||||
* Name public (*defined in the headers*) methods with the prefix `KernAux_` and
|
* Name public (*defined in the headers*) methods with the prefix `KernAux_` and
|
||||||
with the prefix of the type name (example: `KernAux_FooBar_car_cdr`).
|
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
|
* 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
|
prefix `struct` to declare the data itself, withoth the prefix to declare
|
||||||
a pointer or an array:
|
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>
|
2022-12-21 Alex Kotov <kotovalexarian@gmail.com>
|
||||||
|
|
||||||
* configure.ac: Rename feature "--(enable|disable)-debug" to
|
* configure.ac: Rename feature "--(enable|disable)-debug" to
|
||||||
|
|
|
@ -97,6 +97,7 @@ libkernaux_la_SOURCES += \
|
||||||
src/multiboot2/header_helpers.c \
|
src/multiboot2/header_helpers.c \
|
||||||
src/multiboot2/header_is_valid.c \
|
src/multiboot2/header_is_valid.c \
|
||||||
src/multiboot2/header_print.c \
|
src/multiboot2/header_print.c \
|
||||||
|
src/multiboot2/info_convert.c \
|
||||||
src/multiboot2/info_enums.c \
|
src/multiboot2/info_enums.c \
|
||||||
src/multiboot2/info_helpers.c \
|
src/multiboot2/info_helpers.c \
|
||||||
src/multiboot2/info_is_valid.c \
|
src/multiboot2/info_is_valid.c \
|
||||||
|
|
|
@ -69,7 +69,7 @@ zero). Work-in-progress APIs can change at any time.
|
||||||
* Utilities
|
* Utilities
|
||||||
* [Measurement units utils](/include/kernaux/units.h) (*work in progress*)
|
* [Measurement units utils](/include/kernaux/units.h) (*work in progress*)
|
||||||
* [Example: To human](/examples/units_human.c)
|
* [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)
|
* [Example](/examples/memmap.c)
|
||||||
* [printf format parser](/include/kernaux/printf_fmt.h) (*non-breaking since* **0.6.0**)
|
* [printf format parser](/include/kernaux/printf_fmt.h) (*non-breaking since* **0.6.0**)
|
||||||
* [Example](/examples/printf_fmt.c)
|
* [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 <kernaux/memmap.h>
|
||||||
|
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <stdbool.h>
|
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <string.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
#define SIZE_256MiB ( 256 * 1024 * 1024)
|
static char malloc_memory[8192];
|
||||||
#define SIZE_512MiB ( 512 * 1024 * 1024)
|
|
||||||
#define SIZE_1GiB (1024 * 1024 * 1024)
|
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()
|
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));
|
KernAux_Memmap_Builder memmap_builder =
|
||||||
assert(KernAux_MemMap_add_entry(memmap, false, "foo", SIZE_256MiB, SIZE_256MiB));
|
KernAux_Memmap_Builder_new(&malloc.malloc);
|
||||||
assert(KernAux_MemMap_add_entry(memmap, true, "bar", SIZE_512MiB, SIZE_512MiB));
|
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_Builder_add(memmap_builder, kernel_node, 0x400000, 8192, "kernel code"));
|
||||||
assert( KernAux_MemMap_entry_by_index(memmap, 0)->is_available == true);
|
assert(KernAux_Memmap_Builder_add(memmap_builder, kernel_node, 0x402000, 4096, "kernel data"));
|
||||||
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);
|
|
||||||
|
|
||||||
// You can get the entry by it's start address:
|
KernAux_Memmap memmap =
|
||||||
assert( KernAux_MemMap_entry_by_start(memmap, SIZE_256MiB)->is_available == false);
|
KernAux_Memmap_Builder_finish_and_free(memmap_builder);
|
||||||
assert(strcmp(KernAux_MemMap_entry_by_start(memmap, SIZE_256MiB)->tag, "foo") == 0);
|
assert(memmap);
|
||||||
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);
|
|
||||||
|
|
||||||
// You can get the entry by any address inside it:
|
KernAux_Memmap_print(memmap, &display);
|
||||||
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);
|
KERNAUX_MEMMAP_FREE(memmap);
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -53,37 +53,37 @@ Multiboot 2 info tag {
|
||||||
[0]: {
|
[0]: {
|
||||||
u64 base_addr: 0x0
|
u64 base_addr: 0x0
|
||||||
u64 length: 654336
|
u64 length: 654336
|
||||||
u32 type: 1
|
u32 type: 1 (available)
|
||||||
u32 reserved: 0x0
|
u32 reserved: 0x0
|
||||||
}
|
}
|
||||||
[1]: {
|
[1]: {
|
||||||
u64 base_addr: 0x9fc00
|
u64 base_addr: 0x9fc00
|
||||||
u64 length: 1024
|
u64 length: 1024
|
||||||
u32 type: 2
|
u32 type: 2 (reserved)
|
||||||
u32 reserved: 0x0
|
u32 reserved: 0x0
|
||||||
}
|
}
|
||||||
[2]: {
|
[2]: {
|
||||||
u64 base_addr: 0xf0000
|
u64 base_addr: 0xf0000
|
||||||
u64 length: 65536
|
u64 length: 65536
|
||||||
u32 type: 2
|
u32 type: 2 (reserved)
|
||||||
u32 reserved: 0x0
|
u32 reserved: 0x0
|
||||||
}
|
}
|
||||||
[3]: {
|
[3]: {
|
||||||
u64 base_addr: 0x100000
|
u64 base_addr: 0x100000
|
||||||
u64 length: 133038080
|
u64 length: 133038080
|
||||||
u32 type: 1
|
u32 type: 1 (available)
|
||||||
u32 reserved: 0x0
|
u32 reserved: 0x0
|
||||||
}
|
}
|
||||||
[4]: {
|
[4]: {
|
||||||
u64 base_addr: 0x7fe0000
|
u64 base_addr: 0x7fe0000
|
||||||
u64 length: 131072
|
u64 length: 131072
|
||||||
u32 type: 2
|
u32 type: 2 (reserved)
|
||||||
u32 reserved: 0x0
|
u32 reserved: 0x0
|
||||||
}
|
}
|
||||||
[5]: {
|
[5]: {
|
||||||
u64 base_addr: 0xfffc0000
|
u64 base_addr: 0xfffc0000
|
||||||
u64 length: 262144
|
u64 length: 262144
|
||||||
u32 type: 2
|
u32 type: 2 (reserved)
|
||||||
u32 reserved: 0x0
|
u32 reserved: 0x0
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
|
@ -48,37 +48,37 @@ Multiboot 2 info tag {
|
||||||
[0]: {
|
[0]: {
|
||||||
u64 base_addr: 0x0
|
u64 base_addr: 0x0
|
||||||
u64 length: 654336
|
u64 length: 654336
|
||||||
u32 type: 1
|
u32 type: 1 (available)
|
||||||
u32 reserved: 0x0
|
u32 reserved: 0x0
|
||||||
}
|
}
|
||||||
[1]: {
|
[1]: {
|
||||||
u64 base_addr: 0x9fc00
|
u64 base_addr: 0x9fc00
|
||||||
u64 length: 1024
|
u64 length: 1024
|
||||||
u32 type: 2
|
u32 type: 2 (reserved)
|
||||||
u32 reserved: 0x0
|
u32 reserved: 0x0
|
||||||
}
|
}
|
||||||
[2]: {
|
[2]: {
|
||||||
u64 base_addr: 0xf0000
|
u64 base_addr: 0xf0000
|
||||||
u64 length: 65536
|
u64 length: 65536
|
||||||
u32 type: 2
|
u32 type: 2 (reserved)
|
||||||
u32 reserved: 0x0
|
u32 reserved: 0x0
|
||||||
}
|
}
|
||||||
[3]: {
|
[3]: {
|
||||||
u64 base_addr: 0x100000
|
u64 base_addr: 0x100000
|
||||||
u64 length: 133038080
|
u64 length: 133038080
|
||||||
u32 type: 1
|
u32 type: 1 (available)
|
||||||
u32 reserved: 0x0
|
u32 reserved: 0x0
|
||||||
}
|
}
|
||||||
[4]: {
|
[4]: {
|
||||||
u64 base_addr: 0x7fe0000
|
u64 base_addr: 0x7fe0000
|
||||||
u64 length: 131072
|
u64 length: 131072
|
||||||
u32 type: 2
|
u32 type: 2 (reserved)
|
||||||
u32 reserved: 0x0
|
u32 reserved: 0x0
|
||||||
}
|
}
|
||||||
[5]: {
|
[5]: {
|
||||||
u64 base_addr: 0xfffc0000
|
u64 base_addr: 0xfffc0000
|
||||||
u64 length: 262144
|
u64 length: 262144
|
||||||
u32 type: 2
|
u32 type: 2 (reserved)
|
||||||
u32 reserved: 0x0
|
u32 reserved: 0x0
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
|
@ -5,55 +5,60 @@
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include <kernaux/generic/display.h>
|
||||||
|
#include <kernaux/generic/malloc.h>
|
||||||
#include <kernaux/macro.h>
|
#include <kernaux/macro.h>
|
||||||
|
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <stddef.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 {
|
typedef const struct KernAux_Memmap_Node {
|
||||||
bool is_available;
|
uint64_t mem_start, mem_end, mem_size;
|
||||||
char tag[KERNAUX_MEMMAP_ENTRY_TAG_SIZE_MAX];
|
const char *tag;
|
||||||
size_t start, size, end, limit;
|
const struct KernAux_Memmap_Node *next, *children;
|
||||||
} *KernAux_MemMap_Entry;
|
} *KernAux_Memmap_Node;
|
||||||
|
|
||||||
typedef struct KernAux_MemMap {
|
typedef const struct KernAux_Memmap {
|
||||||
bool KERNAUX_PRIVATE_FIELD(is_finished);
|
KernAux_Memmap_Node root_node;
|
||||||
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];
|
|
||||||
|
|
||||||
struct KernAux_MemMap KernAux_MemMap_create(size_t memory_size);
|
KernAux_Malloc KERNAUX_PRIVATE_FIELD(malloc);
|
||||||
void KernAux_MemMap_init(KernAux_MemMap memmap, size_t memory_size);
|
} *KernAux_Memmap;
|
||||||
|
|
||||||
/// @warning Must only be called with NOT finished memmap, otherwise panics.
|
typedef struct KernAux_Memmap_Builder {
|
||||||
bool KernAux_MemMap_add_entry(
|
KernAux_Memmap KERNAUX_PRIVATE_FIELD(memmap);
|
||||||
KernAux_MemMap memmap,
|
} *KernAux_Memmap_Builder;
|
||||||
bool is_available,
|
|
||||||
const char *tag,
|
/*************
|
||||||
size_t start,
|
* Functions *
|
||||||
size_t size
|
*************/
|
||||||
|
|
||||||
|
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.
|
KernAux_Memmap
|
||||||
bool KernAux_MemMap_finish(KernAux_MemMap memmap);
|
KernAux_Memmap_Builder_finish_and_free(KernAux_Memmap_Builder builder);
|
||||||
|
|
||||||
/// @warning Must only be called with finished memmap, otherwise panics.
|
void KernAux_Memmap_free(KernAux_Memmap memmap);
|
||||||
KernAux_MemMap_Entry
|
void KernAux_Memmap_print(KernAux_Memmap memmap, KernAux_Display display);
|
||||||
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);
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,8 +5,10 @@
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <kernaux/macro.h>
|
|
||||||
#include <kernaux/generic/display.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 <kernaux/multiboot2/header_macro.h>
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
@ -559,6 +561,15 @@ KERNAUX_STATIC_TEST_STRUCT_SIZE(
|
||||||
#include <kernaux/multiboot2/header_print.h>
|
#include <kernaux/multiboot2/header_print.h>
|
||||||
#include <kernaux/multiboot2/info_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
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -32,7 +32,15 @@ extern "C" {
|
||||||
#define KERNAUX_MULTIBOOT2_ITAG_EFI_64BIT_IMAGE_HANDLE_PTR 20
|
#define KERNAUX_MULTIBOOT2_ITAG_EFI_64BIT_IMAGE_HANDLE_PTR 20
|
||||||
#define KERNAUX_MULTIBOOT2_ITAG_IMAGE_LOAD_BASE_PHYS_ADDR 21
|
#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_to_str(uint32_t tag_type);
|
||||||
|
const char*
|
||||||
|
KernAux_Multiboot2_ITag_MemoryMap_EntryBase_Type_to_str(uint32_t type);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
|
346
src/memmap.c
346
src/memmap.c
|
@ -4,6 +4,9 @@
|
||||||
|
|
||||||
#include "assert.h"
|
#include "assert.h"
|
||||||
|
|
||||||
|
#include <kernaux/generic/display.h>
|
||||||
|
#include <kernaux/generic/malloc.h>
|
||||||
|
#include <kernaux/macro.h>
|
||||||
#include <kernaux/memmap.h>
|
#include <kernaux/memmap.h>
|
||||||
|
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
|
@ -11,144 +14,245 @@
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <string.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_NOTNULL(malloc);
|
||||||
KernAux_MemMap_init(&memmap, memory_size);
|
|
||||||
|
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;
|
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;
|
KERNAUX_NOTNULL(memmap);
|
||||||
MEMMAP.memory_size = memory_size;
|
KERNAUX_ASSERT(memmap->root_node);
|
||||||
MEMMAP.entries_count = 0;
|
KERNAUX_ASSERT(memmap->malloc);
|
||||||
memset(MEMMAP.entries, 0, sizeof(MEMMAP.entries));
|
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(
|
void KernAux_Memmap_print(
|
||||||
KernAux_MemMap memmap,
|
const KernAux_Memmap memmap,
|
||||||
const bool is_available,
|
const KernAux_Display display
|
||||||
const char *const tag,
|
|
||||||
const size_t start,
|
|
||||||
const size_t size
|
|
||||||
) {
|
) {
|
||||||
if (MEMMAP.is_finished) {
|
KERNAUX_NOTNULL(memmap);
|
||||||
KERNAUX_PANIC("memmap is finished");
|
KERNAUX_ASSERT(memmap->root_node);
|
||||||
return false;
|
KERNAUX_ASSERT(memmap->malloc);
|
||||||
}
|
KERNAUX_ASSERT(memmap->root_node->next == NULL);
|
||||||
|
|
||||||
if (MEMMAP.entries_count >= KERNAUX_MEMMAP_ENTRIES_MAX) return false;
|
print_nodes(memmap->root_node, display, 0);
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool KernAux_MemMap_finish(KernAux_MemMap memmap)
|
void free_node(
|
||||||
{
|
const KernAux_Malloc malloc,
|
||||||
if (MEMMAP.is_finished) {
|
struct KernAux_Memmap_Node *const node
|
||||||
KERNAUX_PANIC("memmap is finished");
|
) {
|
||||||
return false;
|
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) ||
|
if (node->tag) KernAux_Malloc_free(malloc, (void*)node->tag);
|
||||||
MEMMAP.entries_count > KERNAUX_MEMMAP_ENTRIES_MAX ||
|
KernAux_Malloc_free(malloc, node);
|
||||||
MEMMAP.entries[0].start != 0 ||
|
}
|
||||||
MEMMAP.entries[MEMMAP.entries_count - 1].limit != MEMMAP.memory_size)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// At first, let's validate the individual entries.
|
#define PRINT(s) do { KernAux_Display_print (display, s); } while (0)
|
||||||
for (size_t index = 0; index < MEMMAP.entries_count; ++index) {
|
#define PRINTLN(s) do { KernAux_Display_println(display, s); } while (0)
|
||||||
if (SIZE_MAX - MEMMAP.entries[index].start <
|
|
||||||
MEMMAP.entries[index].size
|
#define PRINTLNF(format, ...) \
|
||||||
||
|
do { KernAux_Display_printlnf(display, format, __VA_ARGS__); } while (0)
|
||||||
MEMMAP.entries[index].end !=
|
|
||||||
MEMMAP.entries[index].start + MEMMAP.entries[index].size - 1
|
#define INDENT do { \
|
||||||
||
|
for (unsigned index = 0; index < indentation; ++index) PRINT(" "); \
|
||||||
MEMMAP.entries[index].limit !=
|
} while (0)
|
||||||
MEMMAP.entries[index].start + MEMMAP.entries[index].size)
|
|
||||||
{
|
void print_nodes(
|
||||||
return false;
|
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.
|
if (node->children) {
|
||||||
|
INDENT;
|
||||||
// Finally, let's validate that the entries fit each other properly.
|
PRINTLN(" struct* children: [");
|
||||||
for (size_t index = 1; index < MEMMAP.entries_count; ++index) {
|
print_nodes(node->children, display, indentation + 2);
|
||||||
if (MEMMAP.entries[index - 1].limit != MEMMAP.entries[index].start) {
|
INDENT;
|
||||||
return false;
|
PRINTLN(" ]");
|
||||||
|
} else {
|
||||||
|
INDENT;
|
||||||
|
PRINTLN(" struct* children: []");
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
return MEMMAP.is_finished = true;
|
INDENT;
|
||||||
}
|
PRINTLN("}");
|
||||||
|
}
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
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(" [%zu]: {", index);
|
||||||
PRINTLNF(" u64 base_addr: 0x%llx", base_addr);
|
PRINTLNF(" u64 base_addr: 0x%llx", base_addr);
|
||||||
PRINTLNF(" u64 length: %llu", length);
|
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);
|
PRINTLNF(" u32 reserved: 0x%lx", reserved);
|
||||||
PRINTLN (" }");
|
PRINTLN (" }");
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,12 +11,12 @@
|
||||||
/test_elf
|
/test_elf
|
||||||
/test_free_list
|
/test_free_list
|
||||||
/test_mbr
|
/test_mbr
|
||||||
/test_memmap
|
|
||||||
/test_multiboot2_common_packing
|
/test_multiboot2_common_packing
|
||||||
/test_multiboot2_header_helpers
|
/test_multiboot2_header_helpers
|
||||||
/test_multiboot2_header_print
|
/test_multiboot2_header_print
|
||||||
/test_multiboot2_header_print.c
|
/test_multiboot2_header_print.c
|
||||||
/test_multiboot2_header_validation
|
/test_multiboot2_header_validation
|
||||||
|
/test_multiboot2_info_convert_memmap
|
||||||
/test_multiboot2_info_helpers
|
/test_multiboot2_info_helpers
|
||||||
/test_multiboot2_info_print
|
/test_multiboot2_info_print
|
||||||
/test_multiboot2_info_print.c
|
/test_multiboot2_info_print.c
|
||||||
|
|
|
@ -168,18 +168,6 @@ test_mbr_SOURCES = \
|
||||||
test_mbr.c
|
test_mbr.c
|
||||||
endif
|
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 #
|
# test_multiboot2_common_packing #
|
||||||
##################################
|
##################################
|
||||||
|
@ -241,6 +229,22 @@ test_multiboot2_header_validation_SOURCES = \
|
||||||
../fixtures/multiboot2_header_example2.h
|
../fixtures/multiboot2_header_example2.h
|
||||||
endif
|
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 #
|
# 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);
|
|
||||||
}
|
|
|
@ -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 New Issue