From 8309174f1a4b79113d427c64985e7dd2c7db2a01 Mon Sep 17 00:00:00 2001 From: Mathieu Maret Date: Sat, 23 Jan 2021 00:42:09 +0100 Subject: [PATCH] Get mem mapping from bootloader --- core/klibc.h | 1 + core/main.c | 50 +++++++++------ core/mem.c | 35 +++++------ core/mem.h | 1 + core/minmax.h | 169 ++++++++++++++++++++++++++++++++++++++++++++++++++ tests/test.c | 2 - 6 files changed, 220 insertions(+), 38 deletions(-) create mode 100644 core/minmax.h diff --git a/core/klibc.h b/core/klibc.h index c5a4375..a20d554 100644 --- a/core/klibc.h +++ b/core/klibc.h @@ -1,5 +1,6 @@ #pragma once #include "stdarg.h" +#include "minmax.h" #define islower(c) (('a' <= (c)) && ((c) <= 'z')) #define isupper(c) (('A' <= (c)) && ((c) <= 'Z')) diff --git a/core/main.c b/core/main.c index 135cd71..92a079e 100644 --- a/core/main.c +++ b/core/main.c @@ -37,7 +37,9 @@ void idleThread(void *arg) // https://www.gnu.org/software/grub/manual/multiboot/html_node/Boot-information-format.html#Boot%20information%20format void kmain(unsigned long magic, unsigned long addr) { - unsigned long upperMem = 0; + unsigned long upperMemKB = 0; + int memMapAvailable = 0; + paddr_t lastUsedByMem; VGASetup(BLACK, GREEN); cursorEnable(14, 15); @@ -53,7 +55,7 @@ void kmain(unsigned long magic, unsigned long addr) /* Are mem_* valid? */ if (CHECK_FLAG(mbi->flags, 0)) { printf("mem_lower = %dKiB mem_upper %dKiB\n", mbi->mem_lower, mbi->mem_upper); - upperMem = mbi->mem_upper; + upperMemKB = mbi->mem_upper; } /* Is boot_device valid? */ @@ -79,31 +81,43 @@ void kmain(unsigned long magic, unsigned long addr) } if (CHECK_FLAG(mbi->flags, 6)) { - struct multiboot_mmap_entry *mmap = (struct multiboot_mmap_entry *)mbi->mmap_addr; - uint size = mbi->mmap_length / sizeof(struct multiboot_mmap_entry); - pr_devel("mmap buffer at %d size %d %d\n", mbi->mmap_addr, mbi->mmap_length, - sizeof(multiboot_memory_map_t)); - for (uint i = 0; i < size; i++) { - printf("base_addr 0x%x 0x%x, length = 0x%x 0x%x, type = 0x%x\n", - (unsigned)(mmap[i].addr >> 32), (unsigned)(mmap[i].addr & 0xffffffff), - (unsigned)(mmap[i].len >> 32), (unsigned)(mmap[i].len & 0xffffffff), - (uint32_t)mmap[i].type); - } + memMapAvailable = 1; } } - if (upperMem == 0) { + if (upperMemKB == 0) { printf("Cannot get upper phy mem bound. Using default value 32MB\n"); - upperMem = 32 * 1024; + upperMemKB = 32 * 1024; } - printf("Setting up Pagination\n"); - paddr_t lastUserByMem; - memSetup(upperMem, &lastUserByMem); + printf("Setting up Mem\n"); + memSetup(upperMemKB, &lastUsedByMem); + + if (memMapAvailable) { + multiboot_info_t *mbi = (multiboot_info_t *)addr; + struct multiboot_mmap_entry *mmap = (struct multiboot_mmap_entry *)mbi->mmap_addr; + uint size = mbi->mmap_length / sizeof(struct multiboot_mmap_entry); + pr_devel("mmap buffer at 0x%x with %d entries\n", mbi->mmap_addr, size); + for (uint i = 0; i < size; i++) { + printf(" base_addr 0x%x 0x%x, length = 0x%x 0x%x, type = 0x%x\n", + (unsigned)(mmap[i].addr >> 32), (unsigned)(mmap[i].addr & 0xffffffff), + (unsigned)(mmap[i].len >> 32), (unsigned)(mmap[i].len & 0xffffffff), + (uint32_t)mmap[i].type); + memAddBank( + max(mmap[i].addr, (multiboot_uint64_t)lastUsedByMem), + min((multiboot_uint64_t)(upperMemKB * 1024), mmap[i].addr + mmap[i].len), + mmap[i].type == MULTIBOOT_MEMORY_AVAILABLE); + } + } else { + printf("Cannot get memory Mapping information, using default value\n"); + memAddBank(0, lastUsedByMem, 0); + memAddBank(lastUsedByMem, upperMemKB * 1024, 1); + } #ifdef RUN_TEST testPhymem(); #endif - pagingSetup(lastUserByMem); + printf("Setting up Pagination\n"); + pagingSetup(lastUsedByMem); printf("Setting up IRQ handlers\n"); irqSetRoutine(IRQ_KEYBOARD, keyboard_handler); diff --git a/core/mem.c b/core/mem.c index bfd2dce..8ae1d3b 100644 --- a/core/mem.c +++ b/core/mem.c @@ -7,50 +7,49 @@ static struct memDesc *pageDesc = (struct memDesc *)&__ld_kernel_end; static struct memDesc *freePage; static struct memDesc *usedPage; -static unsigned long memBottom; -static unsigned long memTop; static unsigned long allocatedPage = 0; -int memSetup(paddr_t upperMem, paddr_t *lastPageUsedOut) +int memSetup(paddr_t upperMemKB, paddr_t *lastMemUsedOut) { list_init(freePage); list_init(usedPage); // Align upper mem (in kB) on page size even if it does loose a page - upperMem = ALIGN_DOWN(upperMem, PAGE_SIZE / 1024); - unsigned long nbPage = ((upperMem) / (PAGE_SIZE / 1024)); + upperMemKB = ALIGN_DOWN(upperMemKB, PAGE_SIZE / 1024); + unsigned long nbPage = ((upperMemKB) / (PAGE_SIZE / 1024)); printf("Available Mem from 0x%x to 0x%x: %dMB and %dPages(%d)\n", &__ld_kernel_end, - upperMem * 1024, (upperMem * 1024 - (uint32_t)&__ld_kernel_end) / (1024 * 1024), + upperMemKB * 1024, (upperMemKB * 1024 - (uint32_t)&__ld_kernel_end) / (1024 * 1024), nbPage, PAGE_SIZE); // Memory description is stored after the kernel. We need some place to store it unsigned long pageDescEnd = (unsigned long)pageDesc + nbPage * sizeof(struct memDesc); - uint lastPageUsed = (pageDescEnd >> PAGE_SHIFT) + 1; - memBottom = lastPageUsed << PAGE_SHIFT; - memTop = upperMem * 1024; - *lastPageUsedOut = pageDescEnd; + *lastMemUsedOut = ALIGN(pageDescEnd, PAGE_SIZE); - for (uint i = 0; i < nbPage; i++) { + memAddBank(0, *lastMemUsedOut, 0); + return 0; +} + +int memAddBank(paddr_t bottomMem, paddr_t topMem, int isFree) +{ + for (uint i = (bottomMem >> PAGE_SHIFT); i < (topMem >> PAGE_SHIFT); i++) { struct memDesc *mem = &pageDesc[i]; - if (i < lastPageUsed) { - mem->ref = 1; - list_add_tail(usedPage, mem); - } else { + if (isFree) { mem->ref = 0; list_add_tail(freePage, mem); + } else { + mem->ref = 1; + list_add_tail(usedPage, mem); } mem->phy_addr = i * PAGE_SIZE; } + return 0; } struct memDesc *addr2memDesc(paddr_t addr) { - if (addr > memTop || addr < memBottom) - return NULL; - int idx = addr >> PAGE_SHIFT; return pageDesc + idx; } diff --git a/core/mem.h b/core/mem.h index 3b8f9d6..a5d9fb4 100644 --- a/core/mem.h +++ b/core/mem.h @@ -16,6 +16,7 @@ struct memDesc { }; int memSetup(paddr_t upperMem, paddr_t *lastUsed); +int memAddBank(paddr_t bottomMem, paddr_t topMem, int isFree); paddr_t allocPhyPage(uint nbPage); int unrefPhyPage(paddr_t addr); int refPhyPage(paddr_t addr); diff --git a/core/minmax.h b/core/minmax.h new file mode 100644 index 0000000..2444b7b --- /dev/null +++ b/core/minmax.h @@ -0,0 +1,169 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef _LINUX_MINMAX_H +#define _LINUX_MINMAX_H + +/* + * From linux kernel include/linux/compiler_types.h + */ +#define ___PASTE(a,b) a##b +#define __PASTE(a,b) ___PASTE(a,b) + +/* + * From Linux kernel include/linux/compiler.h + */ +/* Not-quite-unique ID. */ +#ifndef __UNIQUE_ID +# define __UNIQUE_ID(prefix) __PASTE(__PASTE(__UNIQUE_ID_, prefix), __LINE__) +#endif + + + +/* + * min()/max()/clamp() macros must accomplish three things: + * + * - avoid multiple evaluations of the arguments (so side-effects like + * "x++" happen only once) when non-constant. + * - perform strict type-checking (to generate warnings instead of + * nasty runtime surprises). See the "unnecessary" pointer comparison + * in __typecheck(). + * - retain result as a constant expressions when called with only + * constant expressions (to avoid tripping VLA warnings in stack + * allocation usage). + */ +#define __typecheck(x, y) \ + (!!(sizeof((typeof(x) *)1 == (typeof(y) *)1))) + +/* + * This returns a constant expression while determining if an argument is + * a constant expression, most importantly without evaluating the argument. + * Glory to Martin Uecker + */ +#define __is_constexpr(x) \ + (sizeof(int) == sizeof(*(8 ? ((void *)((long)(x) * 0l)) : (int *)8))) + +#define __no_side_effects(x, y) \ + (__is_constexpr(x) && __is_constexpr(y)) + +#define __safe_cmp(x, y) \ + (__typecheck(x, y) && __no_side_effects(x, y)) + +#define __cmp(x, y, op) ((x) op (y) ? (x) : (y)) + +#define __cmp_once(x, y, unique_x, unique_y, op) ({ \ + typeof(x) unique_x = (x); \ + typeof(y) unique_y = (y); \ + __cmp(unique_x, unique_y, op); }) + +#define __careful_cmp(x, y, op) \ + __builtin_choose_expr(__safe_cmp(x, y), \ + __cmp(x, y, op), \ + __cmp_once(x, y, __UNIQUE_ID(__x), __UNIQUE_ID(__y), op)) + +/** + * min - return minimum of two values of the same or compatible types + * @x: first value + * @y: second value + */ +#define min(x, y) __careful_cmp(x, y, <) + +/** + * max - return maximum of two values of the same or compatible types + * @x: first value + * @y: second value + */ +#define max(x, y) __careful_cmp(x, y, >) + +/** + * min3 - return minimum of three values + * @x: first value + * @y: second value + * @z: third value + */ +#define min3(x, y, z) min((typeof(x))min(x, y), z) + +/** + * max3 - return maximum of three values + * @x: first value + * @y: second value + * @z: third value + */ +#define max3(x, y, z) max((typeof(x))max(x, y), z) + +/** + * min_not_zero - return the minimum that is _not_ zero, unless both are zero + * @x: value1 + * @y: value2 + */ +#define min_not_zero(x, y) ({ \ + typeof(x) __x = (x); \ + typeof(y) __y = (y); \ + __x == 0 ? __y : ((__y == 0) ? __x : min(__x, __y)); }) + +/** + * clamp - return a value clamped to a given range with strict typechecking + * @val: current value + * @lo: lowest allowable value + * @hi: highest allowable value + * + * This macro does strict typechecking of @lo/@hi to make sure they are of the + * same type as @val. See the unnecessary pointer comparisons. + */ +#define clamp(val, lo, hi) min((typeof(val))max(val, lo), hi) + +/* + * ..and if you can't take the strict + * types, you can specify one yourself. + * + * Or not use min/max/clamp at all, of course. + */ + +/** + * min_t - return minimum of two values, using the specified type + * @type: data type to use + * @x: first value + * @y: second value + */ +#define min_t(type, x, y) __careful_cmp((type)(x), (type)(y), <) + +/** + * max_t - return maximum of two values, using the specified type + * @type: data type to use + * @x: first value + * @y: second value + */ +#define max_t(type, x, y) __careful_cmp((type)(x), (type)(y), >) + +/** + * clamp_t - return a value clamped to a given range using a given type + * @type: the type of variable to use + * @val: current value + * @lo: minimum allowable value + * @hi: maximum allowable value + * + * This macro does no typechecking and uses temporary variables of type + * @type to make all the comparisons. + */ +#define clamp_t(type, val, lo, hi) min_t(type, max_t(type, val, lo), hi) + +/** + * clamp_val - return a value clamped to a given range using val's type + * @val: current value + * @lo: minimum allowable value + * @hi: maximum allowable value + * + * This macro does no typechecking and uses temporary variables of whatever + * type the input argument @val is. This is useful when @val is an unsigned + * type and @lo and @hi are literals that will otherwise be assigned a signed + * integer type. + */ +#define clamp_val(val, lo, hi) clamp_t(typeof(val), val, lo, hi) + +/** + * swap - swap values of @a and @b + * @a: first value + * @b: second value + */ +#define swap(a, b) \ + do { typeof(a) __tmp = (a); (a) = (b); (b) = __tmp; } while (0) + +#endif /* _LINUX_MINMAX_H */ diff --git a/tests/test.c b/tests/test.c index 1ceda97..b8ececd 100644 --- a/tests/test.c +++ b/tests/test.c @@ -14,8 +14,6 @@ void testPhymem(void) { printf("Testing memory PHY\n"); - assert(refPhyPage((paddr_t)(&__ld_kernel_end)) == -1); - assert(refPhyPage((paddr_t)(&__ld_kernel_begin)) == -1); struct memDesc *allocated_page_list; struct memDesc *page; // Cast in mem_desc to use it. In fact it's the addr of 4K free memory