DescriptorTable.h 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184
  1. /*
  2. * Copyright (c) 2018-2021, Andreas Kling <kling@serenityos.org>
  3. * Copyright (c) 2021, Leon Albrecht <leon2002.la@gmail.com>
  4. *
  5. * SPDX-License-Identifier: BSD-2-Clause
  6. */
  7. #pragma once
  8. #include <AK/StdLibExtras.h>
  9. #include <AK/Types.h>
  10. #include <Kernel/VirtualAddress.h>
  11. #include <AK/Platform.h>
  12. VALIDATE_IS_X86()
  13. #if ARCH(I386)
  14. # define GDT_SELECTOR_CODE0 0x08
  15. # define GDT_SELECTOR_DATA0 0x10
  16. # define GDT_SELECTOR_CODE3 0x18
  17. # define GDT_SELECTOR_DATA3 0x20
  18. # define GDT_SELECTOR_TLS 0x28
  19. # define GDT_SELECTOR_PROC 0x30
  20. # define GDT_SELECTOR_TSS 0x38
  21. // SYSENTER makes certain assumptions on how the GDT is structured:
  22. static_assert(GDT_SELECTOR_CODE0 + 8 == GDT_SELECTOR_DATA0); // SS0 = CS0 + 8
  23. // SYSEXIT makes certain assumptions on how the GDT is structured:
  24. static_assert(GDT_SELECTOR_CODE0 + 16 == GDT_SELECTOR_CODE3); // CS3 = CS0 + 16
  25. static_assert(GDT_SELECTOR_CODE0 + 24 == GDT_SELECTOR_DATA3); // SS3 = CS0 + 32
  26. #else
  27. # define GDT_SELECTOR_CODE0 0x08
  28. # define GDT_SELECTOR_DATA0 0x10
  29. # define GDT_SELECTOR_DATA3 0x18
  30. # define GDT_SELECTOR_CODE3 0x20
  31. # define GDT_SELECTOR_TSS 0x28
  32. # define GDT_SELECTOR_TSS_PART2 0x30
  33. #endif
  34. namespace Kernel {
  35. struct [[gnu::packed]] DescriptorTablePointer {
  36. u16 limit;
  37. void* address;
  38. };
  39. union [[gnu::packed]] Descriptor {
  40. struct {
  41. u16 limit_lo;
  42. u16 base_lo;
  43. u8 base_hi;
  44. u8 type : 4;
  45. u8 descriptor_type : 1;
  46. u8 dpl : 2;
  47. u8 segment_present : 1;
  48. u8 limit_hi : 4;
  49. u8 : 1;
  50. u8 operation_size64 : 1;
  51. u8 operation_size32 : 1;
  52. u8 granularity : 1;
  53. u8 base_hi2;
  54. };
  55. struct {
  56. u32 low;
  57. u32 high;
  58. };
  59. enum Type {
  60. Invalid = 0,
  61. AvailableTSS_16bit = 0x1,
  62. LDT = 0x2,
  63. BusyTSS_16bit = 0x3,
  64. CallGate_16bit = 0x4,
  65. TaskGate = 0x5,
  66. InterruptGate_16bit = 0x6,
  67. TrapGate_16bit = 0x7,
  68. AvailableTSS_32bit = 0x9,
  69. BusyTSS_32bit = 0xb,
  70. CallGate_32bit = 0xc,
  71. InterruptGate_32bit = 0xe,
  72. TrapGate_32bit = 0xf,
  73. };
  74. VirtualAddress base() const
  75. {
  76. FlatPtr base = base_lo;
  77. base |= base_hi << 16u;
  78. base |= base_hi2 << 24u;
  79. return VirtualAddress { base };
  80. }
  81. void set_base(VirtualAddress base)
  82. {
  83. base_lo = base.get() & 0xffffu;
  84. base_hi = (base.get() >> 16u) & 0xffu;
  85. base_hi2 = (base.get() >> 24u) & 0xffu;
  86. VERIFY(base.get() <= 0xffffffff);
  87. }
  88. void set_limit(u32 length)
  89. {
  90. limit_lo = length & 0xffff;
  91. limit_hi = (length >> 16) & 0xf;
  92. }
  93. };
  94. static_assert(AssertSize<Descriptor, 8>());
  95. enum class IDTEntryType {
  96. TaskGate32 = 0b0101,
  97. InterruptGate16 = 0b110,
  98. TrapGate16 = 0b111,
  99. InterruptGate32 = 0b1110,
  100. TrapGate32 = 0b1111,
  101. };
  102. // Clang doesn't format this right due to the compiler magic
  103. // clang-format off
  104. struct [[gnu::packed]] IDTEntry
  105. {
  106. u16 offset_1; // offset bits 0..15
  107. u16 selector; // a code segment selector in GDT or LDT
  108. #if ARCH(I386)
  109. u8 zero; // unused, set to 0
  110. #else
  111. struct {
  112. u8 interrupt_stack_table : 3;
  113. u8 zero : 5; // unused, set to 0
  114. };
  115. #endif
  116. struct {
  117. u8 gate_type : 4;
  118. u8 storage_segment : 1;
  119. u8 descriptor_privilege_level : 2;
  120. u8 present : 1;
  121. } type_attr; // type and attributes
  122. u16 offset_2; // offset bits 16..31
  123. #if !ARCH(I386)
  124. u32 offset_3;
  125. u32 zeros;
  126. #endif
  127. IDTEntry() = default;
  128. IDTEntry(FlatPtr callback, u16 selector_, IDTEntryType type, u8 storage_segment, u8 privilege_level)
  129. : offset_1 { (u16)((FlatPtr)callback & 0xFFFF) }
  130. , selector { selector_ }
  131. #if !ARCH(I386)
  132. , interrupt_stack_table { 0 }
  133. #endif
  134. , zero { 0 }
  135. , type_attr {
  136. .gate_type = (u8)type,
  137. .storage_segment = storage_segment,
  138. .descriptor_privilege_level = (u8)(privilege_level & 0b11),
  139. .present = 1,
  140. }
  141. , offset_2 { (u16)((FlatPtr)callback >> 16) }
  142. #if !ARCH(I386)
  143. , offset_3 { (u32)(((FlatPtr)callback) >> 32) }
  144. , zeros { 0 }
  145. #endif
  146. {
  147. }
  148. FlatPtr off() const
  149. {
  150. #if ARCH(I386)
  151. return (u32)offset_2 << 16 & (u32)offset_1;
  152. #else
  153. return (u64)offset_3 << 32 & (u64)offset_2 << 16 & (u64)offset_1;
  154. #endif
  155. }
  156. IDTEntryType type() const
  157. {
  158. return IDTEntryType(type_attr.gate_type);
  159. }
  160. };
  161. // clang-format on
  162. static_assert(AssertSize<IDTEntry, 2 * sizeof(void*)>());
  163. }