]> git.corax.cc Git - corax/commitdiff
kernel/arch: Split _pg_dir_debug_arch() into three functions, add documentation for...
authorMatthias Kruk <m@m10k.eu>
Sat, 1 Aug 2020 17:06:35 +0000 (02:06 +0900)
committerMatthias Kruk <m@m10k.eu>
Sat, 1 Aug 2020 17:06:35 +0000 (02:06 +0900)
kernel/arch/paging.c

index b5f1f274c1448a22c15881bb08070a913d811e2f..373a294a8dd4510df12e40d8ad44d8b066cb1dbb 100644 (file)
@@ -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)
 {