[haiku-commits] haiku: hrev47207 - src/system/kernel/arch/x86/64 headers/private/kernel/arch/x86/64 src/system/libroot/os/arch/x86_64

  • From: pdziepak@xxxxxxxxxxx
  • To: haiku-commits@xxxxxxxxxxxxx
  • Date: Tue, 6 May 2014 18:48:38 +0200 (CEST)

hrev47207 adds 7 changesets to branch 'master'
old head: 5df1188e862b3653d810842ab52c00dc1ffc60e7
new head: 9db5b975f9ea2b942568eb57bbcce90a1c7420dc
overview: http://cgit.haiku-os.org/haiku/log/?qt=range&q=9db5b97+%5E5df1188

----------------------------------------------------------------------------

ea7e57c: libroot: enable c++11 in os/arch/x86_64

3446437: libroot/x86_64: minor improvements in TLS code
  
   * less inline asm
   * std::atomic<> instead of obsolete atomic_*()

f31c19b: libroot/x86_64: relax asm constraints in find_thread()

c1dc104: kernel/x86_64: enable c++11 in x86_64 specific code

cd59bf4: kernel/x86_64: x86_64 gdt handling code overhaul
  
  Virtually no functional change, just rewriting the code from
  "C in *.cpp files" to C++. Use of constexpr may be advantageous but
  that code is not performance critical anyway.

2b6d4bc: kernel/x86: add space between literal and identifier
  
  Due to introduction of user-defined suffixes C++11 requires that there
  is a space between literal and identifier to avoid ambiguity.

9db5b97: kernel/x86_64: rework of IDT handling code
  
  Similarly to previous patch regarding GDT this is mostly a rewrite of
  IDT handling code from C to C++. Thanks to constexpr IDT is now entirely
  generated at compile-time.

                                    [ Pawel Dziepak <pdziepak@xxxxxxxxxxx> ]

----------------------------------------------------------------------------

7 files changed, 313 insertions(+), 177 deletions(-)
headers/private/kernel/arch/x86/64/descriptors.h |  80 -----
src/system/kernel/arch/x86/64/descriptors.cpp    | 346 +++++++++++++++----
src/system/kernel/arch/x86/Jamfile               |   2 +
src/system/kernel/arch/x86/irq_routing_table.cpp |   2 +-
src/system/libroot/os/arch/x86_64/Jamfile        |   2 +
src/system/libroot/os/arch/x86_64/thread.cpp     |   4 +-
src/system/libroot/os/arch/x86_64/tls.cpp        |  54 ++-

############################################################################

Commit:      ea7e57c9666997c11e3020d0fa71753e2097840b
URL:         http://cgit.haiku-os.org/haiku/commit/?id=ea7e57c
Author:      Pawel Dziepak <pdziepak@xxxxxxxxxxx>
Date:        Mon May  5 15:07:25 2014 UTC

libroot: enable c++11 in os/arch/x86_64

----------------------------------------------------------------------------

diff --git a/src/system/libroot/os/arch/x86_64/Jamfile 
b/src/system/libroot/os/arch/x86_64/Jamfile
index 2cda1c6..26b8c27 100644
--- a/src/system/libroot/os/arch/x86_64/Jamfile
+++ b/src/system/libroot/os/arch/x86_64/Jamfile
@@ -1,5 +1,7 @@
 SubDir HAIKU_TOP src system libroot os arch x86_64 ;
 
+SubDirC++Flags -std=gnu++11 ;
+
 local architectureObject ;
 for architectureObject in [ MultiArchSubDirSetup x86_64 ] {
        on $(architectureObject) {

############################################################################

Commit:      344643740a95c2e3bcdc2286c3310527bcbb5844
URL:         http://cgit.haiku-os.org/haiku/commit/?id=3446437
Author:      Pawel Dziepak <pdziepak@xxxxxxxxxxx>
Date:        Mon May  5 15:07:55 2014 UTC

libroot/x86_64: minor improvements in TLS code

 * less inline asm
 * std::atomic<> instead of obsolete atomic_*()

----------------------------------------------------------------------------

diff --git a/src/system/libroot/os/arch/x86_64/tls.cpp 
b/src/system/libroot/os/arch/x86_64/tls.cpp
index 15925c2..48be907 100644
--- a/src/system/libroot/os/arch/x86_64/tls.cpp
+++ b/src/system/libroot/os/arch/x86_64/tls.cpp
@@ -1,4 +1,5 @@
 /*
+ * Copyright 2014, Paweł Dziepak, pdziepak@xxxxxxxxxxx.
  * Copyright 2012, Alex Smith, alex@xxxxxxxxxxxxxxxx.
  * Distributed under the terms of the MIT License.
  */
@@ -8,6 +9,8 @@
 #      define _NO_INLINE_ASM 1
 #endif
 
+#include <atomic>
+
 #include <runtime_loader/runtime_loader.h>
 
 #include <support/TLS.h>
@@ -22,54 +25,49 @@ struct tls_index {
 };
 
 
-static int32 gNextSlot = TLS_FIRST_FREE_SLOT;
+static std::atomic<int> gNextSlot(TLS_FIRST_FREE_SLOT);
+
+
+static inline void**
+get_tls()
+{
+       void** tls;
+       __asm__ __volatile__ ("movq     %%fs:0, %0" : "=r" (tls));
+       return tls;
+}
 
 
 int32
-tls_allocate(void)
+tls_allocate()
 {
-       int32 next = atomic_add(&gNextSlot, 1);
-       if (next >= TLS_MAX_KEYS)
-               return B_NO_MEMORY;
+       if (gNextSlot < TLS_MAX_KEYS) {
+               auto next = gNextSlot++;
+               if (next < TLS_MAX_KEYS)
+                       return next;
+       }
 
-       return next;
+       return B_NO_MEMORY;
 }
 
 
 void*
-tls_get(int32 _index)
+tls_get(int32 index)
 {
-       int64 index = _index;
-       void* ret;
-
-       __asm__ __volatile__ (
-               "movq   %%fs:(, %1, 8), %0"
-               : "=r" (ret) : "r" (index));
-       return ret;
+       return get_tls()[index];
 }
 
 
 void**
-tls_address(int32 _index)
+tls_address(int32 index)
 {
-       int64 index = _index;
-       void** ret;
-
-       __asm__ __volatile__ (
-               "movq   %%fs:0, %0\n\t"
-               "leaq   (%0, %1, 8), %0\n\t"
-               : "=&r" (ret) : "r" (index));
-       return ret;
+       return get_tls() + index;
 }
 
 
 void
-tls_set(int32 _index, void* value)
+tls_set(int32 index, void* value)
 {
-       int64 index = _index;
-       __asm__ __volatile__ (
-               "movq   %1, %%fs:(, %0, 8)"
-               : : "r" (index), "r" (value));
+       get_tls()[index] = value;
 }
 
 

############################################################################

Commit:      f31c19bb9e6abdd85acde7a900894c7c31e14a01
URL:         http://cgit.haiku-os.org/haiku/commit/?id=f31c19b
Author:      Pawel Dziepak <pdziepak@xxxxxxxxxxx>
Date:        Mon May  5 15:09:34 2014 UTC

libroot/x86_64: relax asm constraints in find_thread()

----------------------------------------------------------------------------

diff --git a/src/system/libroot/os/arch/x86_64/thread.cpp 
b/src/system/libroot/os/arch/x86_64/thread.cpp
index 10614ba..e4da9a8 100644
--- a/src/system/libroot/os/arch/x86_64/thread.cpp
+++ b/src/system/libroot/os/arch/x86_64/thread.cpp
@@ -13,7 +13,9 @@ find_thread(const char* name)
 {
        if (!name) {
                thread_id thread;
-               __asm__ __volatile__ ("movq %%fs:8, %%rax" : "=a" (thread));
+               static_assert(sizeof(thread_id) <= sizeof(uint32_t),
+                       "thread_id is larger than uint32_t");
+               __asm__ __volatile__ ("movl %%fs:8, %0" : "=r" (thread));
                return thread;
        }
 

############################################################################

Commit:      c1dc10496054f49cf6af475cce53bf076bbf4d19
URL:         http://cgit.haiku-os.org/haiku/commit/?id=c1dc104
Author:      Pawel Dziepak <pdziepak@xxxxxxxxxxx>
Date:        Mon May  5 19:16:07 2014 UTC

kernel/x86_64: enable c++11 in x86_64 specific code

----------------------------------------------------------------------------

diff --git a/src/system/kernel/arch/x86/Jamfile 
b/src/system/kernel/arch/x86/Jamfile
index 3941e18..ee6d93b 100644
--- a/src/system/kernel/arch/x86/Jamfile
+++ b/src/system/kernel/arch/x86/Jamfile
@@ -17,6 +17,8 @@ SEARCH_SOURCE += [ FDirName $(SUBDIR) timers ] ;
 
 local archSpecificSources ;
 if $(TARGET_ARCH) = x86_64 {
+       SubDirC++Flags -std=gnu++11 ;
+
        SEARCH_SOURCE += [ FDirName $(SUBDIR) 64 ] ;
        SEARCH_SOURCE += [ FDirName $(SUBDIR) paging 64bit ] ;
 

############################################################################

Commit:      cd59bf434970a082f1bfbb79fc83e4c93b00bc31
URL:         http://cgit.haiku-os.org/haiku/commit/?id=cd59bf4
Author:      Pawel Dziepak <pdziepak@xxxxxxxxxxx>
Date:        Mon May  5 19:16:59 2014 UTC

kernel/x86_64: x86_64 gdt handling code overhaul

Virtually no functional change, just rewriting the code from
"C in *.cpp files" to C++. Use of constexpr may be advantageous but
that code is not performance critical anyway.

----------------------------------------------------------------------------

diff --git a/headers/private/kernel/arch/x86/64/descriptors.h 
b/headers/private/kernel/arch/x86/64/descriptors.h
index 78d02c7..66512b3 100644
--- a/headers/private/kernel/arch/x86/64/descriptors.h
+++ b/headers/private/kernel/arch/x86/64/descriptors.h
@@ -13,13 +13,6 @@
 #define USER_DATA_SEGMENT              3
 #define USER_CODE_SEGMENT              4
 
-#define TSS_BASE_SEGMENT               5
-
-#define TSS_SEGMENT(cpu)               (TSS_BASE_SEGMENT + cpu * 2)
-
-#define GDT_SEGMENT_COUNT              (TSS_BASE_SEGMENT + SMP_MAX_CPUS * 2)
-
-
 #define KERNEL_CODE_SELECTOR   ((KERNEL_CODE_SEGMENT << 3) | DPL_KERNEL)
 #define KERNEL_DATA_SELECTOR   ((KERNEL_DATA_SEGMENT << 3) | DPL_KERNEL)
 
@@ -46,23 +39,6 @@ struct segment_descriptor {
        uint32 base1 : 8;
 } _PACKED;
 
-// Structure of a TSS segment descriptor.
-struct tss_descriptor {
-       uint32 limit0 : 16;
-       uint32 base0 : 24;
-       uint32 type : 4;
-       uint32 desc_type : 1;
-       uint32 dpl : 2;
-       uint32 present : 1;
-       uint32 limit1 : 4;
-       uint32 available : 1;
-       uint32 unused1 : 2;
-       uint32 granularity : 1;
-       uint32 base1 : 8;
-       uint32 base2 : 32;
-       uint32 unused2 : 32;
-} _PACKED;
-
 // Structure of an interrupt descriptor.
 struct interrupt_descriptor {
        uint32 base0 : 16;
@@ -128,29 +104,6 @@ set_segment_descriptor(segment_descriptor* desc, uint8 
type, uint8 dpl)
 
 
 static inline void
-set_tss_descriptor(segment_descriptor* _desc, uint64 base, uint32 limit)
-{
-       clear_segment_descriptor(_desc);
-       clear_segment_descriptor(&_desc[1]);
-
-       // The TSS descriptor is a special format in 64-bit mode, it is 16 bytes
-       // instead of 8.
-       tss_descriptor* desc = (tss_descriptor*)_desc;
-
-       desc->base0 = base & 0xffffff;
-       desc->base1 = (base >> 24) & 0xff;
-       desc->base2 = (base >> 32);
-       desc->limit0 = limit & 0xffff;
-       desc->limit1 = (limit >> 16) & 0xf;
-
-       desc->present = 1;
-       desc->type = DT_TSS;
-       desc->desc_type = DT_SYSTEM_SEGMENT;
-       desc->dpl = DPL_KERNEL;
-}
-
-
-static inline void
 set_interrupt_descriptor(interrupt_descriptor* desc, uint64 addr, uint32 type,
        uint16 seg, uint32 dpl, uint32 ist)
 {
diff --git a/src/system/kernel/arch/x86/64/descriptors.cpp 
b/src/system/kernel/arch/x86/64/descriptors.cpp
index b328eb2..37e0ef2 100644
--- a/src/system/kernel/arch/x86/64/descriptors.cpp
+++ b/src/system/kernel/arch/x86/64/descriptors.cpp
@@ -1,4 +1,5 @@
 /*
+ * Copyright 2014, Paweł Dziepak, pdziepak@xxxxxxxxxxx.
  * Copyright 2012, Alex Smith, alex@xxxxxxxxxxxxxxxx.
  * Distributed under the terms of the MIT License.
  */
@@ -18,38 +19,182 @@
 #define IDT_GATES_COUNT        256
 
 
-typedef void interrupt_handler_function(iframe* frame);
+enum class DescriptorType : unsigned {
+       DataWritable            = 0x2,
+       CodeExecuteOnly         = 0x8,
+       TSS                                     = 0x9,
+};
+
+class Descriptor {
+public:
+       constexpr                               Descriptor();
+       inline                                  Descriptor(uint32_t first, 
uint32_t second);
+       constexpr                               Descriptor(DescriptorType type, 
bool kernelOnly);
+
+protected:
+       union {
+               struct [[gnu::packed]] {
+                       uint16_t                fLimit0;
+                       unsigned                fBase0                  :24;
+                       unsigned                fType                   :4;
+                       unsigned                fSystem                 :1;
+                       unsigned                fDPL                    :2;
+                       unsigned                fPresent                :1;
+                       unsigned                fLimit1                 :4;
+                       unsigned                fUnused                 :1;
+                       unsigned                fLong                   :1;
+                       unsigned                fDB                             
:1;
+                       unsigned                fGranularity    :1;
+                       uint8_t                 fBase1;
+               };
+
+               uint32_t                        fDescriptor[2];
+       };
+};
+
+class TSSDescriptor : public Descriptor {
+public:
+       inline                                          TSSDescriptor(uintptr_t 
base, size_t limit);
+
+                       const Descriptor&       GetLower() const        { 
return *this; }
+                       const Descriptor&       GetUpper() const        { 
return fSecond; }
+
+       static  void                            LoadTSS(unsigned index);
+
+private:
+                       Descriptor                      fSecond;
+};
+
+class GlobalDescriptorTable {
+public:
+       constexpr                                               
GlobalDescriptorTable();
 
+       inline  void                                    Load() const;
+
+                       unsigned                                SetTSS(unsigned 
cpu,
+                                                                               
const TSSDescriptor& tss);
+private:
+       static constexpr        unsigned        kFirstTSS = 5;
+       static constexpr        unsigned        kDescriptorCount
+                                                                               
= kFirstTSS + SMP_MAX_CPUS * 2;
+
+       alignas(sizeof(Descriptor))     Descriptor      
fTable[kDescriptorCount];
+};
+
+
+static GlobalDescriptorTable   sGDT;
 
-static segment_descriptor sGDT[GDT_SEGMENT_COUNT];
 static interrupt_descriptor sIDT[IDT_GATES_COUNT];
 
+typedef void interrupt_handler_function(iframe* frame);
 static const uint32 kInterruptHandlerTableSize = IDT_GATES_COUNT;
 interrupt_handler_function* gInterruptHandlerTable[kInterruptHandlerTableSize];
 
 extern uint8 isr_array[kInterruptHandlerTableSize][16];
 
 
-static inline void
-load_tss(int cpu)
+constexpr bool
+is_code_segment(DescriptorType type)
 {
-       uint16 segment = (TSS_SEGMENT(cpu) << 3) | DPL_KERNEL;
-       asm volatile("ltr %w0" : : "r" (segment));
+       return type == DescriptorType::CodeExecuteOnly;
+};
+
+
+constexpr
+Descriptor::Descriptor()
+       :
+       fDescriptor { 0, 0 }
+{
+       static_assert(sizeof(Descriptor) == sizeof(uint64_t),
+               "Invalid Descriptor size.");
 }
 
 
-static inline void
-load_gdt()
+Descriptor::Descriptor(uint32_t first, uint32_t second)
+       :
+       fDescriptor { first, second }
 {
-       struct {
-               uint16  limit;
-               void*   address;
-       } _PACKED gdtDescriptor = {
-               GDT_SEGMENT_COUNT * sizeof(segment_descriptor) - 1,
-               sGDT
+}
+
+
+constexpr
+Descriptor::Descriptor(DescriptorType type, bool kernelOnly)
+       :
+       fLimit0(-1),
+       fBase0(0),
+       fType(static_cast<unsigned>(type)),
+       fSystem(1),
+       fDPL(kernelOnly ? 0 : 3),
+       fPresent(1),
+       fLimit1(0xf),
+       fUnused(0),
+       fLong(is_code_segment(type) ? 1 : 0),
+       fDB(is_code_segment(type) ? 0 : 1),
+       fGranularity(1),
+       fBase1(0)
+{
+}
+
+
+TSSDescriptor::TSSDescriptor(uintptr_t base, size_t limit)
+       :
+       fSecond(base >> 32, 0)
+{
+       fLimit0 = static_cast<uint16_t>(limit);
+       fBase0 = base & 0xffffff;
+       fType = static_cast<unsigned>(DescriptorType::TSS);
+       fPresent = 1;
+       fLimit1 = (limit >> 16) & 0xf;
+       fBase1 = static_cast<uint8_t>(base >> 24);
+}
+
+
+void
+TSSDescriptor::LoadTSS(unsigned index)
+{
+       asm volatile("ltr %w0" : : "r" (index << 3));
+}
+
+
+constexpr
+GlobalDescriptorTable::GlobalDescriptorTable()
+       :
+       fTable {
+               Descriptor(),
+               Descriptor(DescriptorType::CodeExecuteOnly, true),
+               Descriptor(DescriptorType::DataWritable, true),
+               Descriptor(DescriptorType::DataWritable, false),
+               Descriptor(DescriptorType::CodeExecuteOnly, false),
+       }
+{
+       static_assert(kDescriptorCount <= 8192,
+               "GDT cannot contain more than 8192 descriptors");
+}
+
+
+void
+GlobalDescriptorTable::Load() const
+{
+       struct [[gnu::packed]] {
+               uint16_t        fLimit;
+               const void*     fAddress;
+       } gdtDescriptor = {
+               sizeof(fTable) - 1,
+               static_cast<const void*>(fTable),
        };
 
-       asm volatile("lgdt %0" : : "m" (gdtDescriptor));
+       asm volatile("lgdt      %0" : : "m" (gdtDescriptor));
+}
+
+
+unsigned
+GlobalDescriptorTable::SetTSS(unsigned cpu, const TSSDescriptor& tss)
+{
+       auto index = kFirstTSS + cpu * 2;
+       ASSERT(index + 1 < kDescriptorCount);
+       fTable[index] = tss.GetLower();
+       fTable[index + 1] = tss.GetUpper();
+       return index;
 }
 
 
@@ -96,35 +241,24 @@ x86_64_general_protection_fault(iframe* frame)
 void
 x86_descriptors_preboot_init_percpu(kernel_args* args, int cpu)
 {
-       if (cpu == 0) {
-               STATIC_ASSERT(GDT_SEGMENT_COUNT <= 8192);
-
-               set_segment_descriptor(&sGDT[KERNEL_CODE_SEGMENT], 
DT_CODE_EXECUTE_ONLY,
-                       DPL_KERNEL);
-               set_segment_descriptor(&sGDT[KERNEL_DATA_SEGMENT], 
DT_DATA_WRITEABLE,
-                       DPL_KERNEL);
-               set_segment_descriptor(&sGDT[USER_CODE_SEGMENT], 
DT_CODE_EXECUTE_ONLY,
-                       DPL_USER);
-               set_segment_descriptor(&sGDT[USER_DATA_SEGMENT], 
DT_DATA_WRITEABLE,
-                       DPL_USER);
-       }
+       new(&sGDT) GlobalDescriptorTable;
+       sGDT.Load();
 
        memset(&gCPU[cpu].arch.tss, 0, sizeof(struct tss));
        gCPU[cpu].arch.tss.io_map_base = sizeof(struct tss);
 
-       // Set up the descriptor for this TSS.
-       set_tss_descriptor(&sGDT[TSS_SEGMENT(cpu)], (addr_t)&gCPU[cpu].arch.tss,
-               sizeof(struct tss));
-
        // Set up the double fault IST entry (see x86_descriptors_init()).
        struct tss* tss = &gCPU[cpu].arch.tss;
        size_t stackSize;
        tss->ist1 = (addr_t)x86_get_double_fault_stack(cpu, &stackSize);
        tss->ist1 += stackSize;
 
+       // Set up the descriptor for this TSS.
+       auto tssIndex = sGDT.SetTSS(cpu,
+                       TSSDescriptor(uintptr_t(&gCPU[cpu].arch.tss), 
sizeof(struct tss)));
+       TSSDescriptor::LoadTSS(tssIndex);
+
        load_idt();
-       load_gdt();
-       load_tss(cpu);
 }
 
 

############################################################################

Commit:      2b6d4bc6578b419189a5051ed54f81dd9e70def1
URL:         http://cgit.haiku-os.org/haiku/commit/?id=2b6d4bc
Author:      Pawel Dziepak <pdziepak@xxxxxxxxxxx>
Date:        Tue May  6 02:04:01 2014 UTC

kernel/x86: add space between literal and identifier

Due to introduction of user-defined suffixes C++11 requires that there
is a space between literal and identifier to avoid ambiguity.

----------------------------------------------------------------------------

diff --git a/src/system/kernel/arch/x86/irq_routing_table.cpp 
b/src/system/kernel/arch/x86/irq_routing_table.cpp
index 68cfd1b..9045bba 100644
--- a/src/system/kernel/arch/x86/irq_routing_table.cpp
+++ b/src/system/kernel/arch/x86/irq_routing_table.cpp
@@ -18,7 +18,7 @@
 
 //#define TRACE_PRT
 #ifdef TRACE_PRT
-#      define TRACE(x...) dprintf("IRQRoutingTable: "x)
+#      define TRACE(x...) dprintf("IRQRoutingTable: " x)
 #else
 #      define TRACE(x...)
 #endif

############################################################################

Revision:    hrev47207
Commit:      9db5b975f9ea2b942568eb57bbcce90a1c7420dc
URL:         http://cgit.haiku-os.org/haiku/commit/?id=9db5b97
Author:      Pawel Dziepak <pdziepak@xxxxxxxxxxx>
Date:        Tue May  6 12:39:34 2014 UTC

kernel/x86_64: rework of IDT handling code

Similarly to previous patch regarding GDT this is mostly a rewrite of
IDT handling code from C to C++. Thanks to constexpr IDT is now entirely
generated at compile-time.

----------------------------------------------------------------------------

diff --git a/headers/private/kernel/arch/x86/64/descriptors.h 
b/headers/private/kernel/arch/x86/64/descriptors.h
index 66512b3..c5a783a 100644
--- a/headers/private/kernel/arch/x86/64/descriptors.h
+++ b/headers/private/kernel/arch/x86/64/descriptors.h
@@ -39,21 +39,6 @@ struct segment_descriptor {
        uint32 base1 : 8;
 } _PACKED;
 
-// Structure of an interrupt descriptor.
-struct interrupt_descriptor {
-       uint32 base0 : 16;
-       uint32 sel : 16;
-       uint32 ist : 3;
-       uint32 unused1 : 5;
-       uint32 type : 4;
-       uint32 unused2 : 1;
-       uint32 dpl : 2;
-       uint32 present : 1;
-       uint32 base1 : 16;
-       uint32 base2 : 32;
-       uint32 reserved : 32;
-} _PACKED;
-
 struct tss {
        uint32 _reserved1;
        uint64 sp0;
@@ -103,24 +88,6 @@ set_segment_descriptor(segment_descriptor* desc, uint8 
type, uint8 dpl)
 }
 
 
-static inline void
-set_interrupt_descriptor(interrupt_descriptor* desc, uint64 addr, uint32 type,
-       uint16 seg, uint32 dpl, uint32 ist)
-{
-       desc->base0 = addr & 0xffff;
-       desc->base1 = (addr >> 16) & 0xffff;
-       desc->base2 = (addr >> 32) & 0xffffffff;
-       desc->sel = seg;
-       desc->ist = ist;
-       desc->type = type;
-       desc->dpl = dpl;
-       desc->present = 1;
-       desc->unused1 = 0;
-       desc->unused2 = 0;
-       desc->reserved = 0;
-}
-
-
 #endif /* _ASSEMBLER */
 
 #endif /* _KERNEL_ARCH_X86_64_DESCRIPTORS_H */
diff --git a/src/system/kernel/arch/x86/64/descriptors.cpp 
b/src/system/kernel/arch/x86/64/descriptors.cpp
index 37e0ef2..993dfdf 100644
--- a/src/system/kernel/arch/x86/64/descriptors.cpp
+++ b/src/system/kernel/arch/x86/64/descriptors.cpp
@@ -16,8 +16,20 @@
 #include <arch/user_debugger.h>
 
 
-#define IDT_GATES_COUNT        256
+template<typename T, T (*Function)(unsigned), unsigned N, unsigned ...Index>
+struct GenerateTable : GenerateTable<T, Function, N - 1,  N - 1, Index...> {
+};
+
+template<typename T, T (*Function)(unsigned), unsigned ...Index>
+struct GenerateTable<T, Function, 0, Index...> {
+       GenerateTable()
+               :
+               fTable { Function(Index)... }
+       {
+       }
 
+       T       fTable[sizeof...(Index)];
+};
 
 enum class DescriptorType : unsigned {
        DataWritable            = 0x2,
@@ -78,19 +90,61 @@ private:
        static constexpr        unsigned        kDescriptorCount
                                                                                
= kFirstTSS + SMP_MAX_CPUS * 2;
 
-       alignas(sizeof(Descriptor))     Descriptor      
fTable[kDescriptorCount];
+       alignas(uint64_t)       Descriptor      fTable[kDescriptorCount];
 };
 
+enum class InterruptDescriptorType : unsigned {
+       Interrupt               = 14,
+       Trap,
+};
 
-static GlobalDescriptorTable   sGDT;
+class [[gnu::packed]] InterruptDescriptor {
+public:
+       constexpr                                               
InterruptDescriptor(uintptr_t isr,
+                                                                               
unsigned ist, bool kernelOnly);
+       constexpr                                               
InterruptDescriptor(uintptr_t isr);
 
-static interrupt_descriptor sIDT[IDT_GATES_COUNT];
+       static constexpr        InterruptDescriptor     Generate(unsigned 
index);
 
-typedef void interrupt_handler_function(iframe* frame);
-static const uint32 kInterruptHandlerTableSize = IDT_GATES_COUNT;
-interrupt_handler_function* gInterruptHandlerTable[kInterruptHandlerTableSize];
+private:
+                                               uint16_t        fBase0;
+                                               uint16_t        fSelector;
+                                               unsigned        fIST            
:3;
+                                               unsigned        fReserved0      
:5;
+                                               unsigned        fType           
:4;
+                                               unsigned        fReserved1      
:1;
+                                               unsigned        fDPL            
:2;
+                                               unsigned        fPresent        
:1;
+                                               uint16_t        fBase1;
+                                               uint32_t        fBase2;
+                                               uint32_t        fReserved2;
+};
 
-extern uint8 isr_array[kInterruptHandlerTableSize][16];
+class InterruptDescriptorTable {
+public:
+       inline                          void            Load() const;
+
+       static constexpr        unsigned        kDescriptorCount = 256;
+
+private:
+       typedef GenerateTable<InterruptDescriptor, 
InterruptDescriptor::Generate,
+                       kDescriptorCount> TableType;
+       alignas(uint64_t)       TableType       fTable;
+};
+
+class InterruptServiceRoutine {
+       alignas(16)     uint8_t fDummy[16];
+};
+
+extern const InterruptServiceRoutine
+       isr_array[InterruptDescriptorTable::kDescriptorCount];
+
+static GlobalDescriptorTable   sGDT;
+static InterruptDescriptorTable        sIDT;
+
+typedef void interrupt_handler_function(iframe* frame);
+interrupt_handler_function*
+       gInterruptHandlerTable[InterruptDescriptorTable::kDescriptorCount];
 
 
 constexpr bool
@@ -198,18 +252,58 @@ GlobalDescriptorTable::SetTSS(unsigned cpu, const 
TSSDescriptor& tss)
 }
 
 
-static inline void
-load_idt()
+constexpr
+InterruptDescriptor::InterruptDescriptor(uintptr_t isr, unsigned ist,
+       bool kernelOnly)
+       :
+       fBase0(isr),
+       fSelector(KERNEL_CODE_SELECTOR),
+       fIST(ist),
+       fReserved0(0),
+       fType(static_cast<unsigned>(InterruptDescriptorType::Interrupt)),
+       fReserved1(0),
+       fDPL(kernelOnly ? 0 : 3),
+       fPresent(1),
+       fBase1(isr >> 16),
+       fBase2(isr >> 32),
+       fReserved2(0)
+{
+       static_assert(sizeof(InterruptDescriptor) == sizeof(uint64_t) * 2,
+               "Invalid InterruptDescriptor size.");
+}
+
+
+constexpr
+InterruptDescriptor::InterruptDescriptor(uintptr_t isr)
+       :
+       InterruptDescriptor(isr, 0, true)
+{
+}
+
+
+void
+InterruptDescriptorTable::Load() const
 {
-       struct {
-               uint16  limit;
-               void*   address;
-       } _PACKED idtDescriptor = {
-               IDT_GATES_COUNT * sizeof(interrupt_descriptor) - 1,
-               sIDT
+       struct [[gnu::packed]] {
+               uint16_t        fLimit;
+               const void*     fAddress;
+       } gdtDescriptor = {
+               sizeof(fTable) - 1,
+               static_cast<const void*>(fTable.fTable),
        };
 
-       asm volatile("lidt %0" : : "m" (idtDescriptor));
+       asm volatile("lidt      %0" : : "m" (gdtDescriptor));
+}
+
+
+constexpr InterruptDescriptor
+InterruptDescriptor::Generate(unsigned index)
+{
+       return index == 3
+               ? InterruptDescriptor(uintptr_t(isr_array + index), 0, false)
+               : (index == 8
+                       ? InterruptDescriptor(uintptr_t(isr_array + index), 1, 
true)
+                       : InterruptDescriptor(uintptr_t(isr_array + index)));
 }
 
 
@@ -258,38 +352,22 @@ x86_descriptors_preboot_init_percpu(kernel_args* args, 
int cpu)
                        TSSDescriptor(uintptr_t(&gCPU[cpu].arch.tss), 
sizeof(struct tss)));
        TSSDescriptor::LoadTSS(tssIndex);
 
-       load_idt();
+       new(&sIDT) InterruptDescriptorTable;
+       sIDT.Load();
 }
 
 
 void
 x86_descriptors_init(kernel_args* args)
 {
-       // Fill out the IDT, pointing each entry to the corresponding entry in 
the
-       // ISR array created in arch_interrupts.S (see there to see how this 
works).
-       for(uint32 i = 0; i < kInterruptHandlerTableSize; i++) {
-               // x86_64 removes task gates, therefore we cannot use a 
separate TSS
-               // for the double fault exception. However, instead it adds a 
new stack
-               // switching mechanism, the IST. The IST is a table of stack 
addresses
-               // in the TSS. If the IST field of an interrupt descriptor is 
non-zero,
-               // the CPU will switch to the stack specified by that IST entry 
when
-               // handling that interrupt. So, we use IST entry 1 to store the 
double
-               // fault stack address (set up in 
x86_descriptors_init_post_vm()).
-               uint32 ist = (i == 8) ? 1 : 0;
-
-               // Breakpoint exception can be raised from userland.
-               uint32 dpl = (i == 3) ? DPL_USER : DPL_KERNEL;
-
-               set_interrupt_descriptor(&sIDT[i], (addr_t)&isr_array[i],
-                       GATE_INTERRUPT, KERNEL_CODE_SELECTOR, dpl, ist);
-       }
-
        // Initialize the interrupt handler table.
        interrupt_handler_function** table = gInterruptHandlerTable;
        for (uint32 i = 0; i < ARCH_INTERRUPT_BASE; i++)
                table[i] = x86_invalid_exception;
-       for (uint32 i = ARCH_INTERRUPT_BASE; i < kInterruptHandlerTableSize; 
i++)
+       for (uint32 i = ARCH_INTERRUPT_BASE;
+               i < InterruptDescriptorTable::kDescriptorCount; i++) {
                table[i] = x86_hardware_interrupt;
+       }
 
        table[0]  = x86_unexpected_exception;   // Divide Error Exception (#DE)
        table[1]  = x86_handle_debug_exception; // Debug Exception (#DB)


Other related posts:

  • » [haiku-commits] haiku: hrev47207 - src/system/kernel/arch/x86/64 headers/private/kernel/arch/x86/64 src/system/libroot/os/arch/x86_64 - pdziepak