Fix Mapped Linear Addresses

We saw that the initial part of the fourth gigabyte of kernel linear addresses maps the physical memory of the system. However, at least 128 MB of linear addresses are always left available because the kernel uses them to implement noncontiguous memory allocation and fix-mapped linear addresses.

Noncontiguous memory allocation is just a special way to dynamically allocate and release pages of memory, and is described in Section 7.3. In this section, we focus on fix-mapped linear addresses.

Basically, a fix-mapped linear address is a constant linear address like 0xfffffdf0 whose corresponding physical address can be set up in an arbitrary way. Thus, each fix-mapped linear address maps one page frame of the physical memory.

Fix-mapped linear addresses are conceptually similar to the linear addresses that map the first 896 MB of RAM. However, a fix-mapped linear address can map any physical address, while the mapping established by the linear addresses in the initial portion of the fourth gigabyte is linear (linear address X maps physical address X-page_offset).

With respect to variable pointers, fix-mapped linear addresses are more efficient. In fact, dereferencing a variable pointers requires that one memory access more than dereferencing an immediate constant address. Moreover, checking the value of a variable pointer before dereferencing it is a good programming practice; conversely, the check is never required for a constant linear address.

Each fix-mapped linear address is represented by an integer index defined in the enum fixed_addresses data structure:

enum fixed addresses { FIX_APIC_BASE,

end of fixed addresses

Fix-mapped linear addresses are placed at the end of the fourth gigabyte of linear addresses. The fix_to_virt( ) function computes the constant linear address starting from the index:

inline unsigned long fix to virt(const unsigned int idx) {

if (idx >= end of fixed addresses) this fixmap does not exist( ); return (0xffffe000UL - (idx << PAGE_SHIFT));

Let's assume that some kernel function invokes fix_to_virt(FIX_I0APIC_BASE_0). Since the function is declared as "inline," the C compiler does not invoke fix_to_virt( ), but just inserts its code in the calling function. Moreover, the check on the index value is never performed at runtime. In fact, fix_ioapic_base_0 is a constant, so the compiler can cut away the if statement because its condition is false at compile time. Conversely, if the condition is true or the argument of fix_to_virt( ) is not a constant, the compiler issues an error during the linking phase because the symbol _

_this_fixmap_does_not_exist is not defined elsewhere. Eventually, the compiler computes 0xffffe000-(1<<PAGE_SHiFT) and replaces the fix_to_virt( ) function call with the constant linear address 0xffffd000.

To associate a physical address with a fix-mapped linear address, the kernel uses the set fixmap( idx,phys) and set fixmap nocache( idx,phys) functions. Both of them initialize the Page Table entry corresponding to the fix_to_virt(idx) linear address with the physical address phys; however, the second function also sets the PCD flag of the

Page Table entry, thus disabling the hardware cache when accessing the data in the page frame (see Section 2.4.7 earlier in this chapter).

Continue reading here: Handling the hardware cache

Was this article helpful?

+2 -3