DescriptorTable.h 4.3 KB

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