]> git.corax.cc Git - corax/commitdiff
kernel/arch: Add missing manpage-style comments to paging functions
authorMatthias Kruk <m@m10k.eu>
Sat, 8 Aug 2020 08:07:26 +0000 (17:07 +0900)
committerMatthias Kruk <m@m10k.eu>
Sat, 8 Aug 2020 08:07:26 +0000 (17:07 +0900)
kernel/arch/paging.c

index 1974e1c3e9eb07b7804fc2abe026c46137a3173d..08fafef71804e41489a25b7de1367ef99b8c09d1 100644 (file)
@@ -1073,6 +1073,29 @@ int pg_dir_memcpy(struct pagedir *ddir, void *dvaddr,
        return(ret_val);
 }
 
+/*
+ * _pg_dir_memset_page() - Call memset on a page in a different address space
+ *
+ * SYNOPSIS
+ *  int _pg_dir_memset_page(struct pagedior *ddir, void *dvaddr, int c, u32_t n);
+ *
+ * DESCRIPTION
+ *  The _pg_dir_memset_page() function sets `n' bytes from the address passed in `dvaddr' within
+ *  the page directory pointed to by `ddir' to the value passed in `c', and returns the number of
+ *  bytes that have been set. This function does not write over page boundaries, which means it
+ *  will write from `dvaddr' only to the end of the page. This means that this function may, in
+ *  the worst case, write no more than one byte. For that reason, this function should be called
+ *  in a loop, in order to make sure partial writes are accommodated for. In almost all cases,
+ *  this function should not be used directly, and pg_dir_memset() should be used in its stead.
+ *
+ * RETURN VALUE
+ *  On success, the number of bytes that have been set will be returned. Otherwise, a negative
+ *  error number will be returned.
+ *
+ * ERRORS
+ *  -EADDRNOTAVAIL The page at `dvattr' is not mapped in `ddir'
+ *  -ENOSYS        The current paging mode is not supported
+ */
 int _pg_dir_memset_page(struct pagedir *ddir, void *dvaddr, int c, u32_t n)
 {
        int ret_val;
@@ -1104,15 +1127,40 @@ gtfo:
        return(ret_val);
 }
 
-int pg_dir_memset(struct pagedir *ddir, void *dvaddr,
-                 int c, u32_t n)
+/*
+ * pg_dir_memset() - Call memset in a different address space
+ *
+ * SYNOPSIS
+ *  int pg_dir_memset(struct pagedir *ddir, void *dvaddr, int c, u32_t n);
+ *
+ * DESCRIPTION
+ *  The pg_dir_memset() function sets `n' bytes of memory starting at `dvaddr' within the page
+ *  directory pointed to by `ddir' to the value specified in `c' and returns the number of bytes
+ *  that have been written. The write operation is performed page-wise, as the virtual memory
+ *  region might not be continguous in physical memory.
+ *  This function does not map pages into the destination page directory, meaning that it will
+ *  stop if it encounters a non-present page. For that reason, the caller must check the return
+ *  value of this function if there is even a slight chance that the destination memory is not
+ *  mapped into the page directory.
+ *
+ * RETURN VALUE
+ *  The number of bytes written is returned.
+ *
+ * ERRORS
+ *  This function does not explicitly signal error conditions. However, if a partial write has
+ *  occured, the memory region was not (completely) mapped into the page directory.
+ */
+int pg_dir_memset(struct pagedir *ddir, void *dvaddr, int c, u32_t n)
 {
        int ret_val;
 
        ret_val = 0;
 
        if(!ddir) {
-               /* kernel pagedir - just call memset() */
+               /*
+                * Memory in the kernel page directory is continguous, which means that we can
+                * fulfill the entire request in a single swoop.
+                */
                memset(dvaddr, c, n);
                return((int)n);
        }
@@ -1135,6 +1183,30 @@ int pg_dir_memset(struct pagedir *ddir, void *dvaddr,
        return(ret_val);
 }
 
+/*
+ * _pg_dir_xfer() - Copy a page from one address space to another one
+ *
+ * SYNOPSIS
+ *  int _pg_dir_xfer(struct pagedir *ddir, void *dvaddr,
+ *                   struct pagedir *sdir, void *svaddr, u32_t bytes);
+ *
+ * DESCRIPTION
+ *  The _pg_dir_xfer() function copies the `bytes' of memory starting at `svaddr' in the page
+ *  directory pointed to by `sdir' to the memory pointed to by `dvaddr' within the page directory
+ *  pointed to by `ddir', and returns the number of bytes that have been copied.
+ *  This function does not read or write beyond page boundaries, which means that it will copy at
+ *  most the content of a single page, and may copy as little as a single byte.
+ *  This function should in most cases not be used directly, and the pg_dir_memcpy() function
+ *  should be used in its stead.
+ *
+ * RETURN VALUE
+ *  On success, the number of bytes that have been copied will be returned. Otherwise, a negative
+ *  error number will be returned.
+ *
+ * ERRORS
+ *  -EADDRNOTAVAIL Either the source or the destination addresses point to non-present pages
+ *  -ENOSYS        The current paging mode is not supported
+ */
 int _pg_dir_xfer(struct pagedir *ddir, void *dvaddr,
                 struct pagedir *sdir, void *svaddr, u32_t bytes)
 {
@@ -1221,6 +1293,27 @@ gtfo:
        return(ret_val);
 }
 
+/*
+ * _pg_dir_pagesize() - Get the size of a specific page in a page directory
+ *
+ * SYNOPSIS
+ *  int _pg_dir_pagesize(struct pagedir *pgdir, u32_t virt, u32_t *pagesize);
+ *
+ * DESCRIPTION
+ *  The _pg_dir_pagesize() function determines the size of the page pointed to by `virt' within
+ *  the page directory pointed to by `pgdir' and writes the result to the dword pointed to by
+ *  `pagesize'. This function is used within the kernel to determine the amount of data that can
+ *  be written to a specific address without crossing page boundaries, as the page management in
+ *  Corax allows pages of different sizes to be used within the same page directory.
+ *
+ * RETURN VALUE
+ *  On success, zero is returned. Otherwise, a negative error number is returned and the value
+ *  of `*pagesize' is left untouched.
+ *
+ * ERRORS
+ *  -EADDRNOTAVAIL The page pointed to by `virt' is not present in the page directory
+ *  -ENOSYS        The current paging mode is not supported
+ */
 int _pg_dir_pagesize(struct pagedir *pgdir, u32_t virt, u32_t *pagesize)
 {
        int ret_val;
@@ -1269,6 +1362,26 @@ int _pg_dir_pagesize(struct pagedir *pgdir, u32_t virt, u32_t *pagesize)
        return(ret_val);
 }
 
+/*
+ * _pg_dir_vpxlate() - Look up the corresponding physical address of a virtual address
+ *
+ * SYNOPSIS
+ *  int _pg_dir_vpxlate(struct pagedir *pgdir, u32_t virt, u32_t *phys);
+ *
+ * DESCRIPTION
+ *  The _pg_dir_vpxlate() performs a translation of the virtual address specified by `virt' within
+ *  the page directory pointed to by `pgdir' and writes the result to the dword pointed to by
+ *  `phys'. The translation works essentially the same way as the MMU would have done it, except
+ *  in software. This operation is potentially costly and should be used sparingly.
+ *
+ * RETURN VALUE
+ *  On success, zero is returned. Otherwise, a negative error number is returned and the value of
+ *  `*phys' is left untouched.
+ *
+ * ERRORS
+ *  -EFAULT The page pointed to by `virt' is non-present in the page directory
+ *  -ENOSYS The current paging mode is not supported
+ */
 int _pg_dir_vpxlate(struct pagedir *pgdir, u32_t virt, u32_t *phys)
 {
        int ret_val;
@@ -1320,6 +1433,28 @@ int _pg_dir_vpxlate(struct pagedir *pgdir, u32_t virt, u32_t *phys)
        return(ret_val);
 }
 
+/*
+ * _pg_dir_kstack_map() - Map a kernel-mode stack into a page directory
+ *
+ * SYNOPSIS
+ *  int _pg_dir_kstack_map(struct pagedir *pgdir);
+ *
+ * DESCRIPTION
+ *  The _pg_dir_kstack_map() function attempts to map a stack for kernel-mode execution into the
+ *  page directory pointed to by `pgdir'. This function also updates the state of the page
+ *  directory so that the newly mapped stack is used when an interrupt occurs during execution
+ *  within the page directory.
+ *  The kernel-mode stack will be mapped at the virtual address CONFIG_KERNEL_STACK_BASE within
+ *  the page directory. The stack will be mapped non-executable if supported by the processor and
+ *  configured to do so.
+ *
+ * RETURN VALUE
+ *  If successful, this function returns zero. Otherwise, a negative error number is returned and
+ *  the page directory is returned to its previous state.
+ *
+ * ERRORS
+ *  -ENOMEM The system ran out of memory while trying to map the stack
+ */
 int _pg_dir_kstack_map(struct pagedir *pgdir)
 {
        int ret_val;
@@ -1365,6 +1500,27 @@ cleanup:
        return(ret_val);
 }
 
+/*
+ * _pg_dir_ustack_map() - Map a stack for user-mode execution into a page directory
+ *
+ * SYNOPSIS
+ *  int _pg_dir_ustack_map(struct pagedir *pgdir);
+ *
+ * DESCRIPTION
+ *  The _pg_dir_ustack_map() function maps a stack for user-mode execution into the page directory
+ *  pointed to by `pgdir' and adjusts the internal state of the page directory so that the newly
+ *  allocated stack will be used upon a context switch to the page directory.
+ *  The user-mode stack will be mapped at the virtual address CONFIG_KERNEL_STACK_BASE - PAGE_SIZE
+ *  within the page directory. The stack will be made non-executable if supported by the processor
+ *  and configured to do so.
+ *
+ * RETURN VALUE
+ *  Opon success, zero is returned. Otherwise, a negative error number will be returned and the
+ *  page directory will be returned to its previous state.
+ *
+ * ERRORS
+ *  -ENOMEM The system ran out of memory trying to allocate the stack
+ */
 int _pg_dir_ustack_map(struct pagedir *pgdir)
 {
        int ret_val;
@@ -1378,7 +1534,8 @@ int _pg_dir_ustack_map(struct pagedir *pgdir)
                void* vaddr;
 
                vaddr = (void*)((u32_t)CONFIG_KERNEL_STACK_BASE - PAGE_SIZE);
-               attrs = PAGE_ATTR_PRESENT | PAGE_ATTR_WRITABLE | PAGE_ATTR_USER | PAGE_ATTR_NO_EXEC;
+               attrs = PAGE_ATTR_PRESENT | PAGE_ATTR_WRITABLE |
+                       PAGE_ATTR_USER | PAGE_ATTR_NO_EXEC;
 
                ret_val = pg_dir_map(pgdir, frame, vaddr, PAGE_SIZE, attrs);
 
@@ -1409,6 +1566,26 @@ cleanup:
        return(ret_val);
 }
 
+/*
+ * _pg_dir_heap_start() - Get the start address of page directory's heap
+ *
+ * SYNOPSIS
+ *  static void *_pg_dir_heap_start(pg_dir_t *pd);
+ *
+ * DESCRIPTION
+ *  The _pg_dir_heap_start() function returns the start address of the heap within the page
+ *  directory pointed to by `pd'. If there is no heap mapped into the page directory, the end of
+ *  the last memory section that is not a stack is returned instead (which is the address where
+ *  the heap will be, once it has been mapped).
+ *
+ * RETURN VALUE
+ *  Upon success, the virtual address of the heap will be returned (the heap may in fact not be
+ *  mapped yet, though). If the position of the heap could not be determined, (void*)-1 will be
+ *  returned instead.
+ *
+ * ERRORS
+ *  This function does not return further information in case of an error.
+ */
 static void* _pg_dir_heap_start(pg_dir_t *pd)
 {
        u32_t ret_val;
@@ -1451,6 +1628,27 @@ static void* _pg_dir_heap_start(pg_dir_t *pd)
        return((void*)ret_val);
 }
 
+/*
+ * _pg_dir_heap_map() - Map a heap into a page directory
+ *
+ * SYNOPSIS
+ *  static int _pg_dir_heap_map(pg_dir_t *pd, u32_t heap_size);
+ *
+ * DESCRIPTION
+ *  The _pg_dir_heap_map() function will map a heap of size `heap_size' into the page directory
+ *  pointed to by `pd'. The heap will be mapped non-executable if supported by the processor and
+ *  configured to do so. The heap will be placed after the last memory region that is not a stack.
+ *
+ * RETURN VALUE
+ *  Upon success, zero is returned. Otherwise, a negative error number is returned and the page
+ *  directory is returned to its previous state.
+ *
+ * ERRORS
+ *  -EINVAL   `pd' does not reference a valid page directory
+ *  -EALREADY The page directory already has a heap
+ *  -ENOMEM   Ran out of memory trying to allocate the heap
+ *  -EBADFD   The page directory is in an unusable state
+ */
 static int _pg_dir_heap_map(pg_dir_t *pd, u32_t heap_size)
 {
        /*
@@ -1485,6 +1683,9 @@ static int _pg_dir_heap_map(pg_dir_t *pd, u32_t heap_size)
 
                reg = pd->pd_regions[i];
 
+               dbg_printf("Found a region at 0x%08x:%08x\n",
+                          reg->reg_base, reg->reg_size);
+
                switch(reg->reg_type) {
                case REGION_TYPE_HEAP:
                        /* the page directory apparently already contains a heap */
@@ -1560,6 +1761,28 @@ gtfo:
        return(ret_val);
 }
 
+/*
+ * _clone_kernel_region() - Clone a memory region from the kernel page directory
+ *
+ * SYNOPSIS
+ *  int _clone_kernel_region(pg_dir_t *kdir, region_t *reg, void *data);
+ *
+ * DESCRIPTION
+ *  The _clone_kernel_region() function clones the memory region pointed to by `reg' from the
+ *  page directory pointed to by `kdir' into the page directory pointed to by `data'. This
+ *  function is called from pg_dir_create() by means of the pg_dir_foreach_region() function. As
+ *  such, it is not meant to be called directly.
+ *  If `reg' represents a .text, .bss, .data, or .rodata region, the region will be mapped
+ *  directly. This function does not actually clone the pages belonging to those memory regions,
+ *  as these pages cannot be modified outside of the kernel, and thus there is no need for copies
+ *  that are private to a process.
+ *
+ * RETURN VALUE
+ *  This function zero upon success, or a negative value if an error has occured.
+ *
+ * ERRORS
+ *  This function passes on errors returned by pg_dir_map_region().
+ */
 int _clone_kernel_region(pg_dir_t *kdir, region_t *reg, void *data)
 {
        pg_dir_t *dir;
@@ -1667,6 +1890,28 @@ int _clone_kernel_region(pg_dir_t *kdir, region_t *reg, void *data)
        return(ret_val);
 }
 
+/*
+ * pg_dir_create() - Create a new page directory
+ *
+ * SYNOPSIS
+ *  int pg_dir_create(pg_dir_t **dst);
+ *
+ * DESCRIPTION
+ *  The pg_dir_create() function allocates a new page directory and populates it with those memory
+ *  regions from the kernel that are necessary to make it usable. This function also maps stacks
+ *  for execution in user-mode and kernel-mode into the newly created page directory.
+ *
+ * RETURN VALUE
+ *  Upon success, this function returns zero, and the pointer pointed to by `dst' is adjusted to
+ *  point to the newly allocated page directory. Otherwise, this function returns a negative error
+ *  number, and the value of `*dst' is undefined.
+ *
+ * ERRORS
+ *  -ENOMEM There were no empty page frames to allocate the page directory
+ *  -EFAULT The system's paging mode is in an invalid state
+ *
+ *  This function also passes on errors from _pg_dir_kstack_map() and _pg_dir_ustack_map().
+ */
 int pg_dir_create(pg_dir_t **dst)
 {
        int ret_val;
@@ -1735,8 +1980,30 @@ int pg_dir_create(pg_dir_t **dst)
        return(ret_val);
 }
 
+/*
+ * _pg_dir_map_legacy() - Map memory into a legacy page directory
+ *
+ * SYNOPSIS
+ *  int _pg_dir_map_legacy(page_table_t *pd, u32_t paddr, u32_t vaddr,
+ *                         u32_t size, const page_attrs_t attrs);
+ *
+ * DESCRIPTION
+ *  The _pg_dir_map_legacy() function maps the `size' bytes of physical memory starting at `paddr'
+ *  to the virtual address `vaddr' in the page directory pointed to by `pd', applying the page
+ *  attributes specified in `attrs'.
+ *  If `paddr' is NULL, the physical location of the mapped memory depends on the available of
+ *  allocatable page frames in the system. In this case, the allocated memory may not be
+ *  continguous in physical memory. Unlike `paddr', `vaddr' may not be NULL.
+ *
+ * RETURN VALUE
+ *  This function returns zero upon success, or a negative error number in an error has occured.
+ *
+ * ERRORS
+ *  -ENOMEM   Not enough free page frames available to satisfy the allocation
+ *  -EALREADY The specified virtual memory is already (partially) mapped
+ */
 static int _pg_dir_map_legacy(page_table_t *pd, u32_t paddr, u32_t vaddr,
-                             u32_t size, const u32_t flags)
+                             u32_t size, const page_attrs_t attrs)
 {
        int ret_val;
 
@@ -1759,13 +2026,17 @@ static int _pg_dir_map_legacy(page_table_t *pd, u32_t paddr, u32_t vaddr,
                         */
                        if(size >= PAGE_SIZE_LARGE && ALIGNED(vaddr, PAGE_SIZE_LARGE) &&
                           paddr && ALIGNED(paddr, PAGE_SIZE_LARGE)) {
-                               pd->pt_entries[pde] = paddr | PAGE_ATTR_SIZE | PAGE_ATTR_PRESENT | flags;
+                               pd->pt_entries[pde] = paddr | PAGE_ATTR_SIZE |
+                                       PAGE_ATTR_PRESENT | attrs;
 
                                paddr += PAGE_SIZE_LARGE;
                                vaddr += PAGE_SIZE_LARGE;
                                size -= PAGE_SIZE_LARGE;
 
-                               /* skip the rest of the loop, which would attempt to populate the page table */
+                               /*
+                                * Skip the rest of the loop, which would attempt
+                                * to populate the page table
+                                */
                                continue;
                        } else {
                                pd->pt_entries[pde] = (u32_t)pg_frame_alloc_end();
@@ -1778,19 +2049,19 @@ static int _pg_dir_map_legacy(page_table_t *pd, u32_t paddr, u32_t vaddr,
                                        memset((void*)pd->pt_entries[pde], 0, PAGE_SIZE);
                                }
 
-                               pd->pt_entries[pde] |= PAGE_ATTR_PRESENT | flags;
+                               pd->pt_entries[pde] |= PAGE_ATTR_PRESENT | attrs;
                        }
                }
 
                pt = (page_table_t*)(pd->pt_entries[pde] & 0xfffff000);
 
                /* make sure PAGE_ATTR_USER is set on the page table, if necessary */
-               if(flags & PAGE_ATTR_USER) {
+               if(attrs & PAGE_ATTR_USER) {
                        pd->pt_entries[pde] |= PAGE_ATTR_USER;
                }
 
                /* also make sure the page table is writable, if necessary */
-               if(flags & PAGE_ATTR_WRITABLE) {
+               if(attrs & PAGE_ATTR_WRITABLE) {
                        pd->pt_entries[pde] |= PAGE_ATTR_WRITABLE;
                }
 
@@ -1813,8 +2084,7 @@ static int _pg_dir_map_legacy(page_table_t *pd, u32_t paddr, u32_t vaddr,
                        break;
                }
 
-               /* set the flags */
-               pt->pt_entries[pte] |= PAGE_ATTR_PRESENT | flags;
+               pt->pt_entries[pte] |= PAGE_ATTR_PRESENT | attrs;
 
                vaddr += PAGE_SIZE;
                size -= PAGE_SIZE;
@@ -1823,8 +2093,31 @@ static int _pg_dir_map_legacy(page_table_t *pd, u32_t paddr, u32_t vaddr,
        return(ret_val);
 }
 
+/*
+ * _pg_dir_map_pae() - Map pages into a PAE page directory
+ *
+ * SYNOPSIS
+ *  int _pg_dir_map_pae(pdpt_t *pd, u64_t paddr, u64_t vaddr,
+ *                      u32_t size, const page_attr_t attrs);
+ *
+ * DESCRIPTION
+ * The _pg_dir_map_pae() function maps the `size' bytes of physical memory starting at `paddr'
+ * to the virtual address `vaddr' in the page directory pointed to by `pd' and applies the page
+ * attributes in `attrs' to the newly mapped pages. If `paddr' is NULL, the physical addresses of
+ * the mapping depend on the availability of page frames in the system. In that case, the mapped
+ * memory is not guaranteed to be continguous in physical memory.
+ * This function will attempt to map the desired memory region using the largest possible page
+ * size that suits the passed parameters.
+ *
+ * RETURN VALUE
+ *  This function returns zero upon success, or a negative error number if an error has occured.
+ *
+ * ERRORS
+ *  -ENOMEM   Not enough free page frames available to satisfy the allocation
+ *  -EALREADY The specified virtual memory is already (partially) mapped
+ */
 static int _pg_dir_map_pae(pdpt_t *pd, u64_t paddr, u64_t vaddr,
-                          u32_t size, const u32_t flags)
+                          u32_t size, const page_attrs_t attrs)
 {
        int ret_val;
 
@@ -1867,7 +2160,7 @@ static int _pg_dir_map_pae(pdpt_t *pd, u64_t paddr, u64_t vaddr,
                }
 
                /* set the page attributes on the entry */
-               pt->ppt_entries[pte] |= PAGE_ATTR_PRESENT | flags;
+               pt->ppt_entries[pte] |= PAGE_ATTR_PRESENT | attrs;
 
                vaddr += PAGE_SIZE;
                paddr += PAGE_SIZE;
@@ -1877,8 +2170,32 @@ static int _pg_dir_map_pae(pdpt_t *pd, u64_t paddr, u64_t vaddr,
        return(ret_val);
 }
 
+/*
+ * pg_dir_map() - Map memory into a page directory
+ *
+ * SYNOPSIS
+ *  int pg_dir_map(pg_dir_t *pd, const void *phys, const void *virt,
+ *                 const u32_t size, const page_attrs_t attrs);
+ *
+ * DESCRIPTION
+ *  The pg_dir_map() function maps the `size' bytes of physical memory pointed to by `phys' to
+ *  the virtual address `virt' from the page directory pointed to by `pd', setting the page
+ *  attributes according to `attrs'. If `phys' is NULL, this function will use whatever page
+ *  frames are available for allocation, but they need not be continguous in memory. The value
+ *  passed in `virt' may not be NULL.
+ *  Depending on the paging mode configured in the kernel, this function will call either of the
+ *  _pg_dir_map_legacy() or _pg_dir_map_pae() functions to perform the actual mapping of the
+ *  pages.
+ *
+ * RETURN VALUE
+ *  This function returns zero upon success. Otherwise, a negative error number is returned.
+ *
+ * ERRORS
+ *  -ENOSYS The configured paging mode is not supported
+ *  -EFAULT The configured paging mode is invalid
+ */
 int pg_dir_map(pg_dir_t *pd, const void *phys, const void *virt,
-              const u32_t size, const u32_t flags)
+              const u32_t size, const page_attrs_t attrs)
 {
        int ret_val;
        u32_t asize;
@@ -1893,13 +2210,13 @@ int pg_dir_map(pg_dir_t *pd, const void *phys, const void *virt,
        case PG_MODE_LEGACY:
                ret_val = _pg_dir_map_legacy((struct page_table*)pd->pd_base,
                                             (u32_t)phys, (u32_t)virt,
-                                            asize, flags);
+                                            asize, attrs);
                break;
 
        case PG_MODE_PAE:
                ret_val = _pg_dir_map_pae((struct pdpt*)pd->pd_base,
                                          (unsigned)phys, (unsigned)virt,
-                                         asize, flags);
+                                         asize, attrs);
                break;
 
        case PG_MODE_IA32E:
@@ -1915,6 +2232,29 @@ int pg_dir_map(pg_dir_t *pd, const void *phys, const void *virt,
        return(ret_val);
 }
 
+/*
+ * pg_dir_map_region() - Map a memory region from one page directory into another one
+ *
+ * SYNOPSIS
+ *  int pg_dir_map_region(pg_dir_t *dpd, pg_dir_t *spd, region_t *reg);
+ *
+ * DESCRIPTION
+ *  The pg_dir_map_region() function maps the memory region pointed to by `reg' from the source
+ *  page directory `spd' to the destination page directory `dpd'.
+ *  The region will be mapped into the destination page directory with the same page flags as used
+ *  in the source page directory, unless the source page directory is the kernel page directory.
+ *  In the latter case, the pages will be mapped read-only into the destination page directory.
+ *
+ * RETURN VALUE
+ *  This function returns zero upon success, or a negative error number if an error has occured.
+ *
+ * ERRORS
+ *  -ERANGE The maximum number of regions has been mapped into the destination page directory
+ *  -EFAULT An unknown error (kernel bug) has occured
+ *
+ *  This function also passes on errors from the _pg_dir_vpxlate(), pg_dir_map(), and
+ *  _pg_dir_add_region() functions.
+ */
 int pg_dir_map_region(pg_dir_t *dpd, pg_dir_t *spd, region_t *reg)
 {
        int ret_val;
@@ -1991,6 +2331,25 @@ gtfo:
        return(ret_val);
 }
 
+/*
+ * pg_dir_clone_region() - Clone a memory region from one page directory into another one
+ *
+ * SYNOPSIS
+ *  int pg_dir_clone_region(pg_dir_t *dpd, pg_dir_t *spd, region_t *reg);
+ *
+ * DESCRIPTION
+ *  The pg_dir_clone_region() function creates a copy of the memory region pointed to by `reg'
+ *  from the source page directory `spd' and maps the copy into the destination page directory
+ *  `dpd'. The memory region will be mapped with the same page attributes into the destination
+ *  page directory, with the exception that PAGE_ATTR_USER will be added where necessary.
+ *
+ * RETURN VALUE
+ *  -ERANGE The maximum number of regions has been mapped into the destination page directory
+ *  -EFAULT An unknown error (kernel bug) has occured
+ *
+ *  This function also passes on errors from the pg_dir_map(), pg_dir_memcpy(), and
+ *  _pg_dir_add_region() functions.
+ */
 int pg_dir_clone_region(pg_dir_t *dpd, pg_dir_t *spd, region_t *reg)
 {
        int ret_val;
@@ -2039,11 +2398,49 @@ gtfo:
        return(ret_val);
 }
 
+/*
+ * pg_dir_unmap() - Release a memory mapping from a page directory
+ *
+ * SYNOPSIS
+ *  int pg_dir_unmap(pg_dir_t *pd, const void *base, const u32_t size);
+ *
+ * DESCRIPTION
+ *  The pg_dir_unmap() function releases `size' bytes of memory starting at the virtual address
+ *  `base' from the page directory pointed to by `pd'. This function is currently not implemented.
+ *
+ * RETURN VALUE
+ *  This function returns zero upon success, otherwise a negative error number is returned.
+ *
+ * ERRORS
+ *  -ENOSYS The function is not implemented
+ */
 int pg_dir_unmap(pg_dir_t *pd, const void *base, const u32_t size)
 {
        return(-ENOSYS);
 }
 
+/*
+ * pg_dir_foreach_region() - Execute a function on all memory regions in a page directory
+ *
+ * SYNOPSIS
+ *  int pg_dir_foreach_region(pg_dir_t *pd, int (*func)(pg_dir_t*, region_t*, void*), void *data);
+ *
+ * DESCRIPTION
+ *  The pg_dir_foreach_region() iterates over the memory regions in the page directory pointed to
+ *  by `pd' and calls the function pointed to by `func' on each one of them. The function pointed
+ *  to by `func' must accept three arguments; the first one is a pointer to the page directory,
+ *  the second one is a pointer to the memory region, the third value passed to the function is
+ *  the value that was passed to pg_dir_foreach_region() in the `data' parameter.
+ *  If the function pointed to by `func' returns a negative value, pg_dir_foreach_region() will
+ *  interrupt the iteration early.
+ *
+ * RETURN VALUE
+ *  This function will return the value that was returned by the last call to `func'. If an error
+ *  has occured, a negative error number will be returned.
+ *
+ * ERRORS
+ *  -EINVAL `pd' or `func' point to an invalid value
+ */
 int pg_dir_foreach_region(pg_dir_t *pd, int (*func)(pg_dir_t*, region_t*, void*), void *data)
 {
        int ret_val;
@@ -2071,6 +2468,31 @@ int pg_dir_foreach_region(pg_dir_t *pd, int (*func)(pg_dir_t*, region_t*, void*)
        return(ret_val);
 }
 
+/*
+ * _pg_dir_add_region() - Add a region to a page directory
+ *
+ * SYNOPSIS
+ *  int _pg_dir_add_region(pg_dir_t *pd, void *base, u32_t size, const region_type_t type,
+ *                         const page_attrs_t attrs, const region_opts_t opts);
+ *
+ * DESCRIPTION
+ *  The _pg_dir_add_region() function adds a region with the specified parameters to the page
+ *  directory pointed to by `pd'. A region is a data structure used purely for accounting
+ *  purposes. This call will not modify the paging structures referenced by the page directory.
+ *  The values passed in `base' and `size' represent the base address of the memory region, and
+ *  the regions size in bytes, respectively. The value of `type' determines the type of region
+ *  that the memory represents. The `attrs' argument determines the page attributes that are used
+ *  for pages within this region. The value in `opts' is used to determine if this region is
+ *  private to this page directory, or if it may be shared.
+ *
+ * RETURN VALUE
+ *  On success, this function returns zero. Otherwise, a negative error number is returned.
+ *
+ * ERRORS
+ *  -EFAULT An unknown error (kernel bug) has occured
+ *  -ERANGE The maximum number of regions has been mapped into the destination page directory
+ *  -ENOMEM The kernel ran out of heap space
+ */
 static int _pg_dir_add_region(pg_dir_t *pd, void *base, u32_t size,
                              region_type_t type, page_attrs_t attrs, region_opts_t opts)
 {
@@ -2115,11 +2537,49 @@ gtfo:
        return(ret_val);
 }
 
+/*
+ * pg_dir_get_pdbr() - Get the base address of a page directory
+ *
+ * SYNOPSIS
+ *  void *pg_dir_get_pdbr(pg_dir_t *pd);
+ *
+ * DESCRIPTION
+ *  The pg_dir_get_pdbr() function returns the base address of the page directory pointed to by
+ *  `pd'. The return value may be used in assigments to the page directory base register (also
+ *  known as CR3 on IA-32/Intel64).
+ *
+ * RETURN VALUE
+ *  The value of the variable keeping track of the PDBR within the page directory structure is
+ *  returned by this function. This function does not perform any checks to ensure the validity
+ *  of that value.
+ *
+ * ERRORS
+ *  This function does not signal any error conditions.
+ */
 void* pg_dir_get_pdbr(pg_dir_t *pd)
 {
        return(pd->pd_base);
 }
 
+/*
+ * pg_dir_get_heap() - Get the virtual address of a page directory's heap
+ *
+ * SYNOPSIS
+ *  void *pg_dir_get_heap(pg_dir_t *pd);
+ *
+ * DESCRIPTION
+ *  The pg_dir_get_heap() function returns the virtual address of the heap that is mapped into the
+ *  page directory pointed to by `pd'. This is done by iterating over all memory regions that are
+ *  associated with the page directory, returning the base address of the region with type
+ *  REGION_TYPE_HEAP.
+ *
+ * RETURN VALUE
+ *  Upon success, the virtual base address of the heap is returned. If there is no heap mapped
+ *  into the page directory, NULL will be returned instead.
+ *
+ * ERRORS
+ *  This function does not convey any additional information about errors.
+ */
 void* pg_dir_get_heap(pg_dir_t *pd)
 {
        void *ret_val;
@@ -2135,6 +2595,29 @@ void* pg_dir_get_heap(pg_dir_t *pd)
        return(ret_val);
 }
 
+/*
+ * pg_dir_sbrk() - Change the size of a page directory's heap
+ *
+ * SYNOPSIS
+ *  void *pg_dir_sbrk(pg_dir_t *pd, u32_t increment);
+ *
+ * DESCRIPTION
+ *  The pg_dir_sbrk() function manipulates the size of the heap that is mapped into the page
+ *  directory pointed to by `pd'. If `increment' is positive, the size of the heap will be
+ *  increased by `increment' bytes by increasing the limit of the heap. If `increment' is
+ *  negative, the limit of the size will be decreased by `-increment', shrinking the heap.
+ *  If the value of `increment' is zero, The end of the heap will be returned without modifying
+ *  its position.
+ *  If there is no heap mapped into the page directory, this function will return the address
+ *  where the heap will be mapped if this function is called with a positive `increment' value.
+ *
+ * RETURN VALUE
+ *  Upon success, the address of the end of the heap (that is, the address right behind the heap)
+ *  is returned.
+ *
+ * ERRORS
+ *  This function does not signal information about errors.
+ */
 void* pg_dir_sbrk(pg_dir_t *pd, i32_t increment)
 {
        struct region *heap;
@@ -2180,6 +2663,7 @@ void* pg_dir_sbrk(pg_dir_t *pd, i32_t increment)
                        return(pg_dir_sbrk(pd, 0));
                } else {
                        /* could not map a heap - how do we get the error to the caller? */
+                       dbg_printf("Kernel says no. (_pg_dir_heap_map() says %u)\n", -err);
                        return(NULL);
                }
        } else {
@@ -2222,6 +2706,25 @@ void* pg_dir_sbrk(pg_dir_t *pd, i32_t increment)
        return(ret_val);
 }
 
+/*
+ * pg_fault_debug() - Print page table entries for an address
+ *
+ * SYNOPSIS
+ *  void pg_fault_debug(pg_dir_t *pdir, void *addr);
+ *
+ * DESCRIPTION
+ *  The pg_fault_debug() function prints the page table entries for the virtual address `addr'
+ *  within the page directory pointed to by `pdir'. This function will perform the page table
+ *  lookup as it would be done by the MMU and print the encountered entries to the kernel's debug
+ *  output.
+ *  This function is currently only implemented for legacy IA-32 paging.
+ *
+ * RETURN VALUE
+ *  void
+ *
+ * ERRORS
+ *  This function does not return errors.
+ */
 void pg_fault_debug(pg_dir_t *pdir, void *addr)
 {
        u64_t pde;
@@ -2256,6 +2759,47 @@ void pg_fault_debug(pg_dir_t *pdir, void *addr)
        return;
 }
 
+/*
+ * pg_dir_mmap() - Map various kinds of memory into a page directory
+ *
+ * SYNOPSIS
+ *  int pg_dir_mmap(pg_dir_t *pgdir, void *addr, u32_t size, int prot, int flags, void **dst);
+ *
+ * DESCRITION
+ *  The pg_dir_mmap() function maps memory into the page directory pointed to by `pgdir' according
+ *  to the values specified in the remaining parameters. The function will attempt to create the
+ *  mapping at the virtual address `addr'. The mapping will be created from arbitrary free page
+ *  frames, meaning that they may not be continguous in physical memory.
+ *  If the MAP_PHYS flag is set in `flags', this function will attempt to create an identity
+ *  mapping to physical memory, thus allowing the calling process to map device memory into their
+ *  address space.
+ *
+ *  The attributes of the pages in the region will be set according to `prot':
+ *   - If the PROT_EXEC bit is set, the pages will be made executable
+ *   - If the PROT_WRITE bit is set, the pages will be made writable
+ *   - If the PROT_READ bit is set, the pages will be made readable
+ *
+ *  Note that, in absense of the PROT_READ bit, the pages will not be accessible from non-kernel
+ *  contexts at all, so this bit should almost always be set.
+ *
+ *  The visibility of the mapping is further influenced by the value of `opts':
+ *   - If `opts' is REGION_OPT_SHARED, the physical memory may be shared with other processes,
+ *   - otherwise the memory region will be private and not shareable with other processes.
+ *   - However, mappings made with the MAP_PHYS flag cannot be made private.
+ *
+ *  If the mapping has been successful, the pointer pointed to by `dst' will be made to point to
+ *  the virtual address of the mapping.
+ *
+ * RETURN VALUE
+ *  This function will return zero upon success, or a negative error number in the case that an
+ *  error has occured. In the latter case, the value of `*dst' is undefined.
+ *
+ * ERRORS
+ *  -EINVAL Either `pgdir' or `dst' are invalid pointers
+ *  -EFAULT An unknown error (kernel bug) has occured
+ *
+ *  This function also passes on error values returned by pg_dir_map() and _pg_dir_add_region().
+ */
 int pg_dir_mmap(pg_dir_t *pgdir, void *addr, u32_t size,
                int prot, int flags, void **dst)
 {
@@ -2316,6 +2860,7 @@ int pg_dir_mmap(pg_dir_t *pgdir, void *addr, u32_t size,
 
                        /* or unmap if it can't be accounted for */
                        if(ret_val < 0) {
+                               dbg_printf("...and unmapping again\n");
                                pg_dir_unmap(pgdir, addr, size);
                        }
                }
@@ -2331,6 +2876,25 @@ int pg_dir_mmap(pg_dir_t *pgdir, void *addr, u32_t size,
        return(ret_val);
 }
 
+/*
+ * pg_dir_munmap() - Release a mapping made by pg_dir_mmap()
+ *
+ * SYNOPSIS
+ *  int pg_dir_munmap(pg_dir_t *pgdir, void *addr, u32_t size);
+ *
+ * DESCRIPTION
+ *  The pg_dir_munmap() function releases the `size' bytes of memory mapped at the virtual address
+ *  `addr' inside the page directory pointed to by `pgdir'. This function is the inverse function
+ *  of pg_dir_mmap().
+ *
+ *  This function is currently not implemented.
+ *
+ * RETURN VALUE
+ *  This function returns zero upon success, or a negative error number if an error has occured.
+ *
+ * ERRORS
+ *  -ENOSYS The function is not implemented
+ */
 int pg_dir_munmap(pg_dir_t *pgdir, void *addr, u32_t size)
 {
        return(-ENOSYS);