Public Types | Public Member Functions
gdt_x64 Class Reference

Public Types

using size_type = uint16_t
 
using index_type = uint16_t
 
using integer_pointer = uintptr_t
 
using base_type = uint64_t
 
using limit_type = uint32_t
 
using access_rights_type = uint32_t
 
using segment_descriptor_type = uint64_t
 

Public Member Functions

 gdt_x64 () noexcept
 
 gdt_x64 (size_type size) noexcept
 
 ~gdt_x64 () noexcept=default
 
integer_pointer base () const
 
size_type limit () const
 
void set_base (index_type index, base_type base)
 
base_type base (index_type index) const
 
void set_limit (index_type index, limit_type limit)
 
limit_type limit (index_type index) const
 
void set_access_rights (index_type index, access_rights_type access_rights)
 
access_rights_type access_rights (index_type index) const
 

Detailed Description

Global Descriptor Table

This class provides an abstraction around the global descriptor table for 64bit.

This class does not provide a "descriptor" class as the amount of code needed to completely abstract each descriptor type would be enormous for something that is setup once, and never touched again. So it is left to the user to understand how to set the access rights for each descriptor manually, as this is the part that is descriptor specific. In general, all of the information about each descriptor can be found in the Intel Manual in Volume 3.

Generally speaking, there are 2 different types of descriptors, a code/data segment descriptor, and a TSS descriptor.

A code/data segment descriptor is a descriptor that is loaded into es, cs, ss, ds, fs or gs. Information about these types of descriptors can be found in Volume 3, section 3.4.5. A code segment is any segment that is loaded into CS. Although not called out in all of the documentation, Intel does have a stack segment which is any descriptor loaded into SS, and the access rights are different for a stack segment. Finally there are data segments which are any descriptor loaded into es, ds, fs and gs. On 64bit, es and ds are not available, so they should always point to the NULL descriptor, which is the first descriptor in the table, which has to be set to all 0s (per the spec). The only parts of cs, ss, fs, and gs that are used are the access rights. The CPU in 64bit mode assumes that the base is set to 0, and the limit is 0xFFFFF. Although the limit is only 4G (because it's only 20 bits), the CPU internally sets the limit to 2^64 for you. fs and gs are the only segments that can have a base address not set to 0, but they cannot be set using the GDT, and instead have to be set using the MSRs. Bareflank uses gs to store the offset into the state save area for the exit handler.

A TSS descriptor defines the task state segment. This is a structure that is defined 7.2 (for 32bit), and 7.7 (for 64bit). The OS might fill in this structure for syscalls, but in general, this structure is not used in 64bit, but still needs to be defined. For a hypervisor, this structure can be left blank. The base address of the TSS descriptor needs to be the address of the TSS, the limit should be sizeof(TSS), which for a hypervisor that doesn't use the IO bitmap, or any custom data is 104 bytes, and the access rights are set to a present 64bit TSS. There is one complication with the TSS descriptor which is that you cannot simply call ltr (load task register) with any TSS. The TSS cannot have the busy flags set. Since there is a TSS that the host OS has, and a TSS for the VMM, this tends to be fine, up to the point where the VMM attempts to promote the guest. When this happens, there are actually two TSS descriptors marked as busy, which should never happen, but does. The solution is to mark the host OS's TSS descriptor as not busy manually before loading it.

Definition at line 190 of file gdt_x64.h.

Member Typedef Documentation

◆ size_type

using gdt_x64::size_type = uint16_t

Definition at line 194 of file gdt_x64.h.

◆ index_type

using gdt_x64::index_type = uint16_t

Definition at line 195 of file gdt_x64.h.

◆ integer_pointer

using gdt_x64::integer_pointer = uintptr_t

Definition at line 196 of file gdt_x64.h.

◆ base_type

using gdt_x64::base_type = uint64_t

Definition at line 197 of file gdt_x64.h.

◆ limit_type

using gdt_x64::limit_type = uint32_t

Definition at line 198 of file gdt_x64.h.

◆ access_rights_type

using gdt_x64::access_rights_type = uint32_t

Definition at line 199 of file gdt_x64.h.

◆ segment_descriptor_type

Definition at line 200 of file gdt_x64.h.

Constructor & Destructor Documentation

◆ gdt_x64() [1/2]

gdt_x64::gdt_x64 ( )
inlinenoexcept

Constructor

Creates a GDT based on the GDT currently in hardware.

Precondition
expects: none
Postcondition
ensures: none
Note
This copies the current GDT. Therefore, the set functions do not modify the GDT that is in hardware, but instead modify the copy. If you want to modify the GDT that is in hardware, create a new GDT using an alternate constructor, and set the hardware to use that GDT instead.

Definition at line 215 of file gdt_x64.h.

◆ gdt_x64() [2/2]

gdt_x64::gdt_x64 ( size_type  size)
inlinenoexcept

Constructor

Creates a new GDT, with size defining the number of descriptors in the GDT.

Postcondition
ensures: none
ensures: none
Parameters
sizenumber of entries in the GDT

Definition at line 236 of file gdt_x64.h.

◆ ~gdt_x64()

gdt_x64::~gdt_x64 ( )
defaultnoexcept

Destructor

Precondition
expects: none
Postcondition
ensures: none

Member Function Documentation

◆ base() [1/2]

integer_pointer gdt_x64::base ( ) const
inline

GDT Base Address

Precondition
expects: none
Postcondition
ensures: none
Returns
returns the base address of the GDT itself.

Definition at line 260 of file gdt_x64.h.

◆ limit() [1/2]

size_type gdt_x64::limit ( ) const
inline

GDT Limit

Precondition
expects: none
Postcondition
ensures: none
Returns
returns the size of the GDT itself in bytes

Definition at line 270 of file gdt_x64.h.

◆ set_base()

void gdt_x64::set_base ( index_type  index,
base_type  base 
)
inline

Set Descriptor Base Address

Sets the base address of a descriptor. If the descriptor is a TSS (determined using the system descriptor flag), the base address is a 64bit address, and this operation will attempt to touch 2 64bit descriptor fields. So, if the TSS is at the end of the GDT (like they usually are) make sure you give yourself space for 2 entries for the TSS, otherwise this code will throw an invalid_argument exception. Also, since the access rights determine the descriptor type, make sure you set them first.

Precondition
expects: index != 0
expects: index < m_gdt.size()
expects: index < m_gdt.size() + 1 (if system descriptor)
Postcondition
ensures: none
Parameters
indexthe index of the GDT descriptor
basethe base address. For code/data descriptor this needs to be 0, and for a TSS this is a 64bit virtual address.

Definition at line 293 of file gdt_x64.h.

◆ base() [2/2]

base_type gdt_x64::base ( index_type  index) const
inline

Get Descriptor Base Address

Gets the base address of a descriptor. If the descriptor is a TSS (determined using the system descriptor flag), the base address is a 64bit address, and this operation will attempt to touch 2 64bit descriptor fields. So, if the TSS is at the end of the GDT (like they usually are) make sure you give yourself space for 2 entries for the TSS, otherwise this code will throw an invalid_argument exception. Also, since the access rights determine the descriptor type, make sure you set them first.

Precondition
expects: index != 0
expects: index < m_gdt.size()
expects: index < m_gdt.size() + 1 (if system descriptor)
Postcondition
ensures: none
Parameters
indexthe index of the GDT descriptor
Returns
the base address

Definition at line 360 of file gdt_x64.h.

◆ set_limit()

void gdt_x64::set_limit ( index_type  index,
limit_type  limit 
)
inline

Set Descriptor Limit

Sets the descriptors limit. Note that for code/data descriptors, this needs to be 0xFFFFF as segmentation is not used in 64bit. For the TSS, the limit should be the size in bytes of the TSS, and any other data you wish to store.

Precondition
expects: index != 0
expects: index < m_gdt.size()
Postcondition
ensures: none
Parameters
indexthe index of the GDT descriptor
limitthe descriptors limit

Definition at line 416 of file gdt_x64.h.

◆ limit() [2/2]

limit_type gdt_x64::limit ( index_type  index) const
inline

Get Descriptor Limit

Gets the descriptors limit.

Precondition
expects: index != 0
expects: index < m_gdt.size()
Postcondition
ensures: none
Parameters
indexthe index of the GDT descriptor
Returns
the descriptors limit

Definition at line 451 of file gdt_x64.h.

◆ set_access_rights()

void gdt_x64::set_access_rights ( index_type  index,
access_rights_type  access_rights 
)
inline

Set Descriptor Access Rights

Sets the descriptors access rights. Note that Intel defines this field a little strange. Unlike the base and limit, where the fields and merged, the access rights leaves the upper "limit" bits in the access rights, so you have to leave bits 8-11 as 0 as these are bits 16-19 of the limit field. Also, each bit in the access rights field has a different meaning based on which segment register is used. If CS is used, the descriptor is a code segment, if TR is used the descriptor is a TSS descriptor, if SS is used the segment is a stack segment, and all others are data segments. For a complete list of what each bit does (based on what segment register is loading this descriptor), please see the Intel manual.

Precondition
expects: index != 0
expects: index < m_gdt.size()
Postcondition
ensures: none
Parameters
indexthe index of the GDT descriptor
access_rightsthe access rights for this descriptor

Definition at line 501 of file gdt_x64.h.

◆ access_rights()

access_rights_type gdt_x64::access_rights ( index_type  index) const
inline

Get Descriptor Access Rights

Gets the access rights for the descriptor

Precondition
expects: index != 0
expects: index < m_gdt.size()
Postcondition
ensures: none
Parameters
indexthe index of the GDT descriptor
Returns
the descriptors access rights

Definition at line 534 of file gdt_x64.h.


The documentation for this class was generated from the following file: