DescriptorTable.h 4.3 KB

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