Kernel: Unify IDT and GDT code between x86_64 and x86_32
The code is pretty much the same, so there are just couple macros differiating initialization.
This commit is contained in:
		
							parent
							
								
									af050cc729
								
							
						
					
					
						commit
						1943c3e7a1
					
				|  | @ -33,6 +33,8 @@ set(KERNEL_SOURCES | ||||||
| 	kernel/FS/TmpFS/FileSystem.cpp | 	kernel/FS/TmpFS/FileSystem.cpp | ||||||
| 	kernel/FS/TmpFS/Inode.cpp | 	kernel/FS/TmpFS/Inode.cpp | ||||||
| 	kernel/FS/VirtualFileSystem.cpp | 	kernel/FS/VirtualFileSystem.cpp | ||||||
|  | 	kernel/GDT.cpp | ||||||
|  | 	kernel/IDT.cpp | ||||||
| 	kernel/Input/KeyboardLayout.cpp | 	kernel/Input/KeyboardLayout.cpp | ||||||
| 	kernel/Input/KeyEvent.cpp | 	kernel/Input/KeyEvent.cpp | ||||||
| 	kernel/Input/PS2/Controller.cpp | 	kernel/Input/PS2/Controller.cpp | ||||||
|  | @ -105,8 +107,6 @@ if("${BANAN_ARCH}" STREQUAL "x86_64") | ||||||
| 	set(KERNEL_SOURCES | 	set(KERNEL_SOURCES | ||||||
| 		${KERNEL_SOURCES} | 		${KERNEL_SOURCES} | ||||||
| 		arch/x86_64/boot.S | 		arch/x86_64/boot.S | ||||||
| 		arch/x86_64/GDT.cpp |  | ||||||
| 		arch/x86_64/IDT.cpp |  | ||||||
| 		arch/x86_64/interrupts.S | 		arch/x86_64/interrupts.S | ||||||
| 		arch/x86_64/PageTable.cpp | 		arch/x86_64/PageTable.cpp | ||||||
| 		arch/x86_64/Signal.S | 		arch/x86_64/Signal.S | ||||||
|  | @ -124,8 +124,7 @@ elseif("${BANAN_ARCH}" STREQUAL "i686") | ||||||
| 	set(KERNEL_SOURCES | 	set(KERNEL_SOURCES | ||||||
| 		${KERNEL_SOURCES} | 		${KERNEL_SOURCES} | ||||||
| 		arch/i686/boot.S | 		arch/i686/boot.S | ||||||
| 		arch/i686/GDT.cpp | 		arch/i686/interrupts.S | ||||||
| 		arch/i686/IDT.cpp |  | ||||||
| 		arch/i686/PageTable.cpp | 		arch/i686/PageTable.cpp | ||||||
| 		arch/i686/Signal.S | 		arch/i686/Signal.S | ||||||
| 		arch/i686/Syscall.S | 		arch/i686/Syscall.S | ||||||
|  |  | ||||||
|  | @ -1,21 +0,0 @@ | ||||||
| #include <kernel/GDT.h> |  | ||||||
| 
 |  | ||||||
| namespace Kernel |  | ||||||
| { |  | ||||||
| 
 |  | ||||||
| 	GDT* GDT::create() |  | ||||||
| 	{ |  | ||||||
| 		ASSERT_NOT_REACHED(); |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	void GDT::write_entry(uint8_t, uint32_t, uint32_t, uint8_t, uint8_t) |  | ||||||
| 	{ |  | ||||||
| 		ASSERT_NOT_REACHED(); |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	void GDT::write_tss() |  | ||||||
| 	{ |  | ||||||
| 		ASSERT_NOT_REACHED(); |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| } |  | ||||||
|  | @ -1,31 +0,0 @@ | ||||||
| #include <kernel/IDT.h> |  | ||||||
| 
 |  | ||||||
| namespace Kernel |  | ||||||
| { |  | ||||||
| 
 |  | ||||||
| 	IDT* IDT::create() |  | ||||||
| 	{ |  | ||||||
| 		ASSERT_NOT_REACHED(); |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	[[noreturn]] void IDT::force_triple_fault() |  | ||||||
| 	{ |  | ||||||
| 		ASSERT_NOT_REACHED(); |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	void IDT::register_irq_handler(uint8_t, Interruptable*) |  | ||||||
| 	{ |  | ||||||
| 		ASSERT_NOT_REACHED(); |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	void IDT::register_interrupt_handler(uint8_t, void (*)()) |  | ||||||
| 	{ |  | ||||||
| 		ASSERT_NOT_REACHED(); |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	void IDT::register_syscall_handler(uint8_t, void (*)()) |  | ||||||
| 	{ |  | ||||||
| 		ASSERT_NOT_REACHED(); |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| } |  | ||||||
|  | @ -0,0 +1,134 @@ | ||||||
|  | isr_stub: | ||||||
|  | 	ud2 | ||||||
|  | 	pusha | ||||||
|  | 	call cpp_isr_handler | ||||||
|  | 	popa | ||||||
|  | 	iret | ||||||
|  | 
 | ||||||
|  | irq_stub: | ||||||
|  | 	ud2 | ||||||
|  | 	pusha | ||||||
|  | 	call cpp_irq_handler | ||||||
|  | 	popa | ||||||
|  | 	iret | ||||||
|  | 
 | ||||||
|  | // arguments in EAX, EBX, ECX, EDX, ESI, EDI | ||||||
|  | .global syscall_asm
 | ||||||
|  | syscall_asm: | ||||||
|  | 	ud2 | ||||||
|  | 	pusha | ||||||
|  | 
 | ||||||
|  | 	pushl %esp | ||||||
|  | 	addl $36, (%esp) | ||||||
|  | 
 | ||||||
|  | 	pushl %edi | ||||||
|  | 	pushl %esi | ||||||
|  | 	pushl %edx | ||||||
|  | 	pushl %ecx | ||||||
|  | 	pushl %ebx | ||||||
|  | 	pushl %eax | ||||||
|  | 
 | ||||||
|  | 	call cpp_syscall_handler | ||||||
|  | 
 | ||||||
|  | 	addl $60, %esp | ||||||
|  | 
 | ||||||
|  | 	popl %edi | ||||||
|  | 	popl %esi | ||||||
|  | 	popl %ebp | ||||||
|  | 	addl $4, %esp | ||||||
|  | 	popl %ebx | ||||||
|  | 	popl %edx | ||||||
|  | 	popl %ecx | ||||||
|  | 	addl $4, %esp | ||||||
|  | 
 | ||||||
|  | 	iret | ||||||
|  | 
 | ||||||
|  | .macro isr n | ||||||
|  | 	.global isr\n | ||||||
|  | 	isr\n: | ||||||
|  | 		pushl $0 | ||||||
|  | 		pushl $\n | ||||||
|  | 		jmp isr_stub | ||||||
|  | .endm | ||||||
|  | 
 | ||||||
|  | .macro isr_err n | ||||||
|  | 	.global isr\n | ||||||
|  | 	isr\n: | ||||||
|  | 		pushl $\n | ||||||
|  | 		jmp isr_stub | ||||||
|  | .endm | ||||||
|  | 
 | ||||||
|  | .macro irq n | ||||||
|  | 	.global irq\n | ||||||
|  | 	irq\n: | ||||||
|  | 		pushl $0 | ||||||
|  | 		pushl $\n | ||||||
|  | 		jmp irq_stub | ||||||
|  | .endm | ||||||
|  | 
 | ||||||
|  | isr 0 | ||||||
|  | isr 1 | ||||||
|  | isr 2 | ||||||
|  | isr 3 | ||||||
|  | isr 4 | ||||||
|  | isr 5 | ||||||
|  | isr 6 | ||||||
|  | isr 7 | ||||||
|  | isr_err 8 | ||||||
|  | isr 9 | ||||||
|  | isr_err 10 | ||||||
|  | isr_err 11 | ||||||
|  | isr_err 12 | ||||||
|  | isr_err 13 | ||||||
|  | isr_err 14 | ||||||
|  | isr 15 | ||||||
|  | isr 16 | ||||||
|  | isr_err 17 | ||||||
|  | isr 18 | ||||||
|  | isr 19 | ||||||
|  | isr 20 | ||||||
|  | isr 21 | ||||||
|  | isr 22 | ||||||
|  | isr 23 | ||||||
|  | isr 24 | ||||||
|  | isr 25 | ||||||
|  | isr 26 | ||||||
|  | isr 27 | ||||||
|  | isr 28 | ||||||
|  | isr 29 | ||||||
|  | isr 30 | ||||||
|  | isr 31 | ||||||
|  | 
 | ||||||
|  | irq 0 | ||||||
|  | irq 1 | ||||||
|  | irq 2 | ||||||
|  | irq 3 | ||||||
|  | irq 4 | ||||||
|  | irq 5 | ||||||
|  | irq 6 | ||||||
|  | irq 7 | ||||||
|  | irq 8 | ||||||
|  | irq 9 | ||||||
|  | irq 10 | ||||||
|  | irq 11 | ||||||
|  | irq 12 | ||||||
|  | irq 13 | ||||||
|  | irq 14 | ||||||
|  | irq 15 | ||||||
|  | irq 16 | ||||||
|  | irq 17 | ||||||
|  | irq 18 | ||||||
|  | irq 19 | ||||||
|  | irq 20 | ||||||
|  | irq 21 | ||||||
|  | irq 22 | ||||||
|  | irq 23 | ||||||
|  | irq 24 | ||||||
|  | irq 25 | ||||||
|  | irq 26 | ||||||
|  | irq 27 | ||||||
|  | irq 28 | ||||||
|  | irq 29 | ||||||
|  | irq 30 | ||||||
|  | irq 31 | ||||||
|  | irq 32 | ||||||
|  | @ -1,56 +0,0 @@ | ||||||
| #include <kernel/GDT.h> |  | ||||||
| #include <kernel/Debug.h> |  | ||||||
| 
 |  | ||||||
| #include <string.h> |  | ||||||
| 
 |  | ||||||
| namespace Kernel |  | ||||||
| { |  | ||||||
| 
 |  | ||||||
| 	GDT* GDT::create() |  | ||||||
| 	{ |  | ||||||
| 		auto* gdt = new GDT(); |  | ||||||
| 		ASSERT(gdt); |  | ||||||
| 
 |  | ||||||
| 		gdt->write_entry(0x00, 0x00000000, 0x00000, 0x00, 0x0); // null
 |  | ||||||
| 		gdt->write_entry(0x08, 0x00000000, 0xFFFFF, 0x9A, 0xA); // kernel code
 |  | ||||||
| 		gdt->write_entry(0x10, 0x00000000, 0xFFFFF, 0x92, 0xC); // kernel data
 |  | ||||||
| 		gdt->write_entry(0x18, 0x00000000, 0xFFFFF, 0xFA, 0xA); // user code
 |  | ||||||
| 		gdt->write_entry(0x20, 0x00000000, 0xFFFFF, 0xF2, 0xC); // user data
 |  | ||||||
| 		gdt->write_tss(); |  | ||||||
| 
 |  | ||||||
| 		return gdt; |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	void GDT::write_entry(uint8_t offset, uint32_t base, uint32_t limit, uint8_t access, uint8_t flags) |  | ||||||
| 	{ |  | ||||||
| 		ASSERT(offset % sizeof(SegmentDescriptor) == 0); |  | ||||||
| 		uint8_t idx = offset / sizeof(SegmentDescriptor); |  | ||||||
| 
 |  | ||||||
| 		auto& desc = m_gdt[idx]; |  | ||||||
| 		desc.base1 = (base >>  0) & 0xFFFF; |  | ||||||
| 		desc.base2 = (base >> 16) & 0xFF; |  | ||||||
| 		desc.base3 = (base >> 24) & 0xFF; |  | ||||||
| 
 |  | ||||||
| 		desc.limit1 = (limit >>  0) & 0xFFFF; |  | ||||||
| 		desc.limit2 = (limit >> 16) & 0x0F; |  | ||||||
| 
 |  | ||||||
| 		desc.access = access & 0xFF; |  | ||||||
| 
 |  | ||||||
| 		desc.flags = flags & 0x0F; |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	void GDT::write_tss() |  | ||||||
| 	{ |  | ||||||
| 		memset(&m_tss, 0x00, sizeof(TaskStateSegment)); |  | ||||||
| 		m_tss.iopb = sizeof(TaskStateSegment); |  | ||||||
| 
 |  | ||||||
| 		uint64_t base = reinterpret_cast<uint64_t>(&m_tss); |  | ||||||
| 
 |  | ||||||
| 		write_entry(0x28, (uint32_t)base, sizeof(TaskStateSegment), 0x89, 0x0); |  | ||||||
| 
 |  | ||||||
| 		auto& desc = m_gdt[0x30 / sizeof(SegmentDescriptor)]; |  | ||||||
| 		desc.low = base >> 32; |  | ||||||
| 		desc.high = 0; |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| } |  | ||||||
|  | @ -2,12 +2,14 @@ | ||||||
| 
 | 
 | ||||||
| #include <BAN/Array.h> | #include <BAN/Array.h> | ||||||
| #include <BAN/NoCopyMove.h> | #include <BAN/NoCopyMove.h> | ||||||
|  | #include <kernel/Arch.h> | ||||||
| 
 | 
 | ||||||
| #include <stdint.h> | #include <stdint.h> | ||||||
| 
 | 
 | ||||||
| namespace Kernel | namespace Kernel | ||||||
| { | { | ||||||
| 
 | 
 | ||||||
|  | #if ARCH(x86_64) | ||||||
| 	struct TaskStateSegment | 	struct TaskStateSegment | ||||||
| 	{ | 	{ | ||||||
| 		uint32_t reserved1; | 		uint32_t reserved1; | ||||||
|  | @ -26,6 +28,54 @@ namespace Kernel | ||||||
| 		uint16_t reserved4; | 		uint16_t reserved4; | ||||||
| 		uint16_t iopb; | 		uint16_t iopb; | ||||||
| 	} __attribute__((packed)); | 	} __attribute__((packed)); | ||||||
|  | 	static_assert(sizeof(TaskStateSegment) == 104); | ||||||
|  | #elif ARCH(i686) | ||||||
|  | 	struct TaskStateSegment | ||||||
|  | 	{ | ||||||
|  | 		uint16_t link; | ||||||
|  | 		uint16_t __reserved0; | ||||||
|  | 		uint32_t esp0; | ||||||
|  | 		uint16_t ss0; | ||||||
|  | 		uint16_t __reserved1; | ||||||
|  | 		uint32_t esp1; | ||||||
|  | 		uint16_t ss1; | ||||||
|  | 		uint16_t __reserved2; | ||||||
|  | 		uint32_t esp2; | ||||||
|  | 		uint16_t ss2; | ||||||
|  | 		uint16_t __reserved3; | ||||||
|  | 		uint32_t cr3; | ||||||
|  | 		uint32_t eip; | ||||||
|  | 		uint32_t eflags; | ||||||
|  | 		uint32_t eax; | ||||||
|  | 		uint32_t ecx; | ||||||
|  | 		uint32_t edx; | ||||||
|  | 		uint32_t ebx; | ||||||
|  | 		uint32_t esp; | ||||||
|  | 		uint32_t ebp; | ||||||
|  | 		uint32_t esi; | ||||||
|  | 		uint32_t edi; | ||||||
|  | 		uint16_t es; | ||||||
|  | 		uint16_t __reserved4; | ||||||
|  | 		uint16_t cs; | ||||||
|  | 		uint16_t __reserved5; | ||||||
|  | 		uint16_t ss; | ||||||
|  | 		uint16_t __reserved6; | ||||||
|  | 		uint16_t ds; | ||||||
|  | 		uint16_t __reserved7; | ||||||
|  | 		uint16_t fs; | ||||||
|  | 		uint16_t __reserved8; | ||||||
|  | 		uint16_t gs; | ||||||
|  | 		uint16_t __reserved9; | ||||||
|  | 		uint16_t ldtr; | ||||||
|  | 		uint16_t __reserved10; | ||||||
|  | 		uint16_t __reserved11; | ||||||
|  | 		uint16_t iopb; | ||||||
|  | 		uint32_t ssp; | ||||||
|  | 	}; | ||||||
|  | 	static_assert(sizeof(TaskStateSegment) == 108); | ||||||
|  | #else | ||||||
|  | 	#error | ||||||
|  | #endif | ||||||
| 
 | 
 | ||||||
| 	union SegmentDescriptor | 	union SegmentDescriptor | ||||||
| 	{ | 	{ | ||||||
|  | @ -38,20 +88,20 @@ namespace Kernel | ||||||
| 			uint8_t		limit2 : 4; | 			uint8_t		limit2 : 4; | ||||||
| 			uint8_t		flags  : 4; | 			uint8_t		flags  : 4; | ||||||
| 			uint8_t		base3; | 			uint8_t		base3; | ||||||
| 		} __attribute__((packed)); | 		}; | ||||||
| 
 | 
 | ||||||
| 		struct | 		struct | ||||||
| 		{ | 		{ | ||||||
| 			uint32_t low; | 			uint32_t low; | ||||||
| 			uint32_t high; | 			uint32_t high; | ||||||
| 		} __attribute__((packed)); | 		}; | ||||||
| 
 | 	}; | ||||||
| 	} __attribute__((packed)); | 	static_assert(sizeof(SegmentDescriptor) == 8); | ||||||
| 
 | 
 | ||||||
| 	struct GDTR | 	struct GDTR | ||||||
| 	{ | 	{ | ||||||
| 		uint16_t size; | 		uint16_t size; | ||||||
| 		uint64_t address; | 		uintptr_t address; | ||||||
| 	} __attribute__((packed)); | 	} __attribute__((packed)); | ||||||
| 
 | 
 | ||||||
| 	class GDT | 	class GDT | ||||||
|  | @ -60,7 +110,7 @@ namespace Kernel | ||||||
| 		BAN_NON_MOVABLE(GDT); | 		BAN_NON_MOVABLE(GDT); | ||||||
| 
 | 
 | ||||||
| 	public: | 	public: | ||||||
| 		static GDT* create(); | 		static GDT* create(void* processor); | ||||||
| 		void load() { flush_gdt(); flush_tss(); } | 		void load() { flush_gdt(); flush_tss(); } | ||||||
| 
 | 
 | ||||||
| 		static constexpr inline bool is_user_segment(uint8_t segment) | 		static constexpr inline bool is_user_segment(uint8_t segment) | ||||||
|  | @ -68,9 +118,13 @@ namespace Kernel | ||||||
| 			return (segment & 3) == 3; | 			return (segment & 3) == 3; | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		void set_tss_stack(uintptr_t rsp) | 		void set_tss_stack(uintptr_t sp) | ||||||
| 		{ | 		{ | ||||||
| 			m_tss.rsp0 = rsp; | #if ARCH(x86_64) | ||||||
|  | 			m_tss.rsp0 = sp; | ||||||
|  | #elif ARCH(i686) | ||||||
|  | 			m_tss.esp0 = sp; | ||||||
|  | #endif | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 	private: | 	private: | ||||||
|  | @ -86,15 +140,21 @@ namespace Kernel | ||||||
| 
 | 
 | ||||||
| 		void flush_tss() | 		void flush_tss() | ||||||
| 		{ | 		{ | ||||||
| 			asm volatile("ltr %0" :: "rm"((uint16_t)0x28) : "memory"); | 			asm volatile("ltr %0" :: "rm"(m_tss_offset) : "memory"); | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 	private: | 	private: | ||||||
|  | #if ARCH(x86_64) | ||||||
| 		BAN::Array<SegmentDescriptor, 7> m_gdt; // null, kernel code, kernel data, user code, user data, tss low, tss high
 | 		BAN::Array<SegmentDescriptor, 7> m_gdt; // null, kernel code, kernel data, user code, user data, tss low, tss high
 | ||||||
|  | 		static constexpr uint16_t m_tss_offset = 0x28; | ||||||
|  | #elif ARCH(i686) | ||||||
|  | 		BAN::Array<SegmentDescriptor, 7> m_gdt; // null, kernel code, kernel data, user code, user data, processor data, tss
 | ||||||
|  | 		static constexpr uint16_t m_tss_offset = 0x30; | ||||||
|  | #endif | ||||||
| 		TaskStateSegment m_tss; | 		TaskStateSegment m_tss; | ||||||
| 		const GDTR m_gdtr { | 		const GDTR m_gdtr { | ||||||
| 			.size = m_gdt.size() * sizeof(SegmentDescriptor) - 1, | 			.size = m_gdt.size() * sizeof(SegmentDescriptor) - 1, | ||||||
| 			.address = reinterpret_cast<uint64_t>(m_gdt.data()) | 			.address = reinterpret_cast<uintptr_t>(m_gdt.data()) | ||||||
| 		}; | 		}; | ||||||
| 	}; | 	}; | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -2,6 +2,7 @@ | ||||||
| 
 | 
 | ||||||
| #include <BAN/Array.h> | #include <BAN/Array.h> | ||||||
| #include <BAN/NoCopyMove.h> | #include <BAN/NoCopyMove.h> | ||||||
|  | #include <kernel/Arch.h> | ||||||
| #include <kernel/Interruptable.h> | #include <kernel/Interruptable.h> | ||||||
| 
 | 
 | ||||||
| #include <stdint.h> | #include <stdint.h> | ||||||
|  | @ -12,21 +13,36 @@ constexpr uint8_t IRQ_IPI = 32; | ||||||
| namespace Kernel | namespace Kernel | ||||||
| { | { | ||||||
| 
 | 
 | ||||||
|  | #if ARCH(x86_64) | ||||||
| 	struct GateDescriptor | 	struct GateDescriptor | ||||||
| 	{ | 	{ | ||||||
| 		uint16_t offset1; | 		uint16_t offset0; | ||||||
| 		uint16_t selector; | 		uint16_t selector; | ||||||
| 		uint8_t IST; | 		uint8_t IST; | ||||||
| 		uint8_t flags; | 		uint8_t flags; | ||||||
| 		uint16_t offset2; | 		uint16_t offset1; | ||||||
| 		uint32_t offset3; | 		uint32_t offset2; | ||||||
| 		uint32_t reserved; | 		uint32_t reserved; | ||||||
| 	} __attribute__((packed)); | 	}; | ||||||
|  | 	static_assert(sizeof(GateDescriptor) == 16); | ||||||
|  | #elif ARCH(i686) | ||||||
|  | 	struct GateDescriptor | ||||||
|  | 	{ | ||||||
|  | 		uint16_t offset0; | ||||||
|  | 		uint16_t selector; | ||||||
|  | 		uint8_t reserved; | ||||||
|  | 		uint8_t flags; | ||||||
|  | 		uint16_t offset1; | ||||||
|  | 	}; | ||||||
|  | 	static_assert(sizeof(GateDescriptor) == 8); | ||||||
|  | #else | ||||||
|  | 	#error | ||||||
|  | #endif | ||||||
| 
 | 
 | ||||||
| 	struct IDTR | 	struct IDTR | ||||||
| 	{ | 	{ | ||||||
| 		uint16_t size; | 		uint16_t size; | ||||||
| 		uint64_t offset; | 		uintptr_t offset; | ||||||
| 	} __attribute__((packed)); | 	} __attribute__((packed)); | ||||||
| 
 | 
 | ||||||
| 	class IDT | 	class IDT | ||||||
|  |  | ||||||
|  | @ -18,6 +18,7 @@ namespace Kernel | ||||||
| 		virtual bool is_in_service(uint8_t) = 0; | 		virtual bool is_in_service(uint8_t) = 0; | ||||||
| 
 | 
 | ||||||
| 		static void initialize(bool force_pic); | 		static void initialize(bool force_pic); | ||||||
|  | 		static bool is_initialized(); | ||||||
| 		static InterruptController& get(); | 		static InterruptController& get(); | ||||||
| 
 | 
 | ||||||
| 		virtual void initialize_multiprocessor() = 0; | 		virtual void initialize_multiprocessor() = 0; | ||||||
|  |  | ||||||
|  | @ -0,0 +1,69 @@ | ||||||
|  | #include <kernel/GDT.h> | ||||||
|  | #include <kernel/Processor.h> | ||||||
|  | 
 | ||||||
|  | #include <string.h> | ||||||
|  | 
 | ||||||
|  | namespace Kernel | ||||||
|  | { | ||||||
|  | 
 | ||||||
|  | 	GDT* GDT::create([[maybe_unused]] void* processor) | ||||||
|  | 	{ | ||||||
|  | 		auto* gdt = new GDT(); | ||||||
|  | 		ASSERT(gdt); | ||||||
|  | 
 | ||||||
|  | #if ARCH(x86_64) | ||||||
|  | 		constexpr uint8_t code_flags = 0xA; | ||||||
|  | 		constexpr uint8_t data_flags = 0xC; | ||||||
|  | #elif ARCH(i686) | ||||||
|  | 		constexpr uint8_t code_flags = 0xC; | ||||||
|  | 		constexpr uint8_t data_flags = 0xC; | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
|  | 		gdt->write_entry(0x00, 0x00000000, 0x00000, 0x00, 0x0);			// null
 | ||||||
|  | 		gdt->write_entry(0x08, 0x00000000, 0xFFFFF, 0x9A, code_flags);	// kernel code
 | ||||||
|  | 		gdt->write_entry(0x10, 0x00000000, 0xFFFFF, 0x92, data_flags);	// kernel data
 | ||||||
|  | 		gdt->write_entry(0x18, 0x00000000, 0xFFFFF, 0xFA, code_flags);	// user code
 | ||||||
|  | 		gdt->write_entry(0x20, 0x00000000, 0xFFFFF, 0xF2, data_flags);	// user data
 | ||||||
|  | #if ARCH(i686) | ||||||
|  | 		gdt->write_entry(0x28, reinterpret_cast<uint32_t>(processor), sizeof(Processor), 0x92, 0x4); // processor data
 | ||||||
|  | #endif | ||||||
|  | 		gdt->write_tss(); | ||||||
|  | 
 | ||||||
|  | 		return gdt; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	void GDT::write_entry(uint8_t offset, uint32_t base, uint32_t limit, uint8_t access, uint8_t flags) | ||||||
|  | 	{ | ||||||
|  | 		ASSERT(offset % sizeof(SegmentDescriptor) == 0); | ||||||
|  | 		uint8_t idx = offset / sizeof(SegmentDescriptor); | ||||||
|  | 
 | ||||||
|  | 		auto& desc = m_gdt[idx]; | ||||||
|  | 		desc.base1 = (base >>  0) & 0xFFFF; | ||||||
|  | 		desc.base2 = (base >> 16) & 0xFF; | ||||||
|  | 		desc.base3 = (base >> 24) & 0xFF; | ||||||
|  | 
 | ||||||
|  | 		desc.limit1 = (limit >>  0) & 0xFFFF; | ||||||
|  | 		desc.limit2 = (limit >> 16) & 0x0F; | ||||||
|  | 
 | ||||||
|  | 		desc.access = access & 0xFF; | ||||||
|  | 
 | ||||||
|  | 		desc.flags = flags & 0x0F; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	void GDT::write_tss() | ||||||
|  | 	{ | ||||||
|  | 		memset(&m_tss, 0x00, sizeof(TaskStateSegment)); | ||||||
|  | 		m_tss.iopb = sizeof(TaskStateSegment); | ||||||
|  | 
 | ||||||
|  | 		uintptr_t base = reinterpret_cast<uintptr_t>(&m_tss); | ||||||
|  | 
 | ||||||
|  | 		write_entry(m_tss_offset, (uint32_t)base, sizeof(TaskStateSegment), 0x89, 0x0); | ||||||
|  | 
 | ||||||
|  | #if ARCH(x86_64) | ||||||
|  | 		auto& desc = m_gdt[(m_tss_offset + 8) / sizeof(SegmentDescriptor)]; | ||||||
|  | 		desc.low = base >> 32; | ||||||
|  | 		desc.high = 0; | ||||||
|  | #endif | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | } | ||||||
|  | @ -141,21 +141,16 @@ namespace Kernel | ||||||
| 		"Unkown Exception 0x1F", | 		"Unkown Exception 0x1F", | ||||||
| 	}; | 	}; | ||||||
| 
 | 
 | ||||||
| 	extern "C" void cpp_isr_handler(uint64_t isr, uint64_t error, InterruptStack& interrupt_stack, const Registers* regs) | 	extern "C" void cpp_isr_handler(uint32_t isr, uint32_t error, InterruptStack& interrupt_stack, const Registers* regs) | ||||||
| 	{ | 	{ | ||||||
| 		if (g_paniced) | 		if (g_paniced) | ||||||
| 		{ | 		{ | ||||||
| 			dprintln("Processor {} halted", Processor::current_id()); | 			dprintln("Processor {} halted", Processor::current_id()); | ||||||
| 			InterruptController::get().broadcast_ipi(); | 			if (InterruptController::is_initialized()) | ||||||
|  | 				InterruptController::get().broadcast_ipi(); | ||||||
| 			asm volatile("cli; 1: hlt; jmp 1b"); | 			asm volatile("cli; 1: hlt; jmp 1b"); | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| #if __enable_sse |  | ||||||
| 		bool from_userspace = (interrupt_stack.cs & 0b11) == 0b11; |  | ||||||
| 		if (from_userspace) |  | ||||||
| 			Thread::current().save_sse(); |  | ||||||
| #endif |  | ||||||
| 
 |  | ||||||
| 		pid_t tid = Scheduler::current_tid(); | 		pid_t tid = Scheduler::current_tid(); | ||||||
| 		pid_t pid = tid ? Process::current().pid() : 0; | 		pid_t pid = tid ? Process::current().pid() : 0; | ||||||
| 
 | 
 | ||||||
|  | @ -209,11 +204,19 @@ namespace Kernel | ||||||
| #if __enable_sse | #if __enable_sse | ||||||
| 			else if (isr == ISR::DeviceNotAvailable) | 			else if (isr == ISR::DeviceNotAvailable) | ||||||
| 			{ | 			{ | ||||||
|  | #if ARCH(x86_64) | ||||||
| 				asm volatile( | 				asm volatile( | ||||||
| 					"movq %cr0, %rax;" | 					"movq %cr0, %rax;" | ||||||
| 					"andq $~(1 << 3), %rax;" | 					"andq $~(1 << 3), %rax;" | ||||||
| 					"movq %rax, %cr0;" | 					"movq %rax, %cr0;" | ||||||
| 				); | 				); | ||||||
|  | #elif ARCH(i686) | ||||||
|  | 				asm volatile( | ||||||
|  | 					"movl %cr0, %eax;" | ||||||
|  | 					"andl $~(1 << 3), %eax;" | ||||||
|  | 					"movl %eax, %cr0;" | ||||||
|  | 				); | ||||||
|  | #endif | ||||||
| 				if (auto* current = &Thread::current(); current != Thread::sse_thread()) | 				if (auto* current = &Thread::current(); current != Thread::sse_thread()) | ||||||
| 				{ | 				{ | ||||||
| 					if (auto* sse = Thread::sse_thread()) | 					if (auto* sse = Thread::sse_thread()) | ||||||
|  | @ -302,7 +305,8 @@ done: | ||||||
| 		if (g_paniced) | 		if (g_paniced) | ||||||
| 		{ | 		{ | ||||||
| 			dprintln("Processor {} halted", Processor::current_id()); | 			dprintln("Processor {} halted", Processor::current_id()); | ||||||
| 			InterruptController::get().broadcast_ipi(); | 			if (InterruptController::is_initialized()) | ||||||
|  | 				InterruptController::get().broadcast_ipi(); | ||||||
| 			asm volatile("cli; 1: hlt; jmp 1b"); | 			asm volatile("cli; 1: hlt; jmp 1b"); | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
|  | @ -332,14 +336,17 @@ done: | ||||||
| 
 | 
 | ||||||
| 	void IDT::register_interrupt_handler(uint8_t index, void (*handler)()) | 	void IDT::register_interrupt_handler(uint8_t index, void (*handler)()) | ||||||
| 	{ | 	{ | ||||||
| 		auto& descriptor = m_idt[index]; | 		auto& desc = m_idt[index]; | ||||||
| 		descriptor.offset1 = (uint16_t)((uint64_t)handler >> 0); | 		memset(&desc, 0, sizeof(GateDescriptor)); | ||||||
| 		descriptor.offset2 = (uint16_t)((uint64_t)handler >> 16); |  | ||||||
| 		descriptor.offset3 = (uint32_t)((uint64_t)handler >> 32); |  | ||||||
| 
 | 
 | ||||||
| 		descriptor.selector = 0x08; | 		desc.offset0 = (uint16_t)((uintptr_t)handler >> 0); | ||||||
| 		descriptor.IST = 0; | 		desc.offset1 = (uint16_t)((uintptr_t)handler >> 16); | ||||||
| 		descriptor.flags = 0x8E; | #if ARCH(x86_64) | ||||||
|  | 		desc.offset2 = (uint32_t)((uintptr_t)handler >> 32); | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
|  | 		desc.selector = 0x08; | ||||||
|  | 		desc.flags = 0x8E; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	void IDT::register_syscall_handler(uint8_t index, void (*handler)()) | 	void IDT::register_syscall_handler(uint8_t index, void (*handler)()) | ||||||
|  | @ -40,6 +40,11 @@ namespace Kernel | ||||||
| 		s_instance->m_using_apic = false; | 		s_instance->m_using_apic = false; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | 	bool InterruptController::is_initialized() | ||||||
|  | 	{ | ||||||
|  | 		return s_instance; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
| 	void InterruptController::enter_acpi_mode() | 	void InterruptController::enter_acpi_mode() | ||||||
| 	{ | 	{ | ||||||
| #if ARCH(x86_64) | #if ARCH(x86_64) | ||||||
|  |  | ||||||
|  | @ -38,7 +38,7 @@ namespace Kernel | ||||||
| 		processor.m_stack = kmalloc(s_stack_size, 4096, true); | 		processor.m_stack = kmalloc(s_stack_size, 4096, true); | ||||||
| 		ASSERT(processor.m_stack); | 		ASSERT(processor.m_stack); | ||||||
| 
 | 
 | ||||||
| 		processor.m_gdt = GDT::create(); | 		processor.m_gdt = GDT::create(&processor); | ||||||
| 		ASSERT(processor.m_gdt); | 		ASSERT(processor.m_gdt); | ||||||
| 
 | 
 | ||||||
| 		processor.m_idt = IDT::create(); | 		processor.m_idt = IDT::create(); | ||||||
|  | @ -52,14 +52,19 @@ namespace Kernel | ||||||
| 		auto id = read_processor_id(); | 		auto id = read_processor_id(); | ||||||
| 		auto& processor = s_processors[id]; | 		auto& processor = s_processors[id]; | ||||||
| 
 | 
 | ||||||
|  | 		ASSERT(processor.m_gdt); | ||||||
|  | 		processor.m_gdt->load(); | ||||||
|  | 
 | ||||||
|  | 		// initialize GS
 | ||||||
|  | #if ARCH(x86_64) | ||||||
| 		// set gs base to pointer to this processor
 | 		// set gs base to pointer to this processor
 | ||||||
| 		uint64_t ptr = reinterpret_cast<uint64_t>(&processor); | 		uint64_t ptr = reinterpret_cast<uint64_t>(&processor); | ||||||
| 		uint32_t ptr_hi = ptr >> 32; | 		uint32_t ptr_hi = ptr >> 32; | ||||||
| 		uint32_t ptr_lo = ptr & 0xFFFFFFFF; | 		uint32_t ptr_lo = ptr & 0xFFFFFFFF; | ||||||
| 		asm volatile("wrmsr" :: "d"(ptr_hi), "a"(ptr_lo), "c"(MSR_IA32_GS_BASE)); | 		asm volatile("wrmsr" :: "d"(ptr_hi), "a"(ptr_lo), "c"(MSR_IA32_GS_BASE)); | ||||||
| 
 | #elif ARCH(i686) | ||||||
| 		ASSERT(processor.m_gdt); | 		asm volatile("movw $0x28, %%ax; movw %%ax, %%gs" ::: "ax"); | ||||||
| 		processor.gdt().load(); | #endif | ||||||
| 
 | 
 | ||||||
| 		ASSERT(processor.m_idt); | 		ASSERT(processor.m_idt); | ||||||
| 		processor.idt().load(); | 		processor.idt().load(); | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue