*
* 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
}
/*
- * _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
* 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) */
/*
* 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
}
/*
- * _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
* 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;
}
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
* 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;
* 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
{
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)
#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;
* 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
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);
#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 */
/*
* 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);
* 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
* 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.
* 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.
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)
{