summaryrefslogtreecommitdiff
path: root/Kernel/Arch/x86_64/DescriptorTable.h
blob: be5dc1273b5f95453a8024ce68e723b1d10b30db (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
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
/*
 * Copyright (c) 2018-2021, Andreas Kling <kling@serenityos.org>
 * Copyright (c) 2021, Leon Albrecht <leon2002.la@gmail.com>
 *
 * SPDX-License-Identifier: BSD-2-Clause
 */

#pragma once

#include <AK/Types.h>
#include <Kernel/Memory/VirtualAddress.h>

#include <AK/Platform.h>
VALIDATE_IS_X86()

// Note: These values are x86-64.
#define GDT_SELECTOR_CODE0 0x08
#define GDT_SELECTOR_DATA0 0x10
#define GDT_SELECTOR_DATA3 0x18
#define GDT_SELECTOR_CODE3 0x20
#define GDT_SELECTOR_TSS 0x28
#define GDT_SELECTOR_TSS_PART2 0x30

namespace Kernel {

struct [[gnu::packed]] DescriptorTablePointer {
    u16 limit;
    void* address;
};

union [[gnu::packed]] Descriptor {
    struct {
        u16 limit_lo;
        u16 base_lo;
        u8 base_hi;
        u8 type : 4;
        u8 descriptor_type : 1;
        u8 dpl : 2;
        u8 segment_present : 1;
        u8 limit_hi : 4;
        u8 : 1;
        u8 operation_size64 : 1;
        u8 operation_size32 : 1;
        u8 granularity : 1;
        u8 base_hi2;
    };
    struct {
        u32 low;
        u32 high;
    };

    enum SystemType {
        Invalid = 0,
        AvailableTSS_16bit = 0x1,
        LDT = 0x2,
        BusyTSS_16bit = 0x3,
        CallGate_16bit = 0x4,
        TaskGate = 0x5,
        InterruptGate_16bit = 0x6,
        TrapGate_16bit = 0x7,
        AvailableTSS = 0x9,
        BusyTSS = 0xb,
        CallGate = 0xc,
        InterruptGate = 0xe,
        TrapGate = 0xf,
    };

    VirtualAddress base() const
    {
        FlatPtr base = base_lo;
        base |= base_hi << 16u;
        base |= base_hi2 << 24u;
        return VirtualAddress { base };
    }

    void set_base(VirtualAddress base)
    {
        base_lo = base.get() & 0xffffu;
        base_hi = (base.get() >> 16u) & 0xffu;
        base_hi2 = (base.get() >> 24u) & 0xffu;
        VERIFY(base.get() <= 0xffffffff);
    }

    void set_limit(u32 length)
    {
        limit_lo = length & 0xffff;
        limit_hi = (length >> 16) & 0xf;
    }
};

static_assert(AssertSize<Descriptor, 8>());

enum class IDTEntryType {
    TaskGate32 = 0b0101,
    InterruptGate16 = 0b110,
    TrapGate16 = 0b111,
    InterruptGate32 = 0b1110,
    TrapGate32 = 0b1111,
};

// Clang doesn't format this right due to the compiler magic
// clang-format off
struct [[gnu::packed]] IDTEntry
{
    u16 offset_1; // offset bits 0..15
    u16 selector; // a code segment selector in GDT or LDT

    struct {
        u8 interrupt_stack_table : 3;
        u8 zero : 5; // unused, set to 0
    };

    struct {
        u8 gate_type : 4;
        u8 storage_segment : 1;
        u8 descriptor_privilege_level : 2;
        u8 present : 1;
    } type_attr;  // type and attributes
    u16 offset_2; // offset bits 16..31
    u32 offset_3;
    u32 zeros;

    IDTEntry() = default;
    IDTEntry(FlatPtr callback, u16 selector_, IDTEntryType type, u8 storage_segment, u8 privilege_level)
        : offset_1 { (u16)((FlatPtr)callback & 0xFFFF) }
        , selector { selector_ }
        , interrupt_stack_table { 0 }
        , zero { 0 }
        , type_attr {
            .gate_type = (u8)type,
            .storage_segment = storage_segment,
            .descriptor_privilege_level = (u8)(privilege_level & 0b11),
            .present = 1,
        }
        , offset_2 { (u16)((FlatPtr)callback >> 16) }
        , offset_3 { (u32)(((FlatPtr)callback) >> 32) }
        , zeros { 0 }
    {
    }

    FlatPtr off() const
    {
        return (u64)offset_3 << 32 & (u64)offset_2 << 16 & (u64)offset_1;
    }
    IDTEntryType type() const
    {
        return IDTEntryType(type_attr.gate_type);
    }
};
// clang-format on

static_assert(AssertSize<IDTEntry, 2 * sizeof(void*)>());

}