Building the Logical Map

   

Now that we have muddied the waters of a process's view of memory a bit, we need to stop and consider how these various mapping strategies may be tied to a specific process. The header in a program file contains information regarding the various magic options used during the compile; the kernel takes these into consideration as it sets up the process and kthread environment. Figure 5-8 presents a model of the logical and virtual address spaces.

Figure 5-8. The Process Logical Address Space

graphics/05fig08.gif


The various options we have discussed dictate where in the virtual map the various memory objects of a process may be allocated. It is up to the kernel to handle issues such as sharing and privacy. The kernel also must track what is where and who it belongs to; these issues are covered in Chapter 6. For now, our attention should be turned to the issue of mapping specific virtual memory objects to the logical map of a process. To understand how this is done, we must look to the vas and pregion structures created by the kernel and linked to a process's proc and kthread structures when a process is created (by the fork() or vfork() system calls). On to the vas!

The vas

The vas (virtual address space) structure is merely the head of a list of pregion structures, which in turn define the type and location of the various memory resources required to build the process's logical address space (see Figure 5-9). Modern compilers build an executable image by loading discrete components of the program into contiguous address blocks and then linking them together. This approach is necessary if you want to implement shared libraries, memory-mapped files, shared text, and shared memory all features of the HP-UX kernel.

Figure 5-9. The vas/pregion List

graphics/05fig09.gif


To clarify and equate a couple of terms, contiguously addressed logical memory blocks are mapped to virtual page objects. These are also called memory regions. The term region goes back a long way in the history of UNIX kernels and is present in virtually all UNIX and Linux implementations.

One example of the use of the vas structure occurs when there is a physical page fault. The kernel's fault handler must locate the specific region of memory in which the missing page is managed (this is discussed in greater detail in Chapter 6). The kernel knows which kthread was executing when the fault occurred. The kthread structure provides a direct pointer to the associated proc structure, and it in turn provides a pointer to the vas structure at the head of the linked list of pregions that define the process's logical address space. Next, the fault handler must search the chain of pregion structures to find the one containing the faulted page address. Once the correct pregion is found, page frame specific information is contained in the kernel-managed region structure pointed to by the process's pregion. To speed up the searching of these linked structures, the kernel uses a four-level skip list.

As pregions are added to a process's vas chain, they are assigned a skip level between 0 and 3. Level determination is pseudo-random in nature; the general rule is that we are four times as likely to be assigned level 0 as level 1, and four times as likely to be assigned level 1 as level 2, and four times as likely to be assigned level 2 as level 3. Even given this rule of thumb, you can't predict which level any specific pregion will have until it is allocated by the kernel. We discussed the mechanics of skip lists earlier in this book.

Let's start our examination of the vas structure (Listing 5.4) with the skip list pointers, note there are four forward pointers and a single prev or reverse pointer.

Listing 5.4. q4 fields struct vas
 The va_hilevel records the highest skip level in use for this specific pregion.   0 0 4 0 *       va_ll.lle_next[0]   4 0 4 0 *       va_ll.lle_next[1]   8 0 4 0 *       va_ll.lle_next[2]  12 0 4 0 *       va_ll.lle_next[3]  16 0 4 0 *       va_ll.lle_prev  20 0 4 0 int     va_hilevel Next comes a reference count, an approximate count of shared  resident page frames, an approximate count of private resident  page frames, and an approximate count of private page frames  in swap.  40 0 4 0 int     va_refcnt  44 0 4 0 int     va_rss  48 0 4 0 int     va_prss  52 0 4 0 int     va_dprss A pointer to the proc structure or a pointer to a memory- mapped file's vnode and a pointer to the process's credentials is kept for quick access  56 0 4 0 *       va_proc  64 0 4 0 *       va_fp  96 0 4 0 *       va_cred Hardware-dependent information is next 100 0 4 0 u_int   va_hdl.hdl_textsid 104 0 4 0 u_int   va_hdl.hdl_textpid 108 0 4 0 u_int   va_hdl.hdl_datasid 112 0 4 0 u_int   va_hdl.hdl_datapid 116 0 2 0 u_short va_hdl.v_hdlflags 120 0 4 0 int     va_ki_vss 124 0 1 0 u_char  va_ki_flag 125 0 1 0 u_char  va_stlocked Total user space virtual memory count 128 0 4 0 int     va_ucount Run environment information 132 0 4 0 enum4   va_runenv.r_machine 136 0 4 0 enum4   va_runenv.r_arch 140 0 4 0 enum4   va_runenv.r_os 144 0 4 0 enum4   va_runenv.r_asmodel 148 0 4 0 enum4   va_runenv.r_magic Large page-specific information 152 0 4 0 int     va_lgpg_env.lgpg_data_size 156 0 4 0 int     va_lgpg_env.lgpg_text_size 160 0 4 0 int     va_lgpg_env.lgpg_next_brk_inc 164 0 4 0 int     va_lgpg_env.lgpg_user_brk_cnt 168 0 4 0 int     va_lgpg_env.lgpg_next_stk_inc Memory window information and Memory Reference Group info for  private and shared page frames (this is where a process may  point to a specific memory window for the values for its Q3 and possibly Q2 space registers) 172 0 4 0 u_int   va_winId 176 0 4 0 *       va_winMap 180 0 4 0 *       va_priv_mrg 184 0 4 0 *       va_shar_mrg 

Let's move our discussion on to the pregion.

The pregion (pseudo-region)

This is a good point to discuss what is meant by a pseudo-structure. As mentioned earlier, memory management may be approached from two perspectives. A process could care less if a page is private or shared it simply wants it to be made available when its data or text is needed during the execution of its code. From the process's viewpoint, the vas should provide a direct connection to individual page-frame management data, but in practice it is not that simple!

The kernel also has a perspective when it comes to memory management. We fully explore this point of view in Chapter 6, but for now must consider the basic idea of memory regions. A region is a contiguous range of virtual page frames to be used in a consistent manner with common access rights and privileges. To increase memory utilization efficiencies and provide various types of shared access to memory objects, a concept of private and shared regions has been developed.

A reference count is kept in the region structure, tracking the number of pregions that are currently pointing to it. If this reference count is reduced to zero, then the kernel deallocates the region structure and all the memory resources it controls.

Region sharing is accomplished through the creation of an additional abstraction layer in the kernel. For a process to claim access to a region, a structure known as a pregion (or pseudo-region) is linked into the process's vas chain. Each pregion in the process's chain points to a specific region mapped to the kernel's VAS (see Figure 5-10).

Figure 5-10. The pregion Structure

graphics/05fig10.gif


Pregions from multiple processes may point to the same kernel region, thus creating a shared memory object under kernel control. A region only knows the total number of page frames it contains, where they have been placed in the kernel's VAS map, whether it is private or shared, and the specific status and location of each page frame. The actual purpose of these pages (whether it is text, data, a memory-map or shared memory) is not known at this level.

Conversely, the pregion maintains a detailed list of attributes from the perspective of the process, where it has been linked into the process's logical memory, its usage type, size, and current status.

Let's examine the pregion fields (Listing 5.5).

Listing 5.5. q4 fields struct pregion
 As with the vas, the first entries in the pregion structure hold the skip list pointers   0 0 4 0 *       p_ll.lle_next[0]   4 0 4 0 *       p_ll.lle_next[1]   8 0 4 0 *       p_ll.lle_next[2]  12 0 4 0 *       p_ll.lle_next[3]  16 0 4 0 *       p_ll.lle_prev Enumerated flags are next  20 0 4 0 enum4   p_flags Each region is assigned a type number depending on its usage  24 0 4 0 enum4   p_type The type numbers and enumerations are: 1=PT_UAREA per-thread kernel management area 2=PT_TEXT shared, read-only instruction text 3=PT_DATA  private, read-write process data area 4=PT_STACK private, read-write process stack area 5=PT_SHMEM shared, read-write memory region 6=PT_NULLDREF shared, read-only null pointer dereference 7=PT_IO shared, read-write I/O memory-mapped area 8=PT_MMAP shared or private, read-write memory-mapped file 9=PT_GRAFLOCKPG Frame buffer lock page (used by some graphics devices) 10=PT_ANON_SHMEM shared, read-write anonymous shared memory 11=PT_GRAFDMA graphics DMA region 12=PT_RSESTACK RSE stack (HP emulation on IA64 only) 13=PT_GATEWAY shared, read-only system call gateway page Next, a pointer to the kernel region structure, the virtual  space for the region, and the starting virtual address for the  region  28 0 4 0 *       p_reg  32 0 4 0 u_int   p_space  36 0 4 0 *       p_vaddr These next 5 parameters are used by the paging system (more  later)  40 0 4 0 int     p_off  44 0 4 0 int     p_count  48 0 4 0 int     p_ageremain  52 0 4 0 int     p_agescan  56 0 4 0 int     p_stealscan A direct pointer to the vas this pregion is chained to  60 0 4 0 *       p_vas A direct pointer to the owner kthread if this is a PT_UAREA  64 0 4 0 *       p_thread All pregions on the system are dual linked by these two  pointers; this master list will be searched when memory  pressure triggers the paging system to become active.  68 0 4 0 *       p_forw  72 0 4 0 *       p_back 

Next, we examine the uarea.

The uarea

This snapshot includes a copy of the general registers, control registers, program counters (space and offset queues in the case of PA-RISC), the processor status word, and space registers. The snapshot is called a Process Control Block, or pcb. A key element of any multitasking operating system is the ability to switch between the various threads of execution. This basic function is called a context switch. The term context refers to the state of the machine when a specific thread is executing. If we are to halt execution of a specific thread and return to it at a later time, we need to take a snapshot of the processor's registers on which the thread is running at the instant we suspend execution and return them to this exact state when we want to resume.

The kernel must have a place to safely store the pcb of a sleeping or blocked process until it is required for a context switch back into the processor's registers. To this end, each process thread has created for it a memory region known as a uarea (see Figure 5-11).

Figure 5-11. The uarea Structure

graphics/05fig11.gif


The uarea is not visible from the process's threads and is mapped into the kernel space whenever a thread is activated (made the running thread on a specific processor). When a thread makes a system call or the kernel preempts a thread to handle an interruption, it already has the current thread's uarea mapped into the kernel's memory view. If the kernel determines that it needs to perform a context switch prior to returning to the user space, then the current thread's pcb is stored in its uarea. Next, the kernel determines which thread to switch in and restores a pcb from its uarea prior to the transition to user mode. The kernel routine that manages this black magic is called swtch()and is one of the more expensive, but very necessary, actions the kernel may undertake!

The uarea comprise several key sections (see Figure 5-11). The first is the user structure, which contains room for the pcb and other thread-specific kernel management data, and the second is a kernel stack space. Each thread must provide a limited amount of stack space for use by kernel routines, drivers, and kernel services requested through the system call interface.

Consider for a moment the scenario where two independent threads make a request to the same kernel service, possibly a disk read or write request. As both threads enter the gateway page and transition from user space to kernel space, they are in effect running the same exact set of instructions in the kernel but from two different program contexts.

If the service being requested needs to make a procedure call (and the kernel employs an extensive set of library routines), it must allocate a new stack pointer to accommodate local data and register spill areas. If we could be guaranteed that all calls to the kernel would complete in a first-in last-out order, then a simple kernel stack could be used, but this may not be the case. If the requested disk transactions complete in the wrong order, the unwinding of a common stack could cause corruption!

To avoid this situation, each thread requesting kernel services (system calls) is expected to provide its own localized kernel stack, or kstack, space. Since a thread's uarea is already mapped into the kernel's space while a thread is running, it is a simple matter to add a minimal kstack to the end of this region. For a narrow kernel (32-bit), the uarea is sized to four page frames (one for the user structure and three for the kstack). For wide kernels (64-bit), it is eight pages frames (two for the user structure and six for the kstack).

Let's examine the u_pcb portion of the user structure (Listing 5.6).

Listing 5.6. q4 fields structure uarea
 The u_pcb starts with storage space for the general registers,  r1 through r31 (there is no need to store the value of  r0  considering that it is the permanent zero source register!)    0 0  4 0 u_long             u_pcb.pcb_r1      -  -  -  120 0  4 0 u_long             u_pcb.pcb_r31 Next, the 8 space registers, sr0   sr7, are saved  124 0  4 0 u_long             u_pcb.pcb_sr0     -  -  -  152 0  4 0 u_long             u_pcb.pcb_sr7 Control register cr1 and registers cr8 through cr31 are saved  here. Control registers cr2   cr7 are reserved for use by the  hardware and not included as part of a thread's context  156 0  4 0 u_long             u_pcb.pcb_cr0  160 0  4 0 u_long             u_pcb.pcb_cr8     -  -  -  252 0  4 0 u_long             u_pcb.pcb_cr31 Room is also allocated for the threads pc, psw, ipsw, pcsqe,  pcoqe, and ksp  256 0  4 0 u_long             u_pcb.pcb_pc  260 0  4 0 u_long             u_pcb.pcb_psw  264 0  4 0 u_long             u_pcb.pcb_ipsw  268 0  4 0 u_long             u_pcb.pcb_pcsqe  272 0  4 0 u_long             u_pcb.pcb_pcoqe  276 0  4 0 u_long             u_pcb.pcb_ksp The floating-point registers fr0 through fr31 come next  280 0  8 0 double             u_pcb.pcb_fr0     -  -  -  528 0  8 0 double             u_pcb.pcb_fr31 The pcb ends with several miscellaneous parameters dealing  with the signal system and swap. After the pcb, the user  structure has pointers to the thread's proc structure,  kthread, a saved state, the most recent saved state  584 0  4 0 *                  u_procp  588 0  4 0 *                  u_kthreadp  592 0  4 0 *                  u_sstatep  596 0  4 0 *                  u_pfaultssp The rest of the user structure contains an assortment of  syscall parameters (including the parameters passed to the  most recent system call made by the thread, very useful during debugging a crash dump), process and protection information,  miscellaneous memory management information, various signal  management parameters, KI daemon metrics, and last but not  least a union with the provided kernel stack space. 

To use q4 to examine a specific thread's uarea, first make your way to its kthread structure:

q4> load struct preg from kt_upreg

graphics/leftarrow.gif load the uarea's pregion structure

q4> print x p_space p_vaddr

graphics/leftarrow.gif print out the virtual address information

q4> load struct user from <p_space.p_vaddr> from the previous print statement


Additional Resource Pointers

In addition to the various structures we have mentioned in this chapter, the proc structure provides pointers to a process's file descriptor and kernel signal structures. These are covered later in this book.



HP-UX 11i Internals
HP-UX 11i Internals
ISBN: 0130328618
EAN: 2147483647
Year: 2006
Pages: 167

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net