Descriptors: Difference between revisions
[unchecked revision] | [unchecked revision] |
No edit summary |
No edit summary |
||
Line 2: | Line 2: | ||
:_There is also [descriptor coverage in BabySteps tutorial|BabyStep6]. This is intended as a reference, with exhaustive coverage of various descriptor types, their structs and options, which can be used both for analysis of existing descriptors and for synthesis of your own._ |
|||
Descriptors are one of the key structures of Protected Mode. They are used to hold information about various system objects and are used as entries in the three system tables - GDT, LDT and [IDT]. |
Descriptors are one of the key structures of Protected Mode. They are used to hold information about various system objects and are used as entries in the three system tables - GDT, LDT and [IDT]. |
||
Line 10: | Line 10: | ||
One thing they all have in common is the "type_attr" field (byte at offset 5) that contains descriptor type and some common attributes. Thus, if you have a descriptor of yet unknown type, you should look at the "type_attr" byte to find out the type. (Maybe you want to analyze and display the contents of some table) |
One thing they all have in common is the "type_attr" field (byte at offset 5) that contains descriptor type and some common attributes. Thus, if you have a descriptor of yet unknown type, you should look at the "type_attr" byte to find out the type. (Maybe you want to analyze and display the contents of some table) |
||
<pre> |
|||
<verbatim> |
|||
// a "general" structure of a descriptor whose type we don't know, |
// a "general" structure of a descriptor whose type we don't know, |
||
// only for the sake of discussion - you will want to use a more specific structure |
// only for the sake of discussion - you will want to use a more specific structure |
||
Line 19: | Line 19: | ||
uint8 type_attr(){ return bytes[5]; }; |
uint8 type_attr(){ return bytes[5]; }; |
||
}; |
}; |
||
</ |
</prem> |
||
#[|type_attr]"type_attr" has the following bit fields: |
#[|type_attr]"type_attr" has the following bit fields: |
||
Line 45: | Line 45: | ||
These have S=1. Bit 3 of "type" indicates whether it's (0) Data or (1) Code. |
These have S=1. Bit 3 of "type" indicates whether it's (0) Data or (1) Code. |
||
<pre> |
|||
<verbatim> |
|||
struct SegDescr{ |
struct SegDescr{ |
||
uint16 limit_1; // limit, bits 0..15 |
uint16 limit_1; // limit, bits 0..15 |
||
Line 56: | Line 56: | ||
uint8 base_3; // base, bits 24..31 |
uint8 base_3; // base, bits 24..31 |
||
}; |
}; |
||
</ |
</pre> |
||
So we have (putting all chunks of each field together): |
So we have (putting all chunks of each field together): |
||
Line 105: | Line 105: | ||
<pre> |
|||
<verbatim> |
|||
// computing base and limit values - putting the bits together |
// computing base and limit values - putting the bits together |
||
Line 120: | Line 120: | ||
((lim_attr&0xf)<<16); |
((lim_attr&0xf)<<16); |
||
}; |
}; |
||
</ |
</pre> |
||
==Type bits for Data segments== |
|||
bit 3 | |
bit 3 | |
||
Line 140: | Line 140: | ||
1 (has been accessed) |
1 (has been accessed) |
||
==Type bits for Code segments== |
|||
bit 3 | |
bit 3 | |
Revision as of 18:10, 5 April 2007
- _There is also [descriptor coverage in BabySteps tutorial|BabyStep6]. This is intended as a reference, with exhaustive coverage of various descriptor types, their structs and options, which can be used both for analysis of existing descriptors and for synthesis of your own._
Descriptors are one of the key structures of Protected Mode. They are used to hold information about various system objects and are used as entries in the three system tables - GDT, LDT and [IDT].
All descriptors are 8 bytes in size, but different types may have different format.
One thing they all have in common is the "type_attr" field (byte at offset 5) that contains descriptor type and some common attributes. Thus, if you have a descriptor of yet unknown type, you should look at the "type_attr" byte to find out the type. (Maybe you want to analyze and display the contents of some table)
// a "general" structure of a descriptor whose type we don't know, // only for the sake of discussion - you will want to use a more specific structure // according to the type you're dealing with, or define a union for all types struct Descr{ uint8 bytes[8]; // --- accessor methods uint8 type_attr(){ return bytes[5]; }; }; </prem> #[|type_attr]"type_attr" has the following bit fields: * bit 7: "P" (Present) flag ** Indicates whether the descriptor is being used. Accessing an object through a descriptor which has P=0 will cause a General Protection Fault. * bits 5..6: DPL - Descriptor Privilege Level (2 bits, 0..3) ** Used to control access to the object described by the descriptor * bit 4: "S" - whether this is a data/code segment (S=1) or a system segment (some other object) (S=0). ** One can think of it as "(data/code) Segment" flag. This, combined with the "type" code, can be used to determine the descriptor type and structure. * bits 0..3: type (4 bits, 0..0xF) Here are the formulas: type | (type_attr & 0xF) S | ((type_attr>>4) & 1) DPL | ((type_attr>>5) & 3) P | ((type_attr>>7) & 1) !!! Code/Data Segment Descriptors These have S=1. Bit 3 of "type" indicates whether it's (0) Data or (1) Code. <pre> struct SegDescr{ uint16 limit_1; // limit, bits 0..15 uint16 base_1; // base, bits 0..15 uint8 base_2; // base, bits 16..23 uint8 type_attr; // type_attr uint8 lim_attr; //^ bits 0..3: limit, bits 16..19 //^ bits 4..7: additional data/code attributes uint8 base_3; // base, bits 24..31 };
So we have (putting all chunks of each field together):
- Base - 32 bits total
- Limit - 20 bits total
- when using G=0 (granularity: bytes), limit can be from 1b to 1Mb
- when using G=1 (granularity: pages), limit can be from 4Kb to 4Gb
Type bits interpretation (general, for details specific to data or code see below):
bit 3 |
Data/Code | 0 (data)
1 (code)
bit 2 |
E/C | Expand-down (data)
Conforming (code)
bit 1 |
W/R | Writeable (data)
Readable (code)
bit 0 |
A | Accessed (code, data)
Additional attributes from lim_attr (bits 4..7):
bit 7 |
G | Granularity | 0 (limit is in bytes)
1 (limit is in pages of 4096 bytes)
bit 6 |
D/B | Default operand size/Big | 0 for 16-bit segments
1 for 32-bit segments
bit 5 |
L | 64-bit code segment | 0 normally
1 if this is a 64-bit code segment in IA-32e mode
bit 4 |
AVL | Available | For use by system software
(your OS can use this as you choose)
// computing base and limit values - putting the bits together uint32 SegDescr::base(){ return base_1 | (base_2<<16) | (base_3<<24); }; uint32 SegDescr::limit(){ return limit_1 | ((lim_attr&0xf)<<16); };
Type bits for Data segments
bit 3 |
Data/Code | 0 (data)
bit 2 |
Expand-down | 0 (normal)
1 (expand-down FIXME how this works?)
bit 1 |
Writeable | 0 (read-only)
1 (read-write)
bit 0 |
Accessed | 0 (hasn't been accessed)
1 (has been accessed)
Type bits for Code segments
bit 3 |
Data/Code | 1 (code)
bit 2 |
Conforming | 0 (non-conforming)
1 (conforming FIXME how this works?)
bit 1 |
Readable | 0 (execute-only)
1 (executable and readable)
bit 0 |
Accessed | 0 (hasn't been accessed)
1 (has been accessed)
_to be continued_