Descriptors: Difference between revisions

From OSDev.wiki
Jump to navigation Jump to search
[unchecked revision][unchecked revision]
Content added Content deleted
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._
:_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]; };
};
};
</verbatim>
</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
};
};
</verbatim>
</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);
};
};
</verbatim>
</pre>


!! Type bits for Data segments
==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
==Type bits for Code segments==


bit 3 |
bit 3 |

Revision as of 18:10, 5 April 2007

Template:Convert


_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_