aboutsummaryrefslogtreecommitdiff
path: root/src/gdt.h
blob: 99a6da2dbe74d22db86609dee4cf89589cb12502 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
#pragma once

#include <types.h>

/* From OSDev wiki:
 *
 * Segment
 * a logically contiguous chunk of memory with consistent properties (CPU's speaking)
 *
 * Segment Register
 * a register of your CPU that refers to a segment for a special use (e.g. SS, CS, DS ...)
 *
 * Selector
 * a reference to a descriptor you can load into a segment register; the selector is an offset of a descriptor table
 * entry. These entries are 8 bytes long. Therefore, bits 3 and up only declare the descriptor table entry offset, while
 * bit 2 specifies if this selector is a GDT or LDT selector (LDT - bit set, GDT - bit cleared), and bits 0 - 1 declare
 * the ring level that needs to correspond to the descriptor table entry's DPL field. If it doesn't, a General
 * Protection Fault occurs; if it does correspond then the CPL level of the selector used is changed accordingly.
 *
 * Descriptor
 * a memory structure (part of a table) that tells the CPU the attributes of a given segment
 */

class GDT {
public:
  GDT();
  ~GDT() = default;

  struct Pointer {
    uint16_t limit;
    uint32_t base;
  } __attribute((packed));

  class SegmentDescriptor {
  public:
    SegmentDescriptor(uint32_t base = 0, uint32_t limit = 0, uint8_t type = 0);
    [[nodiscard]] uint32_t base() const;
    [[nodiscard]] uint32_t limit() const;

  private:
    /*
     * |31|  |  |  |  |  |  |24|23|22|  |20|19|  |  |16|15|  |  |12|11|  |  | 8| 7|  |  |  |  |  |  | 0|
     * | base (24~31)          | G|DB|  | A| lim(16~19)| P| DPL | S|    Type   |   base (16~23)        |
     * | base (0~15)                                   | limit (0~15)                                  |
     * |31|  |  |  |  |  |  |  |  |  |  |  |  |  |  |16|15|  |  |  |  |  |  |  |  |  |  |  |  |  |  | 0|
     *
     * limit    size of segment - 1, either in bytes or in 4KiB chunks (check flags)
     * base     address of segment
     * access
     * flags    defines the segment chunks and 16/32 bit
     */

    uint16_t limit_low;
    uint16_t base_low;
    uint8_t base_high;
    uint8_t type;
    uint8_t flags_limit_high;
    uint8_t base_vhigh;
  } __attribute__((packed));

private:
  SegmentDescriptor segments[256];
};

static_assert(sizeof(GDT::Pointer) == 6);
static_assert(sizeof(GDT::SegmentDescriptor) == 8);