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.

Table 82. VM-Related System Limits

Mnemonic

Value

Notes

VM_MAX_PAGE_ADDRESS

0x0007_FFFF_FFFF_F000 (PowerPC)

Highest possible page address. Mac OS X 10.4 provides 51 bits of user virtual memory on 64-bit hardware.

MACH_VM_MIN_ADDRESS

0

 

MACH_VM_MAX_ADDRESS

0x0007_FFFF_FFFF_F000 (PowerPC)

 

VM_MIN_ADDRESS (32-bit)

0

 

VM_MAX_ADDRESS (32-bit)

0xFFFF_F000

 

USRSTACK (32-bit)

0xC000_0000

Default initial user stack pointer for a 32-bit process.

VM_MIN_ADDRESS (64-bit)

0

 

VM_MAX_ADDRESS (64-bit)

0x7_FFFF_FFFF_F000

 

USRSTACK64 (64-bit)

0x7_FFFF_0000_0000

Default initial user stack pointer for a 64-bit process.

VM_MIN_KERNEL_ADDRESS

0x0000_1000

Minimum kernel virtual addressdoes not include the first page, which contains the exception vectors and is mapped V=R.

VM_MAX_KERNEL_ADDRESS

0xDFFF_FFFF

Maximum kernel virtual addressdoes not include the last 512MB, which is used as the user memory window (see Table 83).

KERNEL_STACK_SIZE

16KB

The fixed size of a kernel thread's stack.

INTSTACK_SIZE

20KB

Interrupt stack size.

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.

Table 83. Kernel Virtual Address Space Layout (32-bit PowerPC, Mac OS X 10.4)

Start

End

Notes

0x0000_0000

0x0000_4FFF

Exception vectors and low-memory code in osfmk/ppc/lowmem_vectors.s

0x0000_5000

0x0000_5FFF

Low-memory globals

0x0000_6000

0x0000_6FFF

Low-memory shared page used for low-level debugging

0x0000_7000

0x0000_DFFF

Boot processor interrupt and debug stacks

0x0000_E000

0x0FFF_FFFF

Kernel code and data

0x1000_0000

 

Physical memory window

 

0xDFFF_FFFF

Highest kernel virtual address known to the VM subsystem

0xE000_0000

0xFFFF_FFFF

User memory window

Table 84. User Virtual Address Space Layout (32-bit, Mac OS X 10.4)

Start

End

Notes

0x0000_0000

0x0000_1000

So-called zero page (__PAGEZERO)inaccessible by default so that dereferencing a NULL pointer (including small offsets from a NULL pointer) causes a protection fault

0x0000_1000

0x8FDF_FFFF

Application address range (about 2.3GB)

0x8FE0_0000

8x8FFF_FFFF

Space reserved exclusively for Apple system libraries; e.g., the dynamic linker's text segment, mapped starting at 0x8FE0_0000

0x9000_0000

0x9FFF_FFFF

Global shared text segment, reserved exclusively for Apple system libraries; e.g., the system library's text segment, mapped starting at 0x9000_0000

0xA000_0000

0xAFFF_FFFF

Global shared data segment, reserved exclusively for Apple system libraries; e.g., the system library's data segment, mapped starting at 0xA000_0000

0xB000_0000

0xBFFF_FFFF

Preferred address range for the application's main thread

0xC000_0000

0xEBFF_FFFF

Additional space available for third-party applications and framework code

0xF000_0000

0xFDFF_FFFF

Range preferred for use by additional thread stacks, although applications may use this range as necessary

0xFE00_0000

0xFFBF_FFFF

Range reserved for use by the pasteboard and other system services; not to be used by user programs

0xFFC0_0000

0xFFFD_FFFF

Range preferred for use by other system services, although applications may use this range as necessary

0xFFFE_0000

0xFFFF_7FFF

Range reserved for use by system services and not to be used by user programs; e.g., a portion of the address range starting at 0xFFFE_C000 is used by the Objective-C library as a commpage for optimizing message dispatch

0xFFFF_8000

0xFFFF_EFFF

System-shared commpage (seven pages)

0xFFFF_F000

0xFFFF_FFFF

Last page of a 32-bit address space; cannot be mapped by the Mach VM subsystem

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.

Категории