Chapter 28
(X86)NetBSD UVM: liboskit_netbsd_uvm.a

28.1 Introduction

The NetBSD UVM library provides real virtual memory support including separation of address spaces, demand paging, memory mapped file, memory protection, and so on. This library is based on NetBSD’s new virtual memory system UVM (see http://www.netbsd.org/Documentation/kernel/uvm.html). Since this library is derived from a virtual memory system for UNIX, the services provided are almost the same as for a traditional UNIX virtual memory system. With the UVM library, applications are able to manage multiple user address spaces and map them onto CPU’s virtual address space. Also, applications can allocate more memory than there is physical memory available on machines where a disk swap partition is available.

Although the UVM library provides a method to separate kernel and user address space, it does not offer a way to switch between user and kernel mode. Such functions are separately provided by the Simple Process Library (See Section 30).

The UVM library depends on the OSKit’s POSIX Threads library (See Section 29). The UVM library is thread safe, multiple threads can manipulate the same user address space.

28.2 Restrictions

Currently only the x86 implementation is available but it will be not difficult to port to another architecture where NetBSD has already ported.

The x86 LDT (Local Descriptor Table) is not supported.

No single threaded implementation is provided.

28.3 Virtual Address Space Layout

The address space layout is shown in figure 28.1. Since UVM was originally designed for UNIX, the address space layout is similar to traditional UNIXes; virtual address spaces are separated into two regions, the kernel and user regions. The same kernel image appears in every virtual address space and only one user address space can be mapped in the user region. Unlike NetBSD, the kernel does not reside at higher addresses but remains at its loaded address. The user region is above the kernel region. The base address of a user address space is fixed at 0x40000000. A thread running in kernel mode (CPL (Current Privilege Level < 3) can access both the kernel and the user region and a thread running in user mode (CPL=3) can access only the user region.

At the initialization of the UVM library, all physical memory (0 to phys_max_lmm) are mapped as V = R (virtual address = real (physical) address). The kernel pages are changed to read-only but all other pages in the V = R range are left read-write since the OSKit LMM library needs write access. A stack redzone is also created, although stack overflows are currently fatal since there is not enough support to allow recovery.

The kernel heap area used for memory allocation (See Section 28.4) starts at 0x30000000. The area 0x3f800000 to 0x3fffffff is used by the UVM internally for page table manipulation.


 /*
  *  +---------------+ 0x00000000 (OSKIT_UVM_MIN_KERNEL_ADDRESS)     --+    ---+
  *  |               |                                                 |       |
  *  +---------------+                                                 |       |
  *  | OSKit Kernel  |                                                 |       |
  *  +---------------+                                                 | V=R   |
  *  |  BMODs etc.   |                                                 | range |
  *  +---------------+ ?                                               |       |
  *  |               |                                                 |       |
  *  +---------------+            (phys_max_lmm)                     --+       |
  *  |    unused     |                                                         | kernel
  *  +---------------+ 0x30000000 (OSKIT_UVM_MIN_KERNEL_VIRTUAL_AVAIL)         | region
  *  |  Kernel heap  |                                                         |
  *  +---------------+ (grows upward)                                          |
  *  |               |                                                         |
  *  +---------------+ 0x3f800000                                              |
  *  | Recursive PTE |                                                         |
  *  +---------------+ 0x3fc00000                                              |
  *  | Alternative   |                                                         |
  *  | Recursive PTE |                                                         |
  *  +---------------+ 0x40000000 (OSKIT_UVM_MINUSER_ADDRESS)               ---+
  *  |               |                                                         | user
  *  | User Process  |                                                         | region
  *  |               |                                                         |
  *  +---------------+ 0xffffffff (OSKIT_UVM_MAXUSER_ADDRESS)               ---+
  */
Symbols starting with OSKIT_UVM_ are defined in <oskit/uvm.h>.
Figure 28.1: UVM Address Space Layout

28.4 Memory Interface

The UVM library also provides an implementation of the oskit_mem COM interface (See Section 13.4). This implementation allocates memory from the kernel heap area described above. The kernel heap area can grow automatically and might be paged out. This interface will be the default memory allocator if the UVM library is used and thus, the default malloc implementation uses this interface.

There are some restrictions with this implementation of the oskit_mem interface:

Also, the UVM library provides the following osenv_mem_* APIs for the OSKit device driver framework (See Section 8).

28.5 Threads

With the UVM library, all threads are associated with a particular virtual address space. Initially all threads are associated with the kernel-only virtual address space, which maps only the kernel area. oskit_uvm_vmspace_set associates a calling thread with a specified virtual address space. Once such an association is made, that virtual address space is used for all memory access from the thread.

28.6 Page Faults

All page faults are processed by the page fault handler (oskit_uvm_pfault_handler). The page fault handler runs using the context of the thread that caused the page fault. If a page fault is processed successfully, the context of the thread that caused the page fault is automatically restored. In case of an error such as a page protection violation or an invalid memory access, the application’s handler is called if one was installed with oskit_uvm_handler_set. Otherwise, the SIGSEGV or SIGKILL signal is raised by oskit_sendsig.

The signature of an application fault handler is as follows:

 typedef void    (*oskit_uvm_handler)(struct oskit_vmspace *vm,
                                      int signo, struct trap_state *frame);
where
vm
The virtual address space in which the page fault occurred.
signo
A UNIX signal number. Normally, the value will be SIGSEGV, but it might also be SIGKILL in the case of a memory resource shortage. This is hint only.
frame
A pointer to the stack frame of the page fault handler.

A page fault handler should either map a page of memory at the indicated virtual address or terminate the thread which caused the page fault.

28.7 Virtual memory system calls

The UVM library provides implementations of the mmap, munmap, mprotect, and madvise system calls.

28.8 API reference

28.8.1 oskit_uvm_init: initialize the UVM library

SYNOPSIS

#include <oskit/uvm.h>

void oskit_uvm_init(void);

DESCRIPTION

Initialize the UVM library. It does:

This function must be called after pthread_init but before any other threads have been created. This is because the OSKit UVM library associates information with every thread and currently the implementation relies on that information being set before the thread starts.

28.8.2 oskit_uvm_swap_init: Initialize the swap subsystem

SYNOPSIS

#include <oskit/uvm.h>

void oskit_uvm_swap_init(void);

DESCRIPTION

Initialize the swap subsystem. This function must be called before calling oskit_uvm_swap_on.

RELATED INFORMATION

oskit_uvm_swap_on, oskit_uvm_swap_off

28.8.3 oskit_uvm_swap_on: Add a swap area

SYNOPSIS

#include <oskit/uvm.h>

oskit_error_t oskit_uvm_swap_on(oskit_iunknown_t *iunknown);

DESCRIPTION

Add a swap area. Multiple such areas are possible.

PARAMETERS
iunknown:
An oskit_absio_t * or oskit_blkio_t * that is suitable for use as the swap area. This object should not be accessed directly while the UVM system is active.
RELATED INFORMATION

oskit_uvm_swap_init, oskit_uvm_swap_off, swapon

28.8.4 oskit_uvm_swap_off: Remove a swap area

SYNOPSIS

#include <oskit/uvm.h>

oskit_error_t oskit_uvm_swap_off(oskit_iunknown_t *iunknown);

DESCRIPTION

Remove a swap area. Currently this function is broken due to a bug in the NetBSD code on which this library is based.

RELATED INFORMATION

oskit_uvm_swap_init, oskit_uvm_swap_on, swapoff

28.8.5 oskit_uvm_start_pagedaemon: start the pagedaemon

SYNOPSIS

#include <oskit/uvm.h>

void oskit_uvm_start_pagedaemon(void);

DESCRIPTION

Start the page daemon thread. Must be called after calling oskit_uvm_swap_init.

RELATED INFORMATION

oskit_uvm_swap_init

28.8.6 oskit_uvm_create: Create a virtual address space

SYNOPSIS

#include <oskit/uvm.h>

oskit_error_t oskit_uvm_create(oskit_size_t size, [out] oskit_vmspace_t *out_vm);

DESCRIPTION

Create a virtual address space. The virtual address space information is stored in the opaque oskit_vmspace_t structure which is defined in <oskit/uvm.h>. This function does not map the created address space as the current address space. Use oskit_uvm_vmspace_set to access the created virtual address space.

PARAMETERS
size:
The size of the address space in bytes.
out_vm:
A pointer to where the created oskit_vmspace_t is stored. Caller must allocate the memory for that oskit_vmspace_t structure.
RELATED INFORMATION

oskit_uvm_destroy

28.8.7 oskit_uvm_destroy: Destroy a virtual address space

SYNOPSIS

#include <oskit/uvm.h>

oskit_error_t oskit_uvm_destroy(oskit_vmspace_t vm);

DESCRIPTION

Destroy a virtual address space. No thread must be associated with the specified virtual address space.

RELATED INFORMATION

oskit_uvm_create

28.8.8 oskit_uvm_mmap: Map an object into memory

SYNOPSIS

#include <oskit/uvm.h>

oskit_error_t oskit_uvm_mmap(oskit_vmspace_t vm, [in/out] oskit_addr_t *addr, oskit_size_t size, int prot, int flags, oskit_iunknown_t *iunknown, oskit_off_t foff);

DESCRIPTION

Map an object into a virtual address space. This is similar to mmap but allows the virtual address space affected to be explicitly specified.

PARAMETERS
vm:
The virtual address space to be used for this operation.
addr:
On entry, the value pointed to by this parameter is the the preferable virtual address to map. Must be a multiple of the page size. This is a hint only and can be specified as zero. On return, it contains the start address of the mapped object.
size:
The length to map. Must be a multiple of the page size.
prot:
The desired memory protection. Bitwise combination of PROT_EXEC, PROT_READ, PROT_WRITE or PROT_NONE.
flags:
Specifies the type of the mapped object.
MAP_FIXED
Must use the specified address exactly.
MAP_SHARED
Writes change the underlying object; modifications are shared.
MAP_PRIVATE
Writes only change our mapping; modifications are private.
MAP_ANON
Maps anonymous memory not associated with any specific object. The iunknown parameter may be specified as NULL.
iunknown:
An oskit_absio_t * or oskit_blkio_t * object to map. The object reference is added by the UVM. In the case of multiple threads accessing the same mapped object, iunknown must be a properly wrapped object (see Section 29.5).
foff :
The offset of the object to map. Must be a multiple of the page size.
RETURNS

Returns 0 on success, or an error code specified in #include <oskit/errno.h>, on error.

RELATED INFORMATION

oskit_uvm_munmap

28.8.9 oskit_uvm_unmap: Remove a mapping

SYNOPSIS

#include <oskit/uvm.h>

oskit_error_t oskit_uvm_munmap(oskit_vmspace_t vm, oskit_addr_t addr, oskit_size_t len);

DESCRIPTION

Deletes the mapping of the specified address range from the given address space. Causes further references to addresses within the range to generate invalid memory references.

PARAMETERS
vm:
The virtual address space to be used for this operation.
addr:
The base address of the region to unmap. Must be a multiple of the page size.
len:
The length to unmap. Must be a multiple of the page size.
RETURNS

Returns 0 on success, or an error code specified in #include <oskit/errno.h>, on error.

RELATED INFORMATION

oskit_uvm_mmap

28.8.10 oskit_uvm_mprotect: Control the protection of pages

SYNOPSIS

#include <oskit/uvm.h>

oskit_error_t oskit_uvm_mprotect(oskit_vmspace_t vm, oskit_addr_t addr, oskit_size_t len, int prot);

DESCRIPTION

Changes the specified pages to have protection prot.

PARAMETERS
vm:
The virtual address space to be used for this operation.
addr:
The base address of the region. Must be a multiple of the page size.
size:
The length of the region. Must be a multiple of the page size.
prot:
The desired memory protection.
RETURNS

Returns 0 on success, or an error code specified in #include <oskit/errno.h>, on error.

RELATED INFORMATION

oskit_uvm_mmap

28.8.11 oskit_uvm_madvise: Give advise about use of memory

SYNOPSIS

#include <oskit/uvm.h>

oskit_error_t oskit_uvm_madvise(struct oskit_vmspace *vm, oskit_addr_t addr, oskit_size_t len, int behav);

DESCRIPTION

Gives the UVM a hint of the memory access behavior of the application. Known behaviors are given in #include <oskit/c/sys/mman.h>:

 #define MADV_NORMAL     0       /* no further special treatment */
 #define MADV_RANDOM     1       /* expect random page references */
 #define MADV_SEQUENTIAL 2       /* expect sequential page references */
 #define MADV_WILLNEED   3       /* will need these pages */
 #define MADV_DONTNEED   4       /* dont need these pages */
 #define MADV_SPACEAVAIL 5       /* insure that resources are reserved */
 #define MADV_FREE       6       /* pages are empty, free them */
RETURNS

Returns 0 on success, or an error code specified in #include <oskit/errno.h>, on error.

28.8.12 oskit_uvm_vmspace_set: Associate a thread with a virtual address space

SYNOPSIS

#include <oskit/uvm.h>

oskit_vmspace_t oskit_uvm_vmspace_set(oskit_vmspace_t vm); oskit_vmspace_t oskit_uvm_kvmspace;

DESCRIPTION

Associate the calling thread with specified virtual memory space. Once a thread is associated, all memory accesses from the thread refer to the associated virtual address space. Initially all threads are associated with the virtual address space oskit_uvm_kvmspace which maps the kernel region only.

RETURNS

Returns the previous virtual address space associated with the calling thread.

RELATED INFORMATION

oskit_uvm_vmspace_get

28.8.13 oskit_uvm_vmspace_get: Get the virtual address space associated with a thread

SYNOPSIS

#include <oskit/uvm.h>

oskit_vmspace_t oskit_uvm_vmspace_get(void);

DESCRIPTION

Obtain the virtual address space associated with the calling thread.

RETURNS

Returns the virtual address space associated with the calling thread.

RELATED INFORMATION

oskit_uvm_vmspace_set

28.8.14 copyin: Copy a range of data from user to kernel

SYNOPSIS

#include <oskit/uvm.h>

oskit_error_t copyin(const void *from, void *to, oskit_size_t len);

DESCRIPTION

Copy data from a user address space into the kernel address space if allowed by the current memory protection bits. The entire source memory region specified by from and len must be accessible for read by the current thread’s address space.

PARAMETERS
from:
User-space virtual address to copy from.
to:
Kernel-space virtual address to copy into.
len:
Length of data to copy.
RETURNS

Returns 0 on success, OSKIT_E_POINTER if the user memory region is not accessible.

28.8.15 copyinstr: Copy a string from user to kernel

SYNOPSIS

#include <oskit/uvm.h>

oskit_error_t copyinstr(const void *from, void *to, oskit_size_t len, [out] oskit_size_t *lencopied);

DESCRIPTION

Copy a zero-terminated string of at most len bytes from a user address space into the kernel address space if allowed by the current memory protection bits. The source string specified by from must be accessible for read by the current thread’s address space.

PARAMETERS
from:
User-space virtual address to copy from.
to:
Kernel-space virtual address to copy into.
len:
Maximum bytes to copy.
lencopied:
Actual length of string copied, including terminating zero.
RETURNS

Returns 0 on success, OSKIT_E_POINTER if the user memory region is not accessible.

28.8.16 copyout: Copy a range of data from kernel to user

SYNOPSIS

#include <oskit/uvm.h>

oskit_error_t copyout(const void *from, void *to, oskit_size_t len);

DESCRIPTION

Copy data from the kernel address space into a user address space if allowed by the current memory protection bits. The entire destination memory region specified by to and len must be accessible for write by the current thread’s address space.

PARAMETERS
from:
Kernel-space virtual address to copy from.
to:
User-space virtual address to copy into.
len:
Length of data to copy.
RETURNS

Returns 0 on success, OSKIT_E_POINTER if the user memory region is not accessible.

28.8.17 copyinstr: Copy a string from kernel to user

SYNOPSIS

#include <oskit/uvm.h>

oskit_error_t copyoutstr(const void *from, void *to, oskit_size_t len, [out] oskit_size_t *lencopied);

DESCRIPTION

Copy a zero-terminated string of at most len bytes from the kernel address space into a user address space if allowed by the current memory protection bits. The destination string memory specified by to must be accessible for write by the current thread’s address space.

PARAMETERS
from:
Kernel-space virtual address to copy from.
to:
User-space virtual address to copy into.
len:
Maximum bytes to copy.
lencopied:
Actual length of string copied, including terminating zero.
RETURNS

Returns 0 on success, OSKIT_E_POINTER if the user memory region is not accessible.

28.8.18 oskit_uvm_mem_map_phys: Map a physical memory range into a virtual address space

SYNOPSIS

#include <oskit/uvm.h>

int oskit_uvm_mem_map_phys(oskit_addr_t pa, oskit_size_t size, void **addr, int flags);

DESCRIPTION

Map the specified physical memory range into a virtual address space. This call is exactly the same as osenv_mem_map_phys.

PARAMETERS
pa:
Starting physical address.
length:
Amount of memory to map.
kaddr:
Kernel virtual address allocated and returned by the kernel that maps the specified memory.
flags:
Memory mapping attributes, as described above.
RETURNS

Returns 0 on success, non-zero on error.

RELATED INFORMATION

osenv_mem_map_phys

28.8.19 oskit_handler_set: Install a fault handler

SYNOPSIS

#include <oskit/uvm.h>

void oskit_uvm_handler_set(oskit_vmspace_t vm, oskit_uvm_handler handler);

DESCRIPTION

Install a handler that is called when the default page fault handler fails. See Section 28.6.

PARAMETERS
vm:
The virtual address space where the handler is installed.
handler:
The pointer to the handler.
RELATED INFORMATION

oskit_uvm_handler_get

28.8.20 oskit_uvm_handler_get: Get the fault handler for an address space

SYNOPSIS

#include <oskit/uvm.h>

oskit_uvm_handler oskit_uvm_handler_get(oskit_vmspace_t vm);

DESCRIPTION

Obtain the handler installed for the specified virtual address space.

RELATED INFORMATION

oskit_uvm_handler_set

28.8.21 oskit_uvm_csw_hook_set: Install a context switch hook

SYNOPSIS

#include <oskit/uvm.h>

void oskit_uvm_csw_hook_set(void (*hook)(void));

DESCRIPTION

Install a hook that is called on every context switch. This API is intended to be used from the Simple Process Library.

PARAMETERS
hook:
A pointer to the hook function.