aboutsummaryrefslogtreecommitdiff
path: root/i686/include/gdt.h
blob: 2bdfb229be5e8fa427e74c04023912cf9bf65a4a (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
#pragma once

#include <stdbool.h>
#include <stdint.h>

enum Ring { Ring0 = 0x0, Ring1 = 0x1, Ring2 = 0x2, Ring3 = 0x3 };

struct __attribute__((packed)) Access {
  unsigned accessed : 1;   /* if 0, is set by processor when accessed */
  unsigned readwrite : 1;  /* code seg: read toggle; data seg: write toggle */
  unsigned direction : 1;  /* code seg: conforming bit; data seg: direction bit */
  unsigned executable : 1; /* executable bit */
  unsigned segment : 1;    /* true for code/data; false for gates/tss */
  unsigned privilege : 2;  /* descriptor privilege level */
  unsigned present : 1;    /* true for every active segment */
};
/* _Static_assert(sizeof(struct Access) == 1, "access byte size"); */

static const struct Access null_access = {0, 0, 0, 0, 0, Ring0, 0};
static const struct Access ktext_access = {0, 1, 0, 1, 1, Ring0, 1};
static const struct Access kdata_access = {0, 1, 0, 0, 1, Ring0, 1};

/* Segment Descriptor
 * A memory structure (part of a table) that tells the CPU the attributes of a given segment
 * |31|  |  |  |  |  |  |24|23|22|21|20|19|  |  |16|15|  |  |  |  |  |  | 8| 7|  |  |  |  |  |  | 0|
 * |   base_31_24          | G|DB|  | A| lim_19_16 |   access              |   base_23_16          |
 * |   base_15_0                                   |   limit_15_0                                  |
 * |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 */
struct __attribute__((packed)) SegmentDescriptor_t {
  uint16_t limit_15_0;      /* low bits of segment limit */
  uint16_t base_15_0;       /* low bits of segment base address */
  uint8_t base_23_16;       /* middle bits of segment base address */
  uint8_t access;           /* access byte */
  unsigned limit_19_16 : 4; /* high bits of segment limit */
  /* flags */
  bool a : 1;           /* unused, available for software use */
  bool rsv : 1;         /* reserved */
  bool db : 1;          /* false => 16-bit seg; true => 32-bit seg */
  bool granularity : 1; /* limit scaled by 4k when set */
  uint8_t base_31_24;   /* high bits of segment address */
};
/* _Static_assert(sizeof(struct SegmentDescriptor_t) == 8, "segment descriptor size"); */

void SegmentDescriptor(struct SegmentDescriptor_t *self, unsigned base, unsigned limit, uint8_t access);

void gdt_install();

enum SegmentIndex {
  ktextDescriptor = 2 * sizeof(struct SegmentDescriptor_t),
  kdataDescriptor = 3 * sizeof(struct SegmentDescriptor_t)
};