Mac OS X Internals: A Systems Approach
8.8. Kernel and User Address Space Layouts
The Mac OS X kernel has a 32-bit virtual address space whether it runs on a 32-bit or 64-bit machine. Beginning with Mac OS X 10.4, it is possible to create 64-bit user programs, although very few user-space APIs are available in 64-bit versions. On some systems, a portion of every user address space is reserved for use by the kernel. For example, on 32-bit Windows, a user process is given the lower 2GB[14] of its 4GB virtual address space for private use. The remaining 2GB is used by the operating system. Similarly, the Linux kernel divides a 4GB user address space into two parts. The operating system uses its portion by mapping the kernel into the address space of each process, which avoids the overhead of switching address spaces when the kernel needs to access a user virtual address space. However, there still needs to be a change in the privilege level. [14] Certain versions of Windows allow the user address space size to be varied between 2GB and 3GB through a boot-time option. This reduces the size of the available virtual address space for both the kernel and user. The benefit is that user virtual addresses can be directly accessed in the kernel. An operation such as a copyout() or copyin() can be implemented as a simple memory copy (although with a page-faulting caveat). Mac OS X does not map the kernel into each user address space, and therefore each user/kernel transition (in either direction) requires an address space switch. Mac OS X does map a variety of library code and data into each task's address space, which reduces the amount of arbitrarily usable virtual memory available to the task. Table 82 shows several VM-related limits known to the PowerPC version of the Mac OS X kernel. Many but not all of these limits are the same on the x86 version of Mac OS X.
The Mac OS X kernel uses an optimization called the user memory window, which maps a portion of a user address spaceon a per-thread basisinto the last 512MB of the kernel virtual address space. The kernel uses this mechanism during operations such as copyin(), copyout(), and copypv(). As shown in Table 82, the window starts at kernel virtual address 0xE000_0000. Consequently, a user virtual address addr will be visible in the kernel at virtual address (0xE000_0000 + addr). Let us now look at how the kernel and user virtual address spaces are laid out in Mac OS X. Tables 83 and 84 show the layouts of the kernel and user (32-bit) virtual address spaces, respectively, in Mac OS X 10.4.
Although virtual memory allows each task to theoretically use any virtual address in its virtual address space, in practice, a subset of each task's virtual address space is reserved for conventional or situational purposes. For example, the system maps code and data into predefined address ranges in every task's address space. Moreover, a task may be disallowed to access certain address ranges entirely. For example, every task is disallowed access to the first memory page by default. As a result, a 32-bit task, whose virtual address space is 4GB in size (corresponding to the range defined by 0 and 0xFFFF_FFFF as the lowest and highest virtual memory addresses, respectively), has only a subset of its address space to use for arbitrary purposes. To sum up, the kernel does not take any part of a process's address space. The kernel and every user process get the full 4GB (32-bit) address space. Each transition from user to kernel (and back) requires an address space switch.
The kernel supports setting a per-thread bit (ignoreZeroFault) that instructs the kernel to ignore a page fault because of the thread accessing page 0. This is useful in the case of certain ROM device drivers that access page 0 when they start. If the bit is set for the faulting thread and the faulting address is within the zeroth page, the trap handler simply continues. This technique is deprecated in recent versions of Mac OS X. It was used in earlier versions by the I/O Kit to temporarily allow a "native" driver to access page 0. When there is a copy-in/copy-out, the code that eventually talks to the MMU handles the mapping between address spaces. The mapping's job is to translate a given address to a mapped address per the address space in use. The resultant address is then used in the copy operation. Because of the address space switch (the kernel uses the entire 4GB address space), copy-in/copy-out operations, particularly on small amounts of memory, can be expensive. System calls become expensive as well. |
Категории