]> git.corax.cc Git - corax/commitdiff
kernel/arch: Move computation of the end of usable memory into a separate function...
authorMatthias Kruk <m@m10k.eu>
Sat, 1 Aug 2020 07:36:18 +0000 (16:36 +0900)
committerMatthias Kruk <m@m10k.eu>
Sat, 1 Aug 2020 08:08:44 +0000 (17:08 +0900)
 * 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()

kernel/arch/paging.c

index d0eb3c4202393ea48766ec499d23f8ad6a311abb..bf611a0b25ba3b7eecdc75d1739b4999eda06c80 100644 (file)
@@ -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);