From: Matthias Kruk Date: Sat, 1 Aug 2020 07:36:18 +0000 (+0900) Subject: kernel/arch: Move computation of the end of usable memory into a separate function... X-Git-Url: https://git.corax.cc/?a=commitdiff_plain;h=b6ab58ba18ad9ed2d62242ef0e8eea45875b0415;p=corax kernel/arch: Move computation of the end of usable memory into a separate function, add documentation * Move computation of the end of usable memory from pg_init() into _get_memory_end * Add documentation to the following functions - _pg_dir_debug_regions() - _pg_dir_debug_arch() - _get_memory_end() - pg_init() --- diff --git a/kernel/arch/paging.c b/kernel/arch/paging.c index d0eb3c4..bf611a0 100644 --- a/kernel/arch/paging.c +++ b/kernel/arch/paging.c @@ -252,6 +252,24 @@ void pg_frame_free(void *addr) #if FEATURE(DEBUG) +/* + * _pg_dir_debug_regions() - Print the memory regions of a page directory to the VGA buffer + * + * SYNOPSIS + * void _pg_dir_debug_regions(pg_dir_t *pd); + * + * DESCRIPTION + * The _pg_dir_debug_regions() function iterates over all regions that have been added to the + * page directory pointed to by `pd' and prints the regions' type, base address, and size to + * the VGA buffer. + * This function prints each region, including regions that are unused. + * + * RETURN VALUE + * void + * + * ERRORS + * This function does not signal any errors. + */ static void _pg_dir_debug_regions(pg_dir_t *pd) { struct region *reg; @@ -267,6 +285,26 @@ static void _pg_dir_debug_regions(pg_dir_t *pd) return; } +/* + * _pg_dir_debug_arch() - Print a page directory to the VGA buffer + * + * SYNOPSIS + * void _pg_dir_debug_arch(pg_dir_t *pd); + * + * DESCRIPTION + * The _pg_dir_debug_arch() function prints the contents of the page directory pointed to + * by `pd' to the VGA buffer. In order to do this, this function manually performs lookups + * of the second-level and third-level paging structures, and prints any non-zero entries + * to video memory. + * This function supports printing of page directories that use either legacy (4KB) paging + * or PAE paging. + * + * RETURN VALUE + * void + * + * ERRORS + * This function does not signal any errors. + */ static void _pg_dir_debug_arch(pg_dir_t *pd) { switch(_pg_flags & PG_MODE_MASK) { @@ -290,7 +328,8 @@ static void _pg_dir_debug_arch(pg_dir_t *pd) for(j = 0; j < 1024; j++) { if(tbl->pt_entries[j] & PAGE_ATTR_PRESENT) { - dbg_printf("cr3[%04u][%04u] = 0x%08x\n", i, j, tbl->pt_entries[j]); + dbg_printf("cr3[%04u][%04u] = 0x%08x\n", + i, j, tbl->pt_entries[j]); } } } @@ -327,7 +366,8 @@ static void _pg_dir_debug_arch(pg_dir_t *pd) dbg_printf("cr3[%01u][%03u] = 0x%016llx\n", i, j, tbl->ppt_entries[j]); if(!(tbl->ppt_entries[j] & PAGE_ATTR_SIZE)) { - ttbl = (struct pae_page_table*)((unsigned long)tbl->ppt_entries[j] & ~0xfff); + ttbl = (struct pae_page_table*)((unsigned long)tbl->ppt_entries[j] & + ~0xfff); for(k = 0; k < 512; k++) { if(!(ttbl->ppt_entries[k] & PAGE_ATTR_PRESENT)) { @@ -350,6 +390,90 @@ static void _pg_dir_debug_arch(pg_dir_t *pd) } #endif /* FEATURE(DEBUG) */ +/* + * _get_memory_end() - Get the upper end of usable memory + * + * SYNOPSIS + * u64_t _get_memory_end(struct multiboot_info *info); + * + * DESCRIPTION + * The _get_memory_end() function determines the upper end of the usable memory by inspecting + * the multiboot information pointed to by `info'. It iterates over the memory map provided by + * the bootloader and simply computes the end of the highest memory region that the bootloader + * recons to be available for use by the operating system. + * + * RETURN VALUE + * Upon success, the first address after the highest usable memory region is returned. If the + * address could not be determined, zero is returned. + * + * ERRORS + * This function does not signal any errors. + */ +static u64_t _get_memory_end(struct multiboot_info *info) +{ + struct memory_map *mmap; + u64_t mem_end; + + mem_end = 0; + + for(mmap = (struct memory_map*)info->mmap_addr; + (void*)mmap < (void*)(info->mmap_addr + info->mmap_length); + mmap = (struct memory_map*)((void*)mmap + mmap->size + sizeof(mmap->size))) { + if(mmap->type != MEM_AVAILABLE) { + continue; + } + + if((mmap->addr + mmap->len) > mem_end) { + mem_end = mmap->addr + mmap->len; + } + } + + return(mem_end); +} + +/* + * pg_init() - Initialize kernel page directory + * + * SYNOPSIS + * void* pg_init(struct multiboot_info *info); + * + * DESCRIPTION + * The pg_init() function initializes the memory structures that are necessary for paging to be + * enabled. pg_init() will first allocate memory for the frame map that is used to keep track of + * page availability, and mark all page frames as being in use (this is done to ensure that non- + * usable/reserved page frames are not accidentally left marked as available). Once that is done, + * this function will allocate memory for the kernel page directory and identity-map all memory + * that is in the machine (including reserved/unusable areas) into the kernel's page directory, + * setting the page attributes appropriately (for example, write-thru and cache-disable on APIC + * memory). During the mapping, memory regions that are available for general use are cleared in + * the frame map, making them available for allocations. + * The pg_init() function will then initialize the kernel heap and add regions to the kernel's + * page directory in order to keep track of the allocations (memory for regions is allocated from + * the kernel heap, hence it has to be done in this order). Finally, all frames from 0x0 to the + * end of the kernel heap are set in the frame map, making sure they will not be used for frame + * allocations. + * + * The frame map and the kernel's page directory are allocated from linear memory, using the + * _phys_alloc() function. If the CPU supports PAE paging, the kernel page directory will be + * populated using 2MB pages; otherwise 4MB pages will be used. This is done in order to reduce + * the amount of memory needed for the kernel page directory, and to reduce the burden on the TLB + * when in kernel mode. + * + * This function is called from architecture-dependent initialization code (in init.S). It must not + * be called from anywhere else, and it must not be called more than once. + * + * RETURN VALUE + * This function returns the supported paging mode ORed with the kernel page directory's base + * address (since the base address is page aligned, this is safe to do). The calling code must + * make sure to mask the paging mode bits before assigning the value to CR3. The calling code + * must also make sure to configure the processor for the paging mode indicated by the return + * value, otherwise the initialized kernel page directory might not be usable (for example, if + * this function has set up the kernel page directory for PAE paging, but the caller does not + * enable PAE paging in the CPU). + * + * ERRORS + * This function does not signal any errors. + */ void* pg_init(struct multiboot_info *info) { struct memory_map *mmap; @@ -366,22 +490,7 @@ void* pg_init(struct multiboot_info *info) * We need to determine the size of the frame set. This should be the largest address * that we can use for allocations. */ - - for(mmap = (struct memory_map*)info->mmap_addr; - (void*)mmap < (void*)(info->mmap_addr + info->mmap_length); - mmap = (struct memory_map*)((void*)mmap + mmap->size + sizeof(mmap->size))) { - u64_t limit; - - if(mmap->type != MEM_AVAILABLE) { - continue; - } - - limit = mmap->addr + mmap->len; - - if(limit > mem_size) { - mem_size = limit; - } - } + mem_size = _get_memory_end(info); #if FEATURE(DEBUG) dbg_printf("Last usable address: 0x%016llx\n", mem_size);