From: Matthias Kruk Date: Sat, 1 Aug 2020 17:06:35 +0000 (+0900) Subject: kernel/arch: Split _pg_dir_debug_arch() into three functions, add documentation for... X-Git-Url: https://git.corax.cc/?a=commitdiff_plain;h=e48c4bea8c09e77c068e7fd225a442f288e51f58;p=corax kernel/arch: Split _pg_dir_debug_arch() into three functions, add documentation for pg_dir_memcpy() --- diff --git a/kernel/arch/paging.c b/kernel/arch/paging.c index b5f1f27..373a294 100644 --- a/kernel/arch/paging.c +++ b/kernel/arch/paging.c @@ -258,8 +258,8 @@ void pg_frame_free(void *addr) * * 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. + * 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 @@ -284,18 +284,16 @@ static void _pg_dir_debug_regions(pg_dir_t *pd) } /* - * _pg_dir_debug_arch() - Print a page directory to the VGA buffer + * _pg_dir_debug_arch_legacy() - Print a legacy page directory to the VGA buffer * * SYNOPSIS - * void _pg_dir_debug_arch(pg_dir_t *pd); + * void _pg_dir_debug_arch_legacy(struct page_table *dir); * * 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. + * The _pg_dir_debug_arch_legacy() function prints the contents of the page directory pointed to + * by `dir' to the VGA buffer. In order to do this, this function manually performs lookups of + * the second-level paging structures, and prints any non-zero entries to video memory. + * This function supports printing of page directories that use legacy IA-32 paging. * * RETURN VALUE * void @@ -303,89 +301,132 @@ static void _pg_dir_debug_regions(pg_dir_t *pd) * ERRORS * This function does not signal any errors. */ -static void _pg_dir_debug_arch(pg_dir_t *pd) +static void _pg_dir_debug_arch_legacy(struct page_table *dir) { - switch(_pg_flags & PG_MODE_MASK) { - case PG_MODE_LEGACY: { - struct page_table *dir; - u32_t i; - - dir = (struct page_table*)pd->pd_base; + int i; - for(i = 0; i < 1024; i++) { - if(!(dir->pt_entries[i] & PAGE_ATTR_PRESENT)) { - continue; - } + for(i = 0; i < 1024; i++) { + if(!(dir->pt_entries[i] & PAGE_ATTR_PRESENT)) { + continue; + } - dbg_printf("cr3[%04u] = 0x%08x\n", i, dir->pt_entries[i]); - if(!(dir->pt_entries[i] & PAGE_ATTR_SIZE)) { - struct page_table *tbl; - u32_t j; + dbg_printf("cr3[%04u] = 0x%08x\n", i, dir->pt_entries[i]); + if(!(dir->pt_entries[i] & PAGE_ATTR_SIZE)) { + struct page_table *tbl; + u32_t j; - tbl = (struct page_table*)(dir->pt_entries[i] & 0xfffff000); + tbl = (struct page_table*)(dir->pt_entries[i] & 0xfffff000); - 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]); - } + 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]); } } } - - break; } - case PG_MODE_PAE: { - struct pdpt *dir; - u32_t i; - - dir = (struct pdpt*)pd->pd_base; + return; +} - for(i = 0; i < 4; i++) { - struct pae_page_table *tbl; - int j; +/* + * _pg_dir_debug_arch_pae() - Print a PAE page directory to the VGA buffer + * + * SYNOPSIS + * void _pg_dir_debug_arch_pae(struct pdpt *dir); + * + * DESCRIPTION + * The _pg_dir_debug_arch_pae() function prints the contents of the page directory pointed to by + * `dir' 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 PAE paging. + * + * RETURN VALUE + * void + * + * ERRORS + * This function does not signal any errors. + */ +static void _pg_dir_debug_arch_pae(struct pdpt *dir) +{ + u32_t i; - if(!(dir->pdpt_entries[i] & PAGE_ATTR_PRESENT)) { - continue; - } + for(i = 0; i < 4; i++) { + struct pae_page_table *tbl; + int j; - dbg_printf("cr3[%01u] = 0x%016llx\n", i, dir->pdpt_entries[i]); - tbl = (struct pae_page_table*)((unsigned long)dir->pdpt_entries[i] & ~0xfff); + if(!(dir->pdpt_entries[i] & PAGE_ATTR_PRESENT)) { + continue; + } - for(j = 0; j < 512; j++) { - struct pae_page_table *ttbl; - int k; + dbg_printf("cr3[%01u] = 0x%016llx\n", i, dir->pdpt_entries[i]); + tbl = (struct pae_page_table*)((unsigned long)dir->pdpt_entries[i] & ~0xfff); - if(!(tbl->ppt_entries[j] & PAGE_ATTR_PRESENT)) { - continue; - } + for(j = 0; j < 512; j++) { + struct pae_page_table *ttbl; + int k; - dbg_printf("cr3[%01u][%03u] = 0x%016llx\n", i, j, tbl->ppt_entries[j]); + if(!(tbl->ppt_entries[j] & PAGE_ATTR_PRESENT)) { + continue; + } - if(!(tbl->ppt_entries[j] & PAGE_ATTR_SIZE)) { - ttbl = (struct pae_page_table*)((unsigned long)tbl->ppt_entries[j] & - ~0xfff); + dbg_printf("cr3[%01u][%03u] = 0x%016llx\n", + i, j, tbl->ppt_entries[j]); - for(k = 0; k < 512; k++) { - if(!(ttbl->ppt_entries[k] & PAGE_ATTR_PRESENT)) { - continue; - } + if(!(tbl->ppt_entries[j] & PAGE_ATTR_SIZE)) { + ttbl = (struct pae_page_table*)((unsigned long)tbl->ppt_entries[j] + & ~0xfff); - dbg_printf("cr3[%01u][%03u][%03u] = 0x%016llx\n", - i, j, k, ttbl->ppt_entries[k]); + for(k = 0; k < 512; k++) { + if(!(ttbl->ppt_entries[k] & PAGE_ATTR_PRESENT)) { + continue; } + + dbg_printf("cr3[%01u][%03u][%03u] = 0x%016llx\n", + i, j, k, ttbl->ppt_entries[k]); } } } + } + + 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) { + case PG_MODE_LEGACY: + _pg_dir_debug_arch_legacy((struct page_table*)pd->pd_base); break; - } + case PG_MODE_PAE: + _pg_dir_debug_arch_pae((struct pdpt*)pd->pd_base); + break; } return; } + #endif /* FEATURE(DEBUG) */ /* @@ -395,9 +436,9 @@ static void _pg_dir_debug_arch(pg_dir_t *pd) * 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 + * 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 @@ -430,16 +471,16 @@ static u64_t _get_memory_end(struct multiboot_info *info) } /* - * _pae_identity_map() - Add an identity mapped memory region to a PAE page directory + * _identity_map_pae() - Add an identity mapped memory region to a PAE page directory * * SYNOPSIS - * void _pae_identity_map(pdpt_t *pd, u64_t from, u64_t to, page_attrs_t attrs); + * void _identity_map_pae(pdpt_t *pd, u64_t from, u64_t to, page_attrs_t attrs); * * DESCRIPTION - * The _pae_identity_map() function creates an identity mapping for the linear memory region + * The _identity_map_pae() function creates an identity mapping for the linear memory region * [`from', `to') in the page directory pointed to by `pd' - that means, `to' is the first - * address outside of the mapped region. The page attributes of the mapping will be set - * according to the value passed in `attrs'. + * address outside of the mapped region. The page attributes of the mapping will be set according + * to the value passed in `attrs'. * This function will only map pages from the low 4GB of memory. * * RETURN VALUE @@ -448,14 +489,16 @@ static u64_t _get_memory_end(struct multiboot_info *info) * ERRORS * This function does not signal any errors. */ -static void _pae_identity_map(pdpt_t *pd, u64_t from, u64_t to, page_attrs_t attrs) +static void _identity_map_pae(pdpt_t *pd, u64_t from, u64_t to, page_attrs_t attrs) { u64_t addr; /* the way PAE works we can access 64G of physical memory, but we can still * only address 4G at a time, i.e. in each page directory. So stop at 4G. */ - for(addr = from & ~(PAGE_SIZE_BIG - 1); addr < to && addr < 0x100000000LL; addr += PAGE_SIZE_BIG) { + addr = from & ~(PAGE_SIZE_BIG - 1); + + while(addr < to && addr < 0x100000000LL) { pae_page_table_t *pt; u64_t idx; @@ -470,22 +513,24 @@ static void _pae_identity_map(pdpt_t *pd, u64_t from, u64_t to, page_attrs_t att } pt->ppt_entries[(addr >> 21) & 0x1ff] = addr | attrs; + + addr += PAGE_SIZE_BIG; } return; } /* - * _legacy_identity_map() - Add an identity mapped memory region to an IA-32 page directory + * _identity_map_legacy() - Add an identity mapped memory region to an IA-32 page directory * * SYNOPSIS - * void _legacy_identity_map(page_table_t *pd, u64_t from, u64_t to, page_attrs_t attrs); + * void _identity_map_legacy(page_table_t *pd, u64_t from, u64_t to, page_attrs_t attrs); * * DESCRIPTION - * The _legacy_identity_map() function creates an identity mapping for the linear memory region + * The _identity_map_legacy() function creates an identity mapping for the linear memory region * [`from', `to') in the page directory pointed to by `pd' - that means, `to' is the first - * address outside of the mapped region. The page attributes of the mapping will be set - * according to the value passed in `attrs'. + * address outside of the mapped region. The page attributes of the mapping will be set according + * to the value passed in `attrs'. * * RETURN VALUE * void @@ -493,7 +538,7 @@ static void _pae_identity_map(pdpt_t *pd, u64_t from, u64_t to, page_attrs_t att * ERRORS * This function does not signal any errors. */ -static void _legacy_identity_map(page_table_t *pd, u64_t from, u64_t to, page_attrs_t attrs) +static void _identity_map_legacy(page_table_t *pd, u64_t from, u64_t to, page_attrs_t attrs) { u64_t addr; @@ -511,10 +556,10 @@ static void _legacy_identity_map(page_table_t *pd, u64_t from, u64_t to, page_at * void _identity_map(void *cr3, struct multiboot_info *info); * * DESCRIPTION - * The _identity_map() function will create an identity mapping for the memory map - * provided in the multiboot info pointed to by `info' within the page directory - * pointed to by `cr3'. The identity mapping will be created using pages that are - * as big as possible for the supported paging modes. + * The _identity_map() function will create an identity mapping for the memory map provided in + * the multiboot info pointed to by `info' within the page directory pointed to by `cr3'. The + * identity mapping will be created using pages that are as big as possible for the supported + * paging modes. * * RETURN VALUE * void @@ -526,9 +571,9 @@ static void _identity_map(void *cr3, struct multiboot_info *info) { struct memory_map *mmap; - 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))) { + mmap = (struct memory_map*)info->mmap_addr; + + while((void*)mmap < (void*)(info->mmap_addr + info->mmap_length)) { page_attrs_t attrs; #if FEATURE(DEBUG) @@ -537,29 +582,31 @@ static void _identity_map(void *cr3, struct multiboot_info *info) #endif /* FEATURE(DEBUG) */ /* FIXME: Memory in the region 0x100000:&_mem_start should NOT be writable! */ + attrs = PAGE_ATTR_SIZE | PAGE_ATTR_WRITABLE | PAGE_ATTR_PRESENT; - /* disable caching on reserved memory areas */ if(mmap->type != MEM_AVAILABLE) { - /* the frames are already marked as in-use, so we'll just leave it at that */ + /* disable caching on reserved memory areas */ attrs |= PAGE_ATTR_WRITE_THRU | PAGE_ATTR_CACHE_DISABLE; } switch(_pg_flags & PG_MODE_MASK) { - case PG_MODE_LEGACY: { - _legacy_identity_map((page_table_t*)cr3, mmap->addr, mmap->addr + mmap->len, attrs); + case PG_MODE_LEGACY: + _identity_map_legacy((page_table_t*)cr3, mmap->addr, + mmap->addr + mmap->len, attrs); break; - } - case PG_MODE_PAE: { - _pae_identity_map((pdpt_t*)cr3, mmap->addr, mmap->addr + mmap->len, attrs); + case PG_MODE_PAE: + _identity_map_pae((pdpt_t*)cr3, mmap->addr, + mmap->addr + mmap->len, attrs); break; - } case PG_MODE_INTEL64: case PG_MODE_IA32E: PANIC("How did I get here?"); } + + mmap = (struct memory_map*)((void*)mmap + mmap->size + sizeof(mmap->size)); } return; @@ -631,8 +678,8 @@ void _clear_unused_frames(struct multiboot_info *info) * 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. + * 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 @@ -657,8 +704,8 @@ void* pg_init(struct multiboot_info *info) cr3 = 0; /* - * We need to determine the size of the frame set. This should be the largest address - * that we can use for allocations. + * We need to determine the size of the frame set. This should be the largest address that + * we can use for allocations. */ mem_size = _get_memory_end(info); @@ -668,10 +715,10 @@ void* pg_init(struct multiboot_info *info) #endif /* FEATURE(DEBUG) */ /* - * Figure out if we should be using PAE paging or not. Besides looking at the amount - * of available memory, the kernel should probably also see what cpuid has to say about - * PAE availability. It's not unreasonable to expect PAE to be supported though, since - * it has been around since the Pentium Pro (with the exception of some Pentium Ms). + * Figure out if we should be using PAE paging or not. Besides looking at the amount of + * available memory, the kernel should probably also see what cpuid has to say about PAE + * availability. It's not unreasonable to expect PAE to be supported though, since it has + * been around since the Pentium Pro (with the exception of some Pentium Ms). */ if(mem_size < 0x100000000L) { /* we have less than 4G of memory, no need for PAE */ @@ -683,20 +730,26 @@ void* pg_init(struct multiboot_info *info) /* * Allocate linear memory for the frame map. The size of the frame map is determined by - * dividing the memory size by the smallest possible page size (4096) and then by the number - * of bits in a u32_t. I recon it's not really necessary to do a shift instead of a division - * here since this code will only be executed once and the compiler is going to optimize it - * anyways, but oh well. + * dividing the memory size by the smallest possible page size (4096) and then by the + * number of bits in a u32_t. I recon it's not really necessary to do a shift instead of + * a division here since this code will only be executed once and the compiler is going + * to optimize it anyways, but oh well. */ _nframes = mem_size >> 17; _frame_map = _phys_alloc(_nframes << 2, 4); - /* first mark all frames as used - we will later clear those that are actually available */ + /* + * First mark all frames as used - the ones that are available for allocations will later + * be cleared by means of a call to _clear_unused_frames()/ + */ for(i = 0; i < mem_size; i += PAGE_SIZE) { _frame_set(i); } - /* allocate the proper page directory type for the kernel */ + /* + * Allocate memory for the kernel page directory. The necessary top level paging structure + * depends on the paging mode that we are going to employ. + */ switch(_pg_flags & PG_MODE_MASK) { case PG_MODE_LEGACY: cr3 = (u32_t)_phys_alloc(sizeof(page_table_t), PAGE_ALIGN); @@ -760,11 +813,10 @@ void* pg_init(struct multiboot_info *info) * void *pg_dir_get_kstack(struct pagedir *pgdir); * * DESCRIPTION - * The pg_dir_get_kstack() function looks up the kernel-mode stack that is mapped into - * the page directory pointed to by `pgdir' and returns the linear address of that stack. - * This is done by iterating over all regions that are associated with the page directory, - * looking for the region whose type is REGION_TYPE_KSTACK. If no such region can be found, - * NULL is returned instead. + * The pg_dir_get_kstack() function looks up the kernel-mode stack that is mapped into the page + * directory pointed to by `pgdir' and returns the linear address of that stack. This is done by + * iterating over all regions that are associated with the page directory, looking for the region + * whose type is REGION_TYPE_KSTACK. If no such region can be found, NULL is returned instead. * * RETURN VALUE * This function will return the linear address of the kernel-mode stack of the page @@ -811,15 +863,15 @@ void* pg_dir_get_kstack(struct pagedir *pgdir) * void *pg_dir_get_ustack(struct pagedir *pgdir); * * DESCRIPTION - * The pg_dir_get_ustack() function looks up the user-mode stack that is mapped into the - * page directory pointed to by `pgdir' and returns the virtual address of that stack. - * This is achieved by iterating over all regions that are associated with the page - * directory, looking for the region with type REGION_TYPE_STACK. If no such region could - * be found, NULL is returned instead. + * The pg_dir_get_ustack() function looks up the user-mode stack that is mapped into the page + * directory pointed to by `pgdir' and returns the virtual address of that stack. This is + * achieved by iterating over all regions that are associated with the page directory, looking + * for the region with type REGION_TYPE_STACK. If no such region could be found, NULL is + * returned instead. * * RETURN VALUE - * Upon success, the virtual address of the user-mode stack of the page directory is - * returned. Otherwise NULL is returned. + * Upon success, the virtual address of the user-mode stack of the page directory is returned. + * Otherwise NULL is returned. * * ERRORS * This function does not provide further information in case of an error. @@ -851,17 +903,16 @@ void* pg_dir_get_ustack(struct pagedir *pgdir) * void *pg_dir_get_ustack_top(struct pagedir *pgdir); * * DESCRIPTION - * The pg_dir_get_ustack_top() function looks up the user-mode stack that is mapped - * into the page directory pointed to by `pgdir' and returns the virtual address that - * is behind that stack (i.e. stack_base + stack_size). This is achieved by iterating - * over all regions that are associated with the page directory, looking for the - * region with type REGION_TYPE_STACK. If no such region could be found, NULL is - * returned in its stead. + * The pg_dir_get_ustack_top() function looks up the user-mode stack that is mapped into the + * page directory pointed to by `pgdir' and returns the virtual address that is behind that + * stack (i.e. stack_base + stack_size). This is achieved by iterating over all regions that + * are associated with the page directory, looking for the region with type REGION_TYPE_STACK. + * If no such region could be found, NULL is returned in its stead. * * RETURN VALUE - * Upon success, this function returns the address that is right behind the end of - * the user-mode stack of the page directory. If there is no user-mode stack mapped - * into the page directory, NULL is returned instead. + * Upon success, this function returns the address that is right behind the end of the user-mode + * stack of the page directory. If there is no user-mode stack mapped into the page directory, + * NULL is returned instead. * * ERRORS * This function does not provide additional information in case of an error. @@ -961,6 +1012,32 @@ gtfo: return(ret_val); } +/* + * pg_dir_memcpy() - Copy memory between virtual address spaces + * + * SYNOPSIS + * int pg_dir_memcpy(struct pagedir *ddir, void *dvaddr, + * struct pagedir *sdir, void *svaddr, + * u32_t bytes); + * + * DESCRIPTION + * The pg_dir_memcpy() function copies `bytes' bytes of data from the virtual address `svaddr' + * in the page directory pointed to by `sdir' to the virtual address `dvaddr' in the page + * directory pointed to by `ddir'. It is possible to pass NULL in `ddir' and `sdir'. In that + * case, the kernel page directory will be used as the source and/or destination page directory. + * This function does not map pages into the destination page directory if non-present pages are + * encountered during the copy operation. This situation will result in a partial copy. The + * caller should therefore check whether the return value is less than what had been passed in + * the `bytes' parameter. + * + * RETURN VALUE + * The number of bytes that have been successfully copied is returned. + * + * ERRORS + * This function does not return errors. However, a partial copy (including the case that 0 is + * returned) indicate that at least part of either the source or the destination range is not + * mapped into the respective page directory. + */ int pg_dir_memcpy(struct pagedir *ddir, void *dvaddr, struct pagedir *sdir, void *svaddr, u32_t bytes) {