#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;
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) {
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]);
}
}
}
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)) {
}
#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;
* 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);