Chapter 4 Exploring the Memory Management Mechanism of WINDOWS 2000
Translation: kendiv (fcczj@263.net)
Update:
Sunday, February 14, 2005
Disclaimer: Please indicate the source and guarantee the integrity of the article, and all rights to the translation.
data structure
Some parts of this chapter will involve the underlying memory management mechanism, where we have quickly viewed the substantially outline inside the mechanism. For convenience, I define several data structures in C language. This is because many of the data items inside the i386 CPU need to use a binary bit or a set of binary positions, while C bit-fields is at hand. The bit domain can effectively access one bit in a large data or extract a set of continuous bits. Microsoft's Visual C / C can generate a great code to complete the bit field. Listing 4-2 is part of a series of CPU data type definitions, which contains the following:
l x86_register This is a basic non-symbolic 32-bit integer type that describes multiple CPU registers. This includes: universal, index, pointer, control, debugging, and test registers.
l x86_selector represents a 16-bit segment selector, such as CS, DS, ES, FS, GS, and SS. In Figures 4-1 and 4-2, the selector can describe the high 8 bits of the 48-bit logical address, or as an index of the descriptor table. For the convenience of calculation, the value of the 16-bit selector is extended to 32 bits, but the high 16 bits are identified as "reservation". Note that the x86_selector structure is actually a union of the two structures. The first value specified the value of the selector, which occupies a 16-bit word, its name is Wvalue, the second uses the bit domain. The RPL domain specifies the privileged level of the request, its value or 0 (kernel mode) or 3 (user mode) on Windows 2000. The TI bit is used to select GDT or LDT.
l x86_descriptor defines the format of the page entry that is directed by the selector. This is a 64-bit value, because of historical evolution, this structure is more refined. The linear foundation is defined in the starting position of the segment thereof, which is dispersed in three bit domains: Base1, Base2, and Base3, base1 are the smallest part of the role. Segment limit specifies the segment size, The segment limit specifying the segment size minus one is divided into the pair Limitl and Limit2, with the former representing the least significant half. The remaining bit field storing different attributes of segments (cf. Intel 1999c , pp.3-11). For example, the G bit domain defines the particle size of the segment. If it is zero, the limit is limited by byte; otherwise, the limit value is a multiple of 4KB. Like x86_selector, the X86_Descriptor structure consists of a Union to allow it to explain its value in different ways. If you have to copy a descriptor (in ignore its internal condition), Dvaluelow and DVALUEHIGH members will be helpful.
l x86_gate This structure looks like x86_descriptor. In fact, the two structures are related: x86_descriptro is a GDT entry, and describes the memory properties of a segment, x86_gate represents one of the interrupt descriptor table (IDT) and describes the memory properties of the interrupt routine. IDT can contain tasks, interrupts and traps (no! Bill Gates are not stored in IDT! Haha). The x86_gate structure can match the above three types and distinguishes through the TYPE bit field. TYPE 5 indicates this is a task door; Type 6 and 14 are interrupts; Type 7 and 15 are trap door. The most important bit in Type is the bit of the number of bits used to describe the door: If it is 0, it is a 16-bit gate; the rest is 32-bit. l x86_table is a smart structure that is used to read the current value of GDTR or IDTR, respectively, respectively, implemented by assembly instruction SGDT (storage GDT register), and SIDT (CF. Intel 1999B, PP.3- 636). These two instructions require a 48-bit memory operand to store limit values and base address values in this operand. By adding a DWORD in the structure to align 32-bit base sites, X86_TABLE starts with a 16-bit dummy member WRESERVED. According to whether the SGDT or SIDT command is used, the base address will be interpreted as a descriptor pointer or a door pointer, just like the UNION in PX86_DEScriptor and PX86_GATE. The last WLIMIT member is all the same in these two types.
Translation:
These structural definitions in Listing 4-2 can be found in /src/common/include/w2k_spy.h with a book disc.
TYPEDEF DWORD X86_REGISTER, * PX86_REGISTER, ** PPX86_REGISTER
/ / -------------------------------------------------------------------------------------------- -----------------
Typedef struct _x86_selector
{
union
{
Struct
{
Word Wvalue; // Packed Value
Word wreserved;
}
Struct
{
Unsigned RPL: 2; // Requested Privilege Level
Unsigned Ti: 1; // Table Indicator: 0 = GDT, 1 = LDT
Unsigned Index: 13; // Index Into Descriptor Table
Unsigned reserved: 16;
}
}
}
X86_selector, * px86_selector, ** ppx86_selector;
#define x86_selector_ sizeof (x86_selector)
/ / -------------------------------------------------------------------------------------------- -----------------
Typedef struct _x86_descriptor
{
union
{
Struct
{
DWORD DVALUELOW; // Packed Value
DWORD DVALUEHIGH;
}
Struct
{
Unsigned limited 1: 16; // bits 15..00
Unsigned Base1: 16; // bits 15..00
Unsigned base2: 8; // bits 23..16unsigned type: 4; // segment type
Unsigned s: 1; // type (0 = system, 1 = code / data)
UNSIGNED DPL: 2; // Descriptor Privilege Level
Unsigned P: 1; // segment present
Unsigned limited2: 4; // bits 19..16
Unsigned avl: 1; // Available to Programmer
Unsigned reserved: 1;
Unsigned db: 1; // 0 = 16-bit, 1 = 32-bit
Unsigned G: 1; // Granularity (1 = 4KB)
Unsigned Base3: 8; // Bits 31..24
}
}
}
X86_Descriptor, * px86_descriptor, ** ppx86_descriptor;
#define x86_descriptor_ sizeof (x86_descriptor)
/ / -------------------------------------------------------------------------------------------- -----------------
Typedef struct _x86_gate
{
union
{
Struct
{
DWORD DVALUELOW; // Packed Value
DWORD DVALUEHIGH;
}
Struct
{
Unsigned offset1: 16; // bits 15..00
UNSIGNED SELECTOR: 16; // Segment Selector
Unsigned parameters: 5; // parameters
Unsigned reserved: 3;
Unsigned Type: 4; // Gate Type and size
Unsigned s: 1; // always 0
UNSIGNED DPL: 2; // Descriptor Privilege Level
Unsigned P: 1; // segment present
Unsigned offset2: 16; // bits 31..16
}
}
}
X86_gate, * px86_gate, ** ppx86_gate;
#define x86_gate_ sizeof (x86_gate)
/ / -------------------------------------------------------------------------------------------- -----------------
TypedEf struct _x86_table
{
Word Wreserved; // force 32-bit alignment
Word Wlimit; // Table Limit
union
{
PX86_DESCRIPTOR PDEScriptors; // used by SGDT INSTRUCTION
PX86_GATE PGATES; // Used by SIDT INSTRUCTION
}
}
X86_Table, * PX86_TABLE, ** PPX86_TABLE;
#DEFINE X86_TABLE_SEOF (X86_TABLE)
Listing 4-2. Registers, selectors, descriptors, doors and tables of i386
The next set of structures related to I386 memory management, they are included in Listing 4-3, including: Several members of the request paging and several members of Figures 4-3 and 4-4. l x86_pdbr This structure corresponds to the CR3 register of the CPU, that is, well-known page reference site register (PDBR). It is 20 bits of PFN, which is the index of 4KB physical pages. PFN = 0 corresponds to the physical address 0x00000000, PFN = 1 is 0x00001000, and so on. 20 bits sufficiently converted throughout the 4GB address space. PFN in the PDBR is the index of the physical page, used to control the entire page directory. Most of the remaining positions in the PFN are preserved, but the exception of the 3rd position is used to control the Write-Through (PD) of the page, if it is 1, if it is 1, the page is prohibited. Level cache.
l x86_pde_4m and x86_pde_4k is two options for page directory (PDE), used to select 4MB page or 4KB page. A page directory contains up to 1024 PDEs. PFN is a page frame number, which is pointing to the next level. For a 4MB PDE, its PFN bit field has only 10 widths, addressing a 4MB page. 4KB PDE has 20 PFN, which can point to a page table, and finally select a data page by the page table. The remaining sequence is used to define a variety of properties. The most interesting "page size" bit PS is used to control the size of the page (0 = 4K, 1 = 4MB) and "existent" bit P, identify the subordinate data page (4MB mode) or page table (4KB Mode) Is existing in physical memory.
The x86_pte_4k defines the internal structure of the page table (a page table). Similar to the page directory, a page table can have 1024 items. The difference between x86_pte_4k and x86_pde_4k is: the former does not have a PS bit, which does not need it, because the size of the page is definitely 4KB. It should be noted that there is no so-called 4MB PTE because the middle layer of the page table is not required to use the memory mode of the 4MB page.
The x86_pnpe represents a "Page-not-present entry, PNPE), that is, a P bit in a PDE or PTE is 0. For example, if the Intel's manual said, the 31st of the reserved is "available to the operating system or executive (Executive) (Intel 1999C, PP. 3-28). If a linear address is mapped to a PNPE, this means that this address or has not been used yet, or the page it points to it has been replaced into the page file. Windows 2000 uses PNPE-reserved 31st bit to store information. The structure of page information has no documentation, but it is similar to the 10th bit named PageFile, as shown in Listing 4-3, if this bit is set, indicating that the page has been replaced out of physical memory. In this case, the RESERVED1 and RESERVED2-bit domains contain information that locates the page in the page file, so when you need to access the page, you can quickly replace the physical memory.
The x86_pe This structure is added to facilitate use. It contains only one Union, which includes page items, which refers to: PDBR content, all 4MB and 4KB PDE, PTE, and all PNPEs.
Typedef struct _x86_pdbr // page-directory base register (cr3) {
union
{
Struct
{
DWORD DVALUE; // Packed Value
}
Struct
{
Unsigned reserved1: 3;
Unsigned PWT: 1; // page-level Write-Through
Unsigned PCD: 1; // Page-Level Cache Disabled
Unsigned reserved2: 7;
Unsigned PFN: 20; // Page-frame Number
}
}
}
X86_PDBR, * PX86_PDBR, ** PPX86_PDBR;
#define x86_pdbr_ sizeof (x86_pdbr)
/ / -------------------------------------------------------------------------------------------- -----------------
TYPEDEF STRUCT _X86_PDE_4M / / Page-Directory Entry (4-MB Page)
{
union
{
Struct
{
DWORD DVALUE; // Packed Value
}
Struct
{
Unsigned p: 1; // present (1 = present)
Unsigned rw: 1; // read / write
Unsigned US: 1; // USER / Supervisor
Unsigned PWT: 1; // page-level Write-Through
Unsigned PCD: 1; // Page-Level Cache Disabled
Unsigned a: 1; // accessed
Unsigned D: 1; // DIRTY
Unsigned ps: 1; // page size (1 = 4-MB Page)
UNSIGNED G: 1; // Global Page
Unsigned available: 3; // available to programmer
UNSIGNED Reserved: 10;
UNSIGNED PFN: 10; // Page-Frame Number
}
}
}
X86_PDE_4M, * PX86_PDE_4M, ** PPX86_PDE_4M;
#define x86_pde_4m_ sizeof (x86_pde_4m)
/ / -------------------------------------------------------------------------------------------- -----------------
TYPEDEF STRUCT _X86_PDE_4K // Page-Directory Entry (4-KB Page)
{
union
{
Struct
{
DWORD DVALUE; // Packed Value
}
Struct
{
Unsigned p: 1; // present (1 = present)
Unsigned rw: 1; // read / write
Unsigned US: 1; // USER / Supervisor
Unsigned PWT: 1; // page-level Write-Through
Unsigned PCD: 1; // page-level cache disabledunsigned a: 1; // accessed
Unsigned reserved: 1; // dirty
Unsigned ps: 1; // page size (0 = 4-kB Page)
UNSIGNED G: 1; // Global Page
Unsigned available: 3; // available to programmer
Unsigned PFN: 20; // Page-frame Number
}
}
}
X86_PDE_4K, * PX86_PDE_4K, ** PPX86_PDE_4K;
#define x86_pde_4k_ sizeof (x86_pde_4k)
/ / -------------------------------------------------------------------------------------------- -----------------
Typedef struct _x86_pte_4k // page-Table Entry (4-kb Page)
{
union
{
Struct
{
DWORD DVALUE; // Packed Value
}
Struct
{
Unsigned p: 1; // present (1 = present)
Unsigned rw: 1; // read / write
Unsigned US: 1; // USER / Supervisor
Unsigned PWT: 1; // page-level Write-Through
Unsigned PCD: 1; // Page-Level Cache Disabled
Unsigned a: 1; // accessed
Unsigned D: 1; // DIRTY
Unsigned reserved: 1;
UNSIGNED G: 1; // Global Page
Unsigned available: 3; // available to programmer
Unsigned PFN: 20; // Page-frame Number
}
}
}
X86_PTE_4K, * PX86_PTE_4K, ** PPX86_PTE_4K;
#define x86_pte_4k_ sizeof (x86_pte_4k)
/ / -------------------------------------------------------------------------------------------- -----------------
Typedef struct _x86_pnpe // Page Not Present Entry
{
union
{
Struct
{
DWORD DVALUE; // Packed Value
}
Struct
{
Unsigned p: 1; // present (0 = not present)
Unsigned reserved1: 9;
Unsigned PageFile: 1; // Page Swapped to Pagefile
UNSIGNED Reserved2: 21;
}
}
}
X86_PNPE, * PX86_PNPE, ** PPX86_PNPE;
#define x86_pnpe_ sizeof (x86_pnpe)
/ / -------------------------------------------------------------------------------------------- -----------------
Typedef struct _x86_pe // general page entry {
union
{
DWORD DVALUE; // Packed Value
X86_PDBR PDBR; // page-directory base register
X86_PDE_4M PDE4M; // Page-Directory Entry (4-MB Page)
X86_PDE_4K PDE4K; // Page-Directory Entry (4-KB Page)
X86_PTE_4K PTE4K; // Page-Table Entry (4-KB Page)
X86_PNPE PNPE; / / PAGE Not Present Entry
}
}
X86_PE, * PX86_PE, ** PPX86_PE;
#define x86_pe_ sizeof (x86_pe)
Listing 4-3. PDBR, PDE, PTE, and PNPE of I386
In Listing 4-4, I increased the structured representation of linear addresses. These structures are formal forms of "linear address" in Figures 4-3 and 4-4.
l x86_linear_4m This structure is a formal form of a linear address of the 4MB data page, as shown in Figure 4-4. Page TableCalog Index (PDI) is a page directory index. The page directory address is given by PDBR, using PDI to select a PDE in the page directory. 22-bit OFFSET members point to a target address, this destination address corresponds to the 4MB physical page.
l x86_linear_4k is a 4kB linear address type variable, as shown in Figure 4-3. This structure consists of three bit fields: and the 4MB address is similar, the high 10 bit is PDI, used to select a PDE; the page index PTI is similar to the PDI, pointing to PDE (this PDE is specified by the previous PDI specified) determined One PTE in the page table; the remaining 12 bits are offset in the 4KB physical page.
l x86_linear is another structure that is added to use. This structure is simply simple to combine X86_Linear_4k and X86_LINEAR_4M as a data type. See List 4-4 for details.
Typedef struct _x86_linear_4m // linear address (4-MB Page)
{
union
{
Struct
{
Pvoid Paddress; // Packed Address
}
Struct
{
Unsigned Offset: 22; // Offset INTO PAGE
UNSIGNED PDI: 10; // Page-Directory INDEX
}
}
}
X86_LINEAR_4M, * PX86_LINEAR_4M, ** PPX86_LINEAR_4M;
#define x86_linear_4m_ sizeof (x86_linear_4m)
/ / -------------------------------------------------------------------------------------------- -----------------
TypedEf struct _x86_linear_4k // Linear Address (4-KB Page)
{
union
{
Struct
{
Pvoid Paddress; // Packed Address
}
Struct
{
Unsigned offset: 12; // offset INTO PAGE
UNSIGNED PTI: 10; // Page-Table INDEX
UNSIGNED PDI: 10; // Page-Directory INDEX
}
}
}
X86_LINEAR_4K, * PX86_LINEAR_4K, ** PPX86_LINEAR_4K; #define x86_linear_4k_ sizeof (x86_linear_4k)
/ / -------------------------------------------------------------------------------------------- -----------------
Typedef struct _x86_linear // general Linear Address
{
union
{
Pvoid Paddress; // Packed Address
X86_LINEAR_4M Linear4m; // Linear Address (4-MB Page)
X86_LINEAR_4K linear4k; // linear address (4-kb page)
}
}
X86_Linear, * PX86_LINEAR, ** ppx86_linear;
#define x86_linear_ sizeof (x86_linear)
List 4-4. Linear address of i386
Macro and constant
Listing 4-5 The definition given is a supplement to the structure shown in List 4-2 to List 4-4, allowing us to work more easily with I386 memory management. The definitions of the list 4-5 can be divided into three major groups. The first group is used to control linear addresses:
1. X86_page_mask, x86_pdi_mask and x86_pti_mask are both bitmask, used to select a part of the linear address. They are all based on constants: Page_shift (12), PDI-SHIFT (22) and PTI-SHIFT (12), which are defined in the header file NTDDK.H of the Windows 2000 DDK. X86_Page_Mask is equivalent to 0xffff000, which can effectively mask the offset portion in the 4KB linear address (x86_Linear_4k). X86_PDI_MASK is equivalent to 0xffc00000, apparently this can extract high 10-bit PDI from a linear address. X86_PTI_MASK is equivalent to 0x003FF0000, used to shield all bits except PTI outside the linear address.
2. X86_page (), x86_pdi () and x86_pti () use the above constant to calculate the page index, PDI, and PTI for the given linear address. X86_page () is generally used to read a PTE from the PTE array of Windows 2000 (the array header address is: 0xc0000000). X86_PDI () and x86_pti () are only for a given pointer, simply use X86_PDI_MASK or X86_PTI_MASK, and will move the resulting index to the far right.
3. X86_offset_4m () and x86_offset_4k () extract the offset portion from the 4MB or 4KB linear address, respectively.
4. x86_page_4m and x86_page_4k calculates the size of 4MB and 4KB pages according to the constant PDI_SHIFT and PTI_shift in DDK. X86_page_4m = 4, 194, 304, x86_page_4k = 4,096. Note that x86_page_4k is equivalent to DDK constant Page_Size, which is also defined in NTDDK.H.
5. x86_pages_4m and x86_pages_4k represent the total number of 4MB or 4KB pages that can be accommodated in the 4GB address space, respectively. X86_PAGES_4M is equivalent to 1,024, x86_pages_4k equivalent to 1,048,576.
#define x86_page_mask (0 - (1 << Page_shift))
#define x86_page ((DWORD) (_P) & x86_page_mask >> Page_shift) #define x86_pdi_mask (0 - (1 << PDI_shift))
#define x86_pdi (_P) ((DWORD) (_P) & x86_pdi_mask >> PDI_SHIFT)
#DEFINE X86_PTI_MASK ((0 - (1 << PTI_shift)) & ~ x86_pdi_mask)
#define x86_pti (_P) ((DWORD) (_P) & x86_pti_mask >> PTI_SHIFT)
#define x86_offset (_P, _M) ((DWORD_PTR) (_P) & ~ (_M))
#define x86_offset_4m (_P) x86_offset (_P, x86_pdi_mask)
#define x86_offset_4k (_P) x86_offset (_P, x86_pdi_mask | x86_pti_mask)
#define x86_page_4m (1 << PDI_shift)
#define x86_page_4k (1 << pti_shift)
#define x86_pages_4m (1 << (32 - PDI_SHIFT))
#define x86_pages_4k (1 << (32 - pti_shift))
/ / -------------------------------------------------------------------------------------------- -----------------
#define x86_pages 0xc0000000
#define x86_pte_Array ((PX86_PE) x86_pages)
#define x86_pde_Array (x86_pte_Array (x86_pages >> PTI_shift))
/ / -------------------------------------------------------------------------------------------- -----------------
#define x86_segment_other 0
#define x86_segment_cs 1
#define x86_segment_ds 2
#define x86_segment_es 3
#define x86_segment_fs 4
#define x86_segment_gs 5
#define x86_segment_ss 6
#define x86_segment_tss 7
/ / -------------------------------------------------------------------------------------------- -----------------
#define x86_selector_rpl 0x0003
#define x86_selector_ti 0x0004
#define x86_selector_index 0xfff8
#define x86_selector_shift 3
#define x86_selector_limit (x86_selector_index >> /
X86_Selector_shift)
/ / -------------------------------------------------------------------------------------------- ---------------- # Define x86_descriptor_sys_tss16a 0x1
#define x86_descriptor_sys_ldt 0x2
#define x86_descriptor_sys_tss16b 0x3
#define x86_describTOR_SYS_CALL16 0X4
#define x86_descriptor_sys_task 0x5
#define x86_describTOR_SYS_INT16 0X6
#define x86_descriptor_sys_trap16 0x7
#define x86_describTOR_SYS_TSS32A 0x9
#define x86_descriptor_sys_tss32b 0xb
#define x86_descriptor_sys_call32 0xc
#define x86_descriptor_sys_int32 0xe
#define x86_descriptor_sys_trap32 0xF
/ / -------------------------------------------------------------------------------------------- -----------------
#define x86_descriptor_app_accessed 0x1
#define x86_descriptor_app_read_write 0x2
#DEFINE X86_DESCRIPTOR_APP_EXECUTE_READ 0X2
#DEFINE X86_DESCRIPTOR_APP_EXPAND_DOWN 0x4
#define x86_describTOR_APP_CONFORMING 0x4
#define x86_describTOR_APP_CODE 0x8
Listing 4-5. Additional I386 Memory Management Related Definitions
The second group macro and constant is related to the PDE of Windows 2000. Unlike several other system addresses, the base address of these arrays does not appear as a global variable when the system is started, but is defined as a constant. You can prove that these addresses can be displayed in these functions by reverse memory management API functions: mmgetphysicaladdress () and mmisaddressvalid (). In these functions, these addresses appear in the form of "magic numbers". These constants are not included in the DDK header file, but the list 4-5 shows how to define them.
l x86_pages is a hard-coded address and pointer (pointing 0xc0000000), 0xC0000000 is wherever Windows 2000's PTE array begins.
X86_PTE_Array is equivalent to X86_pages, but is transformed into px86_pe, that is, pointing to an array of x86_pe types, X86_pe is defined in List 4-2.
X86_pde_array is a clever definition that calculates the base address of the PDE array through the PTE array, which requires the PTI_SHIFT constant. The general format of the linear address is mapped to the PTE address is: (Lineradress >> 12) * 4) 0xC0000000, the linear address 0xC0000000 converted the address of the page directory.
The last two parts of the list 4-5 include a selector and a special type of descriptor, and a supplement to the list 4-2.
l x86_selector_rpl, x86_selector_ti and x86_selector_index are bit masks, respectively correspond to RPL, TI, and INDEX members in the x86_selector structure. l x86_selector_shift is a right shift factor, used to align the value of the INDEX of the selector.
l x86_selector_limit defines the maximum index value that the selector can use, which is 8, 191. This value determines the maximum size of the descriptor table. Each selector index is directed to a descriptor, each descriptor contains 64 bits (ie, 8 bytes). Therefore, the maximum size of the descriptor table is: 8,192 * 8 = 64kb.
l x86_descriptor_sys_ * is a set of constants for defining the system descriptor type. If the S bit of the descriptor is set to 0, then the descriptive Type member will use one of this set of types. See the definition of x86_descriptor in Listing 4-2. The system descriptor type has a detailed description in the Intel manual (Intel 1999C, PP. 3-15F), Table 4-1 gives all available system descriptor types.
The X86_Descriptor_app_ * constant in the list 4-5 can also be used to define the TYPE member of the descriptor, provided that the S bit of the descriptor is not 0. At this point, the application descriptor may need to reference a code or data segment. Because the properties of the application descriptor type are affected by the fourth bit of the Type domain, X86_Descriptor_app_ * constants are defined as a single-bit mask, so some bits can have different interpretations for data and code segments.
l x86_descriptor_app_accessed If a segment can be accessed,
l x86_descriptor_app_read_write determines if a data segment allows only read-only or read / write access.
l x86_descriptor_app_conformating Describes whether a code segment matches. That is, it can be called in a weak privileged code (refer to Intel 1999C, PP. 4-13FF).
l x86_descriptor_app_code is used to distinguish between code segments and data segments. Note that the stack belongs to the scope of the data segment and must always be writable.
Later, when the Memory SPY program in the next chapter starts running, we will revoke system descriptors. Table 4-1 is a short summary of I386 memory management. For more information on this topic, please refer to Intel Pentium Manual (Intel 1999a, 1999b, 1999c).
Table 4-1. System Descriptor Type
Name
value
Describe
X86_DESCRIPTOR_SYS_TSS16A 0x1 16 Wei task state segment (available) X86_DESCRIPTOR_SYS_LDT 0x2 Local Descriptor Table (LDT) X86_DESCRIPTOR_SYS_TSS16B 0x3 16 Wei task state segment (busy) X86_DESCRIPTOR_SYS_CALL16 0x4 16 an invocation door X86_DESCRIPTOR_SYS_TASK 0x5 task gate X86_DESCRIPTOR_SYS_INT16 0x6 16 bit interrupts door X86_DESCRIPTOR_SYS_TRAP16 0x7 16 Wei trap door X86_DESCRIPTOR_SYS_TSS32A 0x9 32 Wei task state segment (available) X86_DESCRIPTOR_SYS_TSS32B 0xB 32 Wei task state segment (busy) X86_DESCRIPTOR_SYS_CALL32 0xC 32 an invocation door X86_DESCRIPTOR_SYS_INT32 0xE 32 bit interrupts door X86_DESCRIPTOR_SYS_TRAP32 0XF 32 Wei trap door .................. .. Continued ... ..................