summaryrefslogtreecommitdiffhomepage
path: root/Kernel/HALKit/AMD64/HalDescriptorLoader.cpp
blob: 48f57cc07fa0819b1277bebabf6dd5709405c71b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
/* -------------------------------------------

	Copyright Zeta Electronics Corporation

------------------------------------------- */

#include <ArchKit/ArchKit.hpp>

namespace NewOS::HAL
{
	namespace Detail
	{
		STATIC RegisterGDT kRegGdt;
		STATIC HAL::Register64 kRegIdt;

		STATIC ::NewOS::Detail::AMD64::InterruptDescriptorAMD64
			kInterruptVectorTable[kKernelIdtSize];

		STATIC Void RemapPIC(Void) noexcept
		{
			// Remap PIC.
			HAL::Out8(0x20, 0x10 | 0x01);
			HAL::Out8(0xA0, 0x10 | 0x01);

			HAL::Out8(0x21, 32);
			HAL::Out8(0xA1, 40);

			HAL::Out8(0x21, 4);
			HAL::Out8(0xA1, 2);

			HAL::Out8(0x21, 0x01);
			HAL::Out8(0xA1, 0x01);

			HAL::Out8(0x21, 0x00);
			HAL::Out8(0xA1, 0x00);
		}
	} // namespace Detail

	/// @brief Loads the provided Global Descriptor Table.
	/// @param gdt
	/// @return
	Void GDTLoader::Load(RegisterGDT& gdt)
	{
		MUST_PASS(gdt.Base != 0);

		Detail::kRegGdt.Base  = gdt.Base;
		Detail::kRegGdt.Limit = gdt.Limit;

		hal_load_gdt(Detail::kRegGdt);
	}

	Void IDTLoader::Load(Register64& idt)
	{
		volatile ::NewOS::UIntPtr** baseIdt = (volatile ::NewOS::UIntPtr**)idt.Base;

		MUST_PASS(baseIdt);

		Detail::RemapPIC();

		for (UInt16 i = 0; i < kKernelIdtSize; ++i)
		{
			MUST_PASS(baseIdt[i]);

			Detail::kInterruptVectorTable[i].Selector		= kGdtCodeSelector;
			Detail::kInterruptVectorTable[i].Ist			= 0x0;
			Detail::kInterruptVectorTable[i].TypeAttributes = kInterruptGate;
			Detail::kInterruptVectorTable[i].OffsetLow		= ((UIntPtr)baseIdt[i] & 0xFFFF);
			Detail::kInterruptVectorTable[i].OffsetMid		= (((UIntPtr)baseIdt[i] >> 16) & 0xFFFF);
			Detail::kInterruptVectorTable[i].OffsetHigh =
				(((UIntPtr)baseIdt[i] >> 32) & 0xFFFFFFFF);
			Detail::kInterruptVectorTable[i].Zero = 0x0;
		}

		Detail::kRegIdt.Base  = reinterpret_cast<UIntPtr>(Detail::kInterruptVectorTable);
		Detail::kRegIdt.Limit = sizeof(::NewOS::Detail::AMD64::InterruptDescriptorAMD64) *
								(kKernelIdtSize - 1);

		hal_load_idt(Detail::kRegIdt);
	}

	void GDTLoader::Load(Ref<RegisterGDT>& gdt)
	{
		GDTLoader::Load(gdt.Leak());
	}

	void IDTLoader::Load(Ref<Register64>& idt)
	{
		IDTLoader::Load(idt.Leak());
	}
} // namespace NewOS::HAL