gdt_x64.h
Go to the documentation of this file.
1 //
2 // Bareflank Hypervisor
3 //
4 // Copyright (C) 2015 Assured Information Security, Inc.
5 // Author: Rian Quinn <quinnr@ainfosec.com>
6 // Author: Brendan Kerrigan <kerriganb@ainfosec.com>
7 //
8 // This library is free software; you can redistribute it and/or
9 // modify it under the terms of the GNU Lesser General Public
10 // License as published by the Free Software Foundation; either
11 // version 2.1 of the License, or (at your option) any later version.
12 //
13 // This library is distributed in the hope that it will be useful,
14 // but WITHOUT ANY WARRANTY; without even the implied warranty of
15 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 // Lesser General Public License for more details.
17 //
18 // You should have received a copy of the GNU Lesser General Public
19 // License along with this library; if not, write to the Free Software
20 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21 
22 #ifndef GDT_X64_H
23 #define GDT_X64_H
24 
25 #include <gsl/gsl>
26 
27 #include <vector>
28 #include <algorithm>
29 #include <exception>
30 
31 #include <guard_exceptions.h>
32 
33 // -----------------------------------------------------------------------------
34 // Global Descriptor Table Register
35 // -----------------------------------------------------------------------------
36 
37 #pragma pack(push, 1)
38 
40 {
41  using limit_type = uint16_t;
42  using base_type = uint64_t *;
43 
46 
48  limit(0),
49  base(nullptr)
50  {}
51 
53  limit(l),
54  base(b)
55  {}
56 };
57 
58 #pragma pack(pop)
59 
60 // -----------------------------------------------------------------------------
61 // Intrinsics
62 // -----------------------------------------------------------------------------
63 
64 extern "C" void __read_gdt(gdt_reg_x64_t *gdt_reg) noexcept;
65 extern "C" void __write_gdt(gdt_reg_x64_t *gdt_reg) noexcept;
66 
67 // -----------------------------------------------------------------------------
68 // GDT Functions
69 // -----------------------------------------------------------------------------
70 
71 // *INDENT-OFF*
72 
73 namespace x64
74 {
75 namespace gdt
76 {
77  inline auto get() noexcept
78  {
79  auto &&reg = gdt_reg_x64_t{};
80  __read_gdt(&reg);
81 
82  return reg;
83  }
84 
86  {
87  auto &&reg = gdt_reg_x64_t{base, limit};
88  __write_gdt(&reg);
89  }
90 
91  namespace base
92  {
93  inline auto get() noexcept
94  {
95  auto &&reg = gdt_reg_x64_t{};
96  __read_gdt(&reg);
97 
98  return reg.base;
99  }
100 
101  inline void set(gdt_reg_x64_t::base_type base) noexcept
102  {
103  auto &&reg = gdt_reg_x64_t{};
104  __read_gdt(&reg);
105 
106  reg.base = base;
107  __write_gdt(&reg);
108  }
109  }
110 
111  namespace limit
112  {
113  inline auto get() noexcept
114  {
115  auto &&reg = gdt_reg_x64_t{};
116  __read_gdt(&reg);
117 
118  return reg.limit;
119  }
120 
121  inline void set(gdt_reg_x64_t::limit_type limit) noexcept
122  {
123  auto &&reg = gdt_reg_x64_t{};
124  __read_gdt(&reg);
125 
126  reg.limit = limit;
127  __write_gdt(&reg);
128  }
129  }
130 }
131 }
132 
133 // *INDENT-ON*
134 
135 // -----------------------------------------------------------------------------
136 // Global Descriptor Table
137 // -----------------------------------------------------------------------------
138 
190 class gdt_x64
191 {
192 public:
193 
194  using size_type = uint16_t;
195  using index_type = uint16_t;
196  using integer_pointer = uintptr_t;
197  using base_type = uint64_t;
198  using limit_type = uint32_t;
199  using access_rights_type = uint32_t;
200  using segment_descriptor_type = uint64_t;
201 
216  {
217  guard_exceptions([&]
218  {
219  m_gdt_reg.base = x64::gdt::base::get();
220  m_gdt_reg.limit = x64::gdt::limit::get();
221 
222  std::copy_n(m_gdt_reg.base, m_gdt_reg.limit >> 3, std::back_inserter(m_gdt));
223  });
224  }
225 
237  m_gdt(size)
238  {
239  guard_exceptions([&]
240  {
241  m_gdt_reg.base = m_gdt.data();
242  m_gdt_reg.limit = gsl::narrow_cast<size_type>(size << 3);
243  });
244  }
245 
251  ~gdt_x64() noexcept = default;
252 
261  { return reinterpret_cast<integer_pointer>(m_gdt_reg.base); }
262 
270  size_type limit() const
271  { return m_gdt_reg.limit; }
272 
294  {
295  segment_descriptor_type sd1 = 0;
296  segment_descriptor_type sd2 = 0;
297 
298  expects(index != 0);
299 
300  sd1 = m_gdt.at(index);
301  sd1 = (sd1 & 0x00FFFF000000FFFF);
302 
303  // The segment base description can be found in the Intel's software
304  // developer's manual, volume 3, chapter 3.4.5 as well as volume 3,
305  // chapter 24.4.1.
306  //
307  // Note that in 64bit mode, system descriptors are 16 bytes long
308  // instead of the traditional 8 bytes. A system descriptor has the
309  // system flag set to 0. Most of the time, this is going to be the
310  // TSS descriptor. Even though Intel Tasks don't exist in 64 bit mode,
311  // the TSS descriptor is still used, and thus, TR must still be loaded.
312  //
313  // ------------------------------------------------------------------
314  // | Base 63-32 |
315  // ------------------------------------------------------------------
316  // | Base 31-24 | | Base 23-16 |
317  // ------------------------------------------------------------------
318  // | Base 15-00 | |
319  // ------------------------------------------------------------------
320  //
321 
322  segment_descriptor_type base_15_00 = ((base & 0x000000000000FFFF) << 16);
323  segment_descriptor_type base_23_16 = ((base & 0x0000000000FF0000) << 16);
324  segment_descriptor_type base_31_24 = ((base & 0x00000000FF000000) << 32);
325  segment_descriptor_type base_63_32 = ((base & 0xFFFFFFFF00000000) >> 32);
326 
327  if ((sd1 & 0x100000000000) == 0)
328  {
329  sd2 = m_gdt.at(index + 1U);
330  sd2 = (sd2 & 0xFFFFFFFF00000000);
331 
332  m_gdt.at(index + 0U) = sd1 | base_31_24 | base_23_16 | base_15_00;
333  m_gdt.at(index + 1U) = sd2 | base_63_32;
334  }
335  else
336  {
337  m_gdt.at(index + 0U) = sd1 | base_31_24 | base_23_16 | base_15_00;
338  }
339  }
340 
361  {
362  segment_descriptor_type sd1 = 0;
363  segment_descriptor_type sd2 = 0;
364 
365  expects(index != 0);
366 
367  // The segment base description can be found in the Intel's software
368  // developer's manual, volume 3, chapter 3.4.5 as well as volume 3,
369  // chapter 24.4.1.
370  //
371  // Note that in 64bit mode, system descriptors are 16 bytes long
372  // instead of the traditional 8 bytes. A system descriptor has the
373  // system flag set to 0. Most of the time, this is going to be the
374  // TSS descriptor. Even though Intel Tasks don't exist in 64 bit mode,
375  // the TSS descriptor is still used, and thus, TR must still be loaded.
376  //
377  // ------------------------------------------------------------------
378  // | Base 63-32 |
379  // ------------------------------------------------------------------
380  // | Base 31-24 | | Base 23-16 |
381  // ------------------------------------------------------------------
382  // | Base 15-00 | |
383  // ------------------------------------------------------------------
384  //
385 
386  sd1 = m_gdt.at(index);
387  base_type base_15_00 = ((sd1 & 0x00000000FFFF0000) >> 16);
388  base_type base_23_16 = ((sd1 & 0x000000FF00000000) >> 16);
389  base_type base_31_24 = ((sd1 & 0xFF00000000000000) >> 32);
390 
391  if ((sd1 & 0x100000000000) == 0)
392  {
393  sd2 = m_gdt.at(index + 1U);
394  base_type base_63_32 = ((sd2 & 0x00000000FFFFFFFF) << 32);
395 
396  return base_63_32 | base_31_24 | base_23_16 | base_15_00;
397  }
398 
399  return base_31_24 | base_23_16 | base_15_00;
400  }
401 
417  {
418  expects(index != 0);
419  segment_descriptor_type sd1 = (m_gdt.at(index) & 0xFFF0FFFFFFFF0000);
420 
421  // The segment limit description can be found in the Intel's software
422  // developer's manual, volume 3, chapter 3.4.5 as well as volume 3,
423  // chapter 24.4.1.
424  //
425  // ------------------------------------------------------------------
426  // | | Limit 19-16 | |
427  // ------------------------------------------------------------------
428  // | | Limit 15-00 |
429  // ------------------------------------------------------------------
430 
431  if ((sd1 & 0x80000000000000) != 0)
432  limit = (limit >> 12);
433 
434  segment_descriptor_type limit_15_00 = ((static_cast<segment_descriptor_type>(limit) & 0x000000000000FFFF) << 0);
435  segment_descriptor_type limit_19_16 = ((static_cast<segment_descriptor_type>(limit) & 0x00000000000F0000) << 32);
436 
437  m_gdt.at(index) = sd1 | limit_19_16 | limit_15_00;
438  }
439 
452  {
453  expects(index != 0);
454  segment_descriptor_type sd1 = m_gdt.at(index);
455 
456  // The segment limit description can be found in the Intel's software
457  // developer's manual, volume 3, chapter 3.4.5 as well as volume 3,
458  // chapter 24.4.1.
459  //
460  // ------------------------------------------------------------------
461  // | | Limit 19-16 | |
462  // ------------------------------------------------------------------
463  // | | Limit 15-00 |
464  // ------------------------------------------------------------------
465 
466  if ((sd1 & 0x80000000000000) != 0)
467  {
468  limit_type limit_15_00 = gsl::narrow_cast<limit_type>((sd1 & 0x000000000000FFFF) >> 0);
469  limit_type limit_19_16 = gsl::narrow_cast<limit_type>((sd1 & 0x000F000000000000) >> 32);
470 
471  return ((limit_19_16 | limit_15_00) << 12) | 0x0000000000000FFF;
472  }
473 
474  limit_type limit_15_00 = gsl::narrow_cast<limit_type>((sd1 & 0x000000000000FFFF) >> 0);
475  limit_type limit_19_16 = gsl::narrow_cast<limit_type>((sd1 & 0x000F000000000000) >> 32);
476 
477  return limit_19_16 | limit_15_00;
478  }
479 
502  {
503  expects(index != 0);
504  segment_descriptor_type sd1 = (m_gdt.at(index) & 0xFF0F00FFFFFFFFFF);
505 
506  // The segment access description can be found in the intel's software
507  // developer's manual, volume 3, chapter 3.4.5 as well as volume 3,
508  // chapter 24.4.1.
509  //
510  // ------------------------------------------------------------------
511  // | | A 15-12 | | Access 07-00 | |
512  // ------------------------------------------------------------------
513  // | | |
514  // ------------------------------------------------------------------
515  //
516 
517  segment_descriptor_type access_rights_07_00 = ((static_cast<segment_descriptor_type>(access_rights) & 0x00000000000000FF) << 40);
518  segment_descriptor_type access_rights_15_12 = ((static_cast<segment_descriptor_type>(access_rights) & 0x000000000000F000) << 40);
519 
520  m_gdt.at(index) = sd1 | access_rights_15_12 | access_rights_07_00;
521  }
522 
535  {
536  expects(index != 0);
537  segment_descriptor_type sd1 = m_gdt.at(index);
538 
539  // The segment access description can be found in the Intel's software
540  // developer's manual, volume 3, chapter 3.4.5 as well as volume 3,
541  // chapter 24.4.1.
542  //
543  // ------------------------------------------------------------------
544  // | | A 15-12 | | Access 07-00 | |
545  // ------------------------------------------------------------------
546  // | | |
547  // ------------------------------------------------------------------
548  //
549 
550  access_rights_type access_rights_07_00 = static_cast<access_rights_type>((sd1 & 0x0000FF0000000000) >> 40);
551  access_rights_type access_rights_15_12 = static_cast<access_rights_type>((sd1 & 0x00F0000000000000) >> 40);
552 
553  return access_rights_15_12 | access_rights_07_00;
554  }
555 
556 private:
557 
558  friend class intrinsics_ut;
559 
560  gdt_reg_x64_t m_gdt_reg;
561  std::vector<segment_descriptor_type> m_gdt;
562 };
563 
564 #endif
expects(rbx)
base_type base
Definition: gdt_x64.h:45
uint64_t segment_descriptor_type
Definition: gdt_x64.h:200
gdt_x64(size_type size) noexcept
Definition: gdt_x64.h:236
access_rights_type access_rights(index_type index) const
Definition: gdt_x64.h:534
void __write_gdt(gdt_reg_x64_t *gdt_reg) noexcept
void set_base(index_type index, base_type base)
Definition: gdt_x64.h:293
gdt_reg_x64_t() noexcept
Definition: gdt_x64.h:47
void set_access_rights(index_type index, access_rights_type access_rights)
Definition: gdt_x64.h:501
void set_limit(index_type index, limit_type limit)
Definition: gdt_x64.h:416
~gdt_x64() noexcept=default
uint16_t limit_type
Definition: gdt_x64.h:41
uint16_t index_type
Definition: gdt_x64.h:195
constexpr const auto size
void uint64_t uint64_t uint64_t *rdx noexcept
auto get() noexcept
Definition: gdt_x64.h:113
auto index(const T virt, const F from)
gdt_reg_x64_t(base_type b, limit_type l) noexcept
Definition: gdt_x64.h:52
limit_type limit(index_type index) const
Definition: gdt_x64.h:451
uint32_t access_rights_type
Definition: gdt_x64.h:199
uint64_t base_type
Definition: gdt_x64.h:197
uint64_t * base_type
Definition: gdt_x64.h:42
auto get() noexcept
Definition: gdt_x64.h:93
void __read_gdt(gdt_reg_x64_t *gdt_reg) noexcept
gdt_x64() noexcept
Definition: gdt_x64.h:215
size_type limit() const
Definition: gdt_x64.h:270
E guard_exceptions(E error_code, T func)
Definition: cache_x64.h:31
uintptr_t integer_pointer
Definition: gdt_x64.h:196
uint32_t limit_type
Definition: gdt_x64.h:198
base_type base(index_type index) const
Definition: gdt_x64.h:360
limit_type limit
Definition: gdt_x64.h:44
uint16_t size_type
Definition: gdt_x64.h:194