diff options
Diffstat (limited to 'Kernel/HALKit/AMD64')
33 files changed, 2521 insertions, 0 deletions
diff --git a/Kernel/HALKit/AMD64/CPUID.hxx b/Kernel/HALKit/AMD64/CPUID.hxx new file mode 100644 index 00000000..0e570148 --- /dev/null +++ b/Kernel/HALKit/AMD64/CPUID.hxx @@ -0,0 +1,81 @@ +/* ------------------------------------------- + + Copyright SoftwareLabs + + File: CPUID.hxx + Purpose: CPUID flags. + + Revision History: + + 30/01/24: Added file (amlel) + +------------------------------------------- */ + +#pragma once + +enum +{ + CPU_FEATURE_ECX_SSE3 = 1 << 0, + CPU_FEATURE_ECX_PCLMUL = 1 << 1, + CPU_FEATURE_ECX_DTES64 = 1 << 2, + CPU_FEATURE_ECX_MONITOR = 1 << 3, + CPU_FEATURE_ECX_DS_CPL = 1 << 4, + CPU_FEATURE_ECX_VMX = 1 << 5, + CPU_FEATURE_ECX_SMX = 1 << 6, + CPU_FEATURE_ECX_EST = 1 << 7, + CPU_FEATURE_ECX_TM2 = 1 << 8, + CPU_FEATURE_ECX_SSSE3 = 1 << 9, + CPU_FEATURE_ECX_CID = 1 << 10, + CPU_FEATURE_ECX_SDBG = 1 << 11, + CPU_FEATURE_ECX_FMA = 1 << 12, + CPU_FEATURE_ECX_CX16 = 1 << 13, + CPU_FEATURE_ECX_XTPR = 1 << 14, + CPU_FEATURE_ECX_PDCM = 1 << 15, + CPU_FEATURE_ECX_PCID = 1 << 17, + CPU_FEATURE_ECX_DCA = 1 << 18, + CPU_FEATURE_ECX_SSE4_1 = 1 << 19, + CPU_FEATURE_ECX_SSE4_2 = 1 << 20, + CPU_FEATURE_ECX_X2APIC = 1 << 21, + CPU_FEATURE_ECX_MOVBE = 1 << 22, + CPU_FEATURE_ECX_POP3C = 1 << 23, + CPU_FEATURE_ECX_TSC = 1 << 24, + CPU_FEATURE_ECX_AES = 1 << 25, + CPU_FEATURE_ECX_XSAVE = 1 << 26, + CPU_FEATURE_ECX_OSXSAVE = 1 << 27, + CPU_FEATURE_ECX_AVX = 1 << 28, + CPU_FEATURE_ECX_F16C = 1 << 29, + CPU_FEATURE_ECX_RDRAND = 1 << 30, + CPU_FEATURE_ECX_HYPERVISOR = 1 << 31, + CPU_FEATURE_EDX_FPU = 1 << 0, + CPU_FEATURE_EDX_VME = 1 << 1, + CPU_FEATURE_EDX_DE = 1 << 2, + CPU_FEATURE_EDX_PSE = 1 << 3, + CPU_FEATURE_EDX_TSC = 1 << 4, + CPU_FEATURE_EDX_MSR = 1 << 5, + CPU_FEATURE_EDX_PAE = 1 << 6, + CPU_FEATURE_EDX_MCE = 1 << 7, + CPU_FEATURE_EDX_CX8 = 1 << 8, + CPU_FEATURE_EDX_APIC = 1 << 9, + CPU_FEATURE_EDX_SEP = 1 << 11, + CPU_FEATURE_EDX_MTRR = 1 << 12, + CPU_FEATURE_EDX_PGE = 1 << 13, + CPU_FEATURE_EDX_MCA = 1 << 14, + CPU_FEATURE_EDX_CMOV = 1 << 15, + CPU_FEATURE_EDX_PAT = 1 << 16, + CPU_FEATURE_EDX_PSE36 = 1 << 17, + CPU_FEATURE_EDX_PSN = 1 << 18, + CPU_FEATURE_EDX_CLFLUSH = 1 << 19, + CPU_FEATURE_EDX_DS = 1 << 21, + CPU_FEATURE_EDX_ACPI = 1 << 22, + CPU_FEATURE_EDX_MMX = 1 << 23, + CPU_FEATURE_EDX_FXSR = 1 << 24, + CPU_FEATURE_EDX_SSE = 1 << 25, + CPU_FEATURE_EDX_SSE2 = 1 << 26, + CPU_FEATURE_EDX_SS = 1 << 27, + CPU_FEATURE_EDX_HTT = 1 << 28, + CPU_FEATURE_EDX_TM = 1 << 29, + CPU_FEATURE_EDX_IA64 = 1 << 30, + CPU_FEATURE_EDX_PBE = 1 << 31 +}; + +typedef int CPU_FEATURE;
\ No newline at end of file diff --git a/Kernel/HALKit/AMD64/HalACPIFactoryInterface.cxx b/Kernel/HALKit/AMD64/HalACPIFactoryInterface.cxx new file mode 100644 index 00000000..3609165f --- /dev/null +++ b/Kernel/HALKit/AMD64/HalACPIFactoryInterface.cxx @@ -0,0 +1,123 @@ +/* ------------------------------------------- + + Copyright SoftwareLabs + +------------------------------------------- */ + +#include <Builtins/ACPI/ACPIFactoryInterface.hxx> +#include <HALKit/AMD64/Processor.hpp> +#include <NewKit/String.hpp> + +namespace NewOS +{ + + /// Custom to the virtual machine, you'll need to parse the MADT instead. + + void rt_shutdown_acpi_qemu_20(void) + { + HAL::Out16(0xb004, 0x2000); + } + + void rt_shutdown_acpi_qemu_30_plus(void) + { + HAL::Out16(0x604, 0x2000); + } + + void rt_shutdown_acpi_virtualbox(void) + { + HAL::Out16(0x4004, 0x3400); + } + + /// You have to parse the MADT! + + ACPIFactoryInterface::ACPIFactoryInterface(voidPtr rsdPtr) + : fRsdp(rsdPtr), fEntries(0) + { + } + + Void ACPIFactoryInterface::Shutdown() + { +#ifdef __DEBUG__ + rt_shutdown_acpi_qemu_30_plus(); +#else + +#endif + } + + /// @brief Reboot (shutdowns on qemu.) + /// @return + Void ACPIFactoryInterface::Reboot() + { +#ifdef __DEBUG__ + rt_shutdown_acpi_qemu_30_plus(); +#else + +#endif + } + + /// @brief Finds a descriptor table inside ACPI XSDT. + ErrorOr<voidPtr> ACPIFactoryInterface::Find(const char* signature) + { + MUST_PASS(fRsdp); + + if (!signature) + return ErrorOr<voidPtr>{-2}; + + if (*signature == 0) + return ErrorOr<voidPtr>{-3}; + + RSDP* rsdPtr = reinterpret_cast<RSDP*>(this->fRsdp); + + if (rsdPtr->Revision <= 1) + { + return ErrorOr<voidPtr>{-4}; + } + + SDT* xsdt = (SDT*)(rsdPtr->XsdtAddress >> (rsdPtr->XsdtAddress & 0xFFF)); + + SizeT num = xsdt->Length + sizeof(SDT) / 8; + + this->fEntries = num; + + kcout << "ACPI: Number of entries: " << number(num) << endl; + kcout << "ACPI: Address of XSDT: " << hex_number((UIntPtr)xsdt) << endl; + + constexpr short ACPI_SIGNATURE_LENGTH = 4; + + for (Size index = 0; index < num; ++index) + { + SDT* sdt = (SDT*)*((UInt64*)(UInt64)xsdt + sizeof(SDT) + (index * 8)); + + for (int signature_index = 0; signature_index < 4; signature_index++) + { + if (sdt->Signature[signature_index] != signature[signature_index]) + break; + + if (signature_index == 3) + return ErrorOr<voidPtr>(reinterpret_cast<voidPtr>((SDT*)sdt)); + } + } + + return ErrorOr<voidPtr>{-1}; + } + + /*** + @brief check SDT header + @param checksum the header to checksum + @param len the length of it. +*/ + bool ACPIFactoryInterface::Checksum(const char* checksum, SSizeT len) + { + if (len == 0) + return -1; + + char chr = 0; + + for (int index = 0; index < len; ++index) + { + chr += checksum[index]; + } + + return chr == 0; + } +} // namespace NewOS diff --git a/Kernel/HALKit/AMD64/HalControlRegister.s b/Kernel/HALKit/AMD64/HalControlRegister.s new file mode 100644 index 00000000..7798ea09 --- /dev/null +++ b/Kernel/HALKit/AMD64/HalControlRegister.s @@ -0,0 +1,40 @@ +/* ------------------------------------------- + + Copyright SoftwareLabs + +------------------------------------------- */ + +.globl hal_write_cr3 +.globl hal_write_cr0 +.globl hal_read_cr2 +.globl hal_read_cr3 +.globl hal_read_cr0 +.globl hal_flush_tlb + +.text + +hal_flush_tlb: + call hal_read_cr3 + mov %rcx, %rax + call hal_write_cr3 + ret + +hal_read_cr3: + movq %cr3, %rax + ret + +hal_read_cr0: + movq %rax, %cr0 + ret + +hal_read_cr2: + movq %rax, %cr2 + ret + +hal_write_cr3: + movq %cr3, %rdi + ret + +hal_write_cr0: + movq %cr0, %rdi + ret diff --git a/Kernel/HALKit/AMD64/HalCoreInterruptHandlerAMD64.cpp b/Kernel/HALKit/AMD64/HalCoreInterruptHandlerAMD64.cpp new file mode 100644 index 00000000..1f2e21e2 --- /dev/null +++ b/Kernel/HALKit/AMD64/HalCoreInterruptHandlerAMD64.cpp @@ -0,0 +1,101 @@ +/* ------------------------------------------- + + Copyright SoftwareLabs + +------------------------------------------- */ + +#include <ArchKit/ArchKit.hpp> +#include <KernelKit/ProcessScheduler.hpp> +#include <NewKit/String.hpp> + +/// @brief Handle GPF fault. +/// @param rsp +EXTERN_C void idt_handle_gpf(NewOS::UIntPtr rsp) +{ + MUST_PASS(NewOS::ProcessScheduler::Shared().Leak().GetCurrent()); + + NewOS::kcout << "New OS: Stack Pointer: " + << NewOS::StringBuilder::FromInt("rsp{%}", rsp); + + NewOS::kcout + << "New OS: General Protection Fault, caused by " + << NewOS::ProcessScheduler::Shared().Leak().GetCurrent().Leak().GetName(); + + NewOS::ProcessScheduler::Shared().Leak().GetCurrent().Leak().Crash(); +} + +/// @brief Handle the scheduler interrupt, raised from the HPET timer. +/// @param rsp +EXTERN_C void idt_handle_scheduler(NewOS::UIntPtr rsp) +{ + NewOS::kcout << NewOS::StringBuilder::FromInt("rsp{%}", rsp); + + NewOS::kcout + << "New OS: Will be scheduled back later " + << NewOS::ProcessScheduler::Shared().Leak().GetCurrent().Leak().GetName() + << NewOS::end_line(); + + /// schedule another process. + if (!NewOS::ProcessHelper::StartScheduling()) + { + NewOS::kcout << "New OS: Continue schedule this process...\r"; + } +} + +/// @brief Handle page fault. +/// @param rsp +EXTERN_C void idt_handle_pf(NewOS::UIntPtr rsp) +{ + MUST_PASS(NewOS::ProcessScheduler::Shared().Leak().GetCurrent()); + NewOS::kcout << NewOS::StringBuilder::FromInt("rsp{%}", rsp); + + NewOS::kcout + << "New OS: Segmentation Fault, caused by " + << NewOS::ProcessScheduler::Shared().Leak().GetCurrent().Leak().GetName(); + + NewOS::ProcessScheduler::Shared().Leak().GetCurrent().Leak().Crash(); +} + +/// @brief Handle math fault. +/// @param rsp +EXTERN_C void idt_handle_math(NewOS::UIntPtr rsp) +{ + MUST_PASS(NewOS::ProcessScheduler::Shared().Leak().GetCurrent()); + NewOS::kcout << NewOS::StringBuilder::FromInt("rsp{%}", rsp); + + NewOS::kcout + << "New OS: Math error, caused by " + << NewOS::ProcessScheduler::Shared().Leak().GetCurrent().Leak().GetName(); + + NewOS::ProcessScheduler::Shared().Leak().GetCurrent().Leak().Crash(); +} + +/// @brief Handle any generic fault. +/// @param rsp +EXTERN_C void idt_handle_generic(NewOS::UIntPtr rsp) +{ + MUST_PASS(NewOS::ProcessScheduler::Shared().Leak().GetCurrent()); + NewOS::kcout << NewOS::StringBuilder::FromInt("sp{%}", rsp); + + NewOS::kcout + << "New OS: Execution error, caused by " + << NewOS::ProcessScheduler::Shared().Leak().GetCurrent().Leak().GetName(); + + NewOS::ProcessScheduler::Shared().Leak().GetCurrent().Leak().Crash(); +} + +/// @brief Handle #UD fault. +/// @param rsp +EXTERN_C void idt_handle_ud(NewOS::UIntPtr rsp) +{ + MUST_PASS(NewOS::ProcessScheduler::Shared().Leak().GetCurrent()); + + NewOS::kcout << "New OS: Stack Pointer: " + << NewOS::StringBuilder::FromInt("rsp{%}", rsp); + + NewOS::kcout + << "New OS: Invalid interrupt, caused by " + << NewOS::ProcessScheduler::Shared().Leak().GetCurrent().Leak().GetName(); + + NewOS::ProcessScheduler::Shared().Leak().GetCurrent().Leak().Crash(); +} diff --git a/Kernel/HALKit/AMD64/HalCoreMultiProcessingAMD64.cpp b/Kernel/HALKit/AMD64/HalCoreMultiProcessingAMD64.cpp new file mode 100644 index 00000000..2129d790 --- /dev/null +++ b/Kernel/HALKit/AMD64/HalCoreMultiProcessingAMD64.cpp @@ -0,0 +1,124 @@ +/* ------------------------------------------- + + Copyright SoftwareLabs + +------------------------------------------- */ + +#include <Builtins/ACPI/ACPIFactoryInterface.hxx> +#include <HALKit/AMD64/Processor.hpp> +#include <NewKit/KernelCheck.hpp> + +/////////////////////////////////////////////////////////////////////////////////////// + +//! NOTE: fGSI stands 'Field Global System Interrupt' + +/////////////////////////////////////////////////////////////////////////////////////// + +namespace NewOS::HAL +{ + constexpr Int32 kThreadAPIC = 0; + constexpr Int32 kThreadLAPIC = 1; + constexpr Int32 kThreadIOAPIC = 2; + constexpr Int32 kThreadAPIC64 = 3; + constexpr Int32 kThreadBoot = 4; + + /* + * + * this is used to store info about the current running thread + * we use this struct to determine if we can use it, or mark it as used or on + * sleep. + * + */ + + struct ProcessorInfoAMD64 final + { + Int32 ThreadType; + UIntPtr JumpAddress; + + struct + { + UInt32 Code; + UInt32 Data; + UInt32 BSS; + } Selector; + }; + + STATIC voidPtr kApicMadt = nullptr; + STATIC const char* kApicSignature = "APIC"; + + /// @brief Multiple APIC descriptor table. + struct MadtType final : public SDT + { + struct MadtAddress final + { + UInt32 fFlags; // 1 = Dual Legacy PICs installed + UInt32 fPhysicalAddress; + + Char fType; + Char fRecLen; // record length + } Madt[]; + }; + + struct MadtProcessorLocalApic final + { + Char fProcessorId; + Char fApicId; + UInt32 fFlags; + }; + + struct MadtIOApic final + { + Char fApicId; + Char fReserved; + UInt32 fAddress; + UInt32 fSystemInterruptBase; + }; + + struct MadtInterruptSource final + { + Char fBusSource; + Char fIrqSource; + UInt32 fGSI; + UInt16 fFlags; + }; + + struct MadtInterruptNmi final + { + Char fNmiSource; + Char fReserved; + UInt16 fFlags; + UInt32 fGSI; + }; + + struct MadtLocalApicAddressOverride final + { + UInt16 fResvered; + UIntPtr fAddress; + }; + + /////////////////////////////////////////////////////////////////////////////////////// + + STATIC MadtType* kApicInfoBlock = nullptr; + + /////////////////////////////////////////////////////////////////////////////////////// + + void hal_system_get_cores(voidPtr rsdPtr) + { + kcout << "New OS: Constructing ACPIFactoryInterface...\r"; + + auto acpi = ACPIFactoryInterface(rsdPtr); + kApicMadt = acpi.Find(kApicSignature).Leak().Leak(); + + if (kApicMadt) + { + kcout << "New OS: Successfuly fetched the MADT!\r"; + kApicInfoBlock = (MadtType*)kApicMadt; + } + else + { + MUST_PASS(false); + } + } +} // namespace NewOS::HAL + +/////////////////////////////////////////////////////////////////////////////////////// diff --git a/Kernel/HALKit/AMD64/HalDebugOutput.cxx b/Kernel/HALKit/AMD64/HalDebugOutput.cxx new file mode 100644 index 00000000..3227be1f --- /dev/null +++ b/Kernel/HALKit/AMD64/HalDebugOutput.cxx @@ -0,0 +1,145 @@ +/* ------------------------------------------- + + Copyright SoftwareLabs + +------------------------------------------- */ + +#include <ArchKit/ArchKit.hpp> +#include <KernelKit/DebugOutput.hpp> +#include <KernelKit/Framebuffer.hpp> +#include <NewKit/Utils.hpp> + +namespace NewOS +{ + enum CommStatus + { + kStateInvalid, + kStateReady = 0xCF, + kStateTransmit = 0xFC, + kStateCnt = 3 + }; + + namespace Detail + { + constexpr short PORT = 0x3F8; + + static int kState = kStateInvalid; + + /// @brief Init COM1. + /// @return + bool serial_init() noexcept + { +#ifdef __DEBUG__ + if (kState == kStateReady || kState == kStateTransmit) + return true; + + HAL::Out8(PORT + 1, 0x00); // Disable all interrupts + HAL::Out8(PORT + 3, 0x80); // Enable DLAB (set baud rate divisor) + HAL::Out8(PORT + 0, 0x03); // Set divisor to 3 (lo byte) 38400 baud + HAL::Out8(PORT + 1, 0x00); // (hi byte) + HAL::Out8(PORT + 3, 0x03); // 8 bits, no parity, one stop bit + HAL::Out8(PORT + 2, 0xC7); // Enable FIFO, clear them, with 14-byte threshold + HAL::Out8(PORT + 4, 0x0B); // IRQs enabled, RTS/DSR set + HAL::Out8(PORT + 4, 0x1E); // Set in loopback mode, test the serial chip + HAL::Out8(PORT + 0, 0xAE); // Test serial chip (send byte 0xAE and check if + // serial returns same byte) + + // Check if serial is faulty (i.e: not same byte as sent) + if (HAL::In8(PORT) != 0xAE) + { + ke_stop(RUNTIME_CHECK_HANDSHAKE); + } + + kState = kStateReady; + + // If serial is not faulty set it in normal operation mode + // (not-loopback with IRQs enabled and OUT#1 and OUT#2 bits enabled) + HAL::Out8(Detail::PORT + 4, 0x0F); +#endif // __DEBUG__ + + return true; + } + } // namespace Detail + + EXTERN_C void ke_io_write(const char* bytes) + { +#ifdef __DEBUG__ + Detail::serial_init(); + + if (!bytes || Detail::kState != kStateReady) + return; + if (*bytes == 0) + return; + + Detail::kState = kStateTransmit; + + SizeT index = 0; + SizeT len = rt_string_len(bytes, 256); + + while (index < len) + { + if (bytes[index] == '\r') + HAL::Out8(Detail::PORT, '\r'); + + HAL::Out8(Detail::PORT, bytes[index] == '\r' ? '\n' : bytes[index]); + ++index; + } + + Detail::kState = kStateReady; +#endif // __DEBUG__ + } + + EXTERN_C void ke_io_read(const char* bytes) + { +#ifdef __DEBUG__ + Detail::serial_init(); + + if (!bytes || Detail::kState != kStateReady) + return; + + Detail::kState = kStateTransmit; + + SizeT index = 0; + + ///! TODO: Look on how to wait for the UART to complete. + while (true) + { + auto in = HAL::In8(Detail::PORT); + + ///! If enter pressed then break. + if (in == 0xD) + { + break; + } + + if (in < '0' || in < 'A' || in < 'a') + { + if (in != '@' || in != '!' || in != '?' || in != '.' || in != '/' || + in != ':') + { + continue; + } + } + + ((char*)bytes)[index] = in; + + ++index; + } + + ((char*)bytes)[index] = 0; + + Detail::kState = kStateReady; +#endif // __DEBUG__ + } + + TerminalDevice& TerminalDevice::Shared() noexcept + { + static TerminalDevice* out = nullptr; + + if (!out) + out = new TerminalDevice(NewOS::ke_io_write, NewOS::ke_io_read); + + return *out; + } + +} // namespace NewOS diff --git a/Kernel/HALKit/AMD64/HalDebugPort.cxx b/Kernel/HALKit/AMD64/HalDebugPort.cxx new file mode 100644 index 00000000..6d7a03f5 --- /dev/null +++ b/Kernel/HALKit/AMD64/HalDebugPort.cxx @@ -0,0 +1,40 @@ +/* ------------------------------------------- + + Copyright SoftwareLabs + +------------------------------------------- */ + +//! @file DebuggerPort.cxx +//! @brief UART debug via packets. + +#include <ArchKit/ArchKit.hpp> +#include <KernelKit/DebugOutput.hpp> + +// after that we have start of additional data. + +namespace NewOS +{ + void rt_debug_listen(DebuggerPortHeader* theHook) noexcept + { + if (theHook == nullptr) + return; + + for (UInt32 i = 0U; i < kDebugMaxPorts; ++i) + { + HAL::Out16(theHook->fPort[i], kDebugMag0); + HAL::rt_wait_400ns(); + + HAL::Out16(theHook->fPort[i], kDebugMag1); + HAL::rt_wait_400ns(); + + HAL::Out16(theHook->fPort[i], kDebugMag2); + HAL::rt_wait_400ns(); + + HAL::Out16(theHook->fPort[i], kDebugMag3); + HAL::rt_wait_400ns(); + + if (HAL::In16(theHook->fPort[i] != kDebugUnboundPort)) + theHook->fBoundCnt++; + } + } +} // namespace NewOS diff --git a/Kernel/HALKit/AMD64/HalDescriptorLoader.cpp b/Kernel/HALKit/AMD64/HalDescriptorLoader.cpp new file mode 100644 index 00000000..689c1742 --- /dev/null +++ b/Kernel/HALKit/AMD64/HalDescriptorLoader.cpp @@ -0,0 +1,90 @@ +/* ------------------------------------------- + + Copyright SoftwareLabs + +------------------------------------------- */ + +#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 diff --git a/Kernel/HALKit/AMD64/HalHardwareMP.cpp b/Kernel/HALKit/AMD64/HalHardwareMP.cpp new file mode 100644 index 00000000..2ebf45fd --- /dev/null +++ b/Kernel/HALKit/AMD64/HalHardwareMP.cpp @@ -0,0 +1,34 @@ +/* ------------------------------------------- + + Copyright SoftwareLabs + +------------------------------------------- */ + +#include <ArchKit/ArchKit.hpp> + +// bugs = 0 + +namespace NewOS +{ + /// @brief wakes up thread. + /// wakes up thread from hang. + void rt_wakeup_thread(HAL::StackFrame* stack) + { + HAL::rt_cli(); + + stack->Rcx = 0; + + HAL::rt_sti(); + } + + /// @brief makes thread sleep. + /// hooks and hangs thread to prevent code from executing. + void rt_hang_thread(HAL::StackFrame* stack) + { + HAL::rt_cli(); + + stack->Rcx = 1; + + HAL::rt_sti(); + } +} // namespace NewOS diff --git a/Kernel/HALKit/AMD64/HalInstallTIB.asm b/Kernel/HALKit/AMD64/HalInstallTIB.asm new file mode 100644 index 00000000..a5f3ef73 --- /dev/null +++ b/Kernel/HALKit/AMD64/HalInstallTIB.asm @@ -0,0 +1,22 @@ +;; /* +;; * ======================================================== +;; * +;; * NewOS +;; * Copyright SoftwareLabs, all rights reserved. +;; * +;; * ======================================================== +;; */ + +[bits 64] + +[global rt_install_tib] + +;; changed: rs, fs +;; expected: rcx, rdx + +rt_install_tib: + mov rcx, gs ;; TIB -> Thread Information Block + mov rdx, fs ;; PIB -> Process Information Block + ret + +;; //////////////////////////////////////////////////// ;; diff --git a/Kernel/HALKit/AMD64/HalInterruptAPI.asm b/Kernel/HALKit/AMD64/HalInterruptAPI.asm new file mode 100644 index 00000000..e4063388 --- /dev/null +++ b/Kernel/HALKit/AMD64/HalInterruptAPI.asm @@ -0,0 +1,222 @@ +;; /* +;; * --------------------------------------------------- +;; * +;; * Copyright SoftwareLabs, all rights reserved. +;; * +;; * File: HalInterruptAPI.asm +;; * Purpose: Interrupt routing, redirect raw interrupts into their handlers. +;; * +;; * --------------------------------------------------- +;; */ + +[bits 64] + +%define kInterruptId 0x21 + +%macro IntExp 1 +global __HCR_INT_%1 +__HCR_INT_%1: + cld + + iretq +%endmacro + +%macro IntNormal 1 +global __HCR_INT_%1 +__HCR_INT_%1: + cld + + iretq +%endmacro + +; This file handles the core interrupt table +; Last edited 31/01/24 + +global _ke_power_on_self_test +global ke_handle_irq +global kInterruptVectorTable + +extern _hal_handle_mouse +extern idt_handle_gpf +extern idt_handle_pf +extern ke_io_write +extern idt_handle_ud + +section .text + +IntNormal 0 +IntNormal 1 + +IntNormal 2 + +IntNormal 3 +IntNormal 4 +IntNormal 5 + +;; Invalid opcode interrupt +__HCR_INT_6: + cli + + push rax + + mov rcx, rsp + call idt_handle_ud + + pop rax + + sti + iretq + +IntNormal 7 +IntExp 8 +IntNormal 9 +IntExp 10 +IntExp 11 + +IntExp 12 + +__HCR_INT_13: + cli + + push rax + + mov rcx, rsp + call idt_handle_gpf + + pop rax + + sti + iretq + +__HCR_INT_14: + cli + + push rax + + mov rcx, rsp + call idt_handle_pf + + pop rax + + sti + iretq + +IntNormal 15 +IntNormal 16 +IntExp 17 +IntNormal 18 +IntNormal 19 +IntNormal 20 +IntNormal 21 +IntNormal 22 +IntNormal 23 +IntNormal 24 +IntNormal 25 +IntNormal 26 +IntNormal 27 +IntNormal 28 +IntNormal 29 +IntExp 30 + +IntNormal 31 + +IntNormal 32 + +IntNormal 33 + +IntNormal 34 +IntNormal 35 +IntNormal 36 +IntNormal 37 +IntNormal 38 +IntNormal 39 +IntNormal 40 +IntNormal 41 +IntNormal 42 +IntNormal 43 + +__HCR_INT_44: + cli + + ;; TODO: CoreEvents dispatch routine. + + push rax + call _hal_handle_mouse + pop rax + + sti + iretq + +IntNormal 45 +IntNormal 46 +IntNormal 47 +IntNormal 48 +IntNormal 49 + +__HCR_INT_50: + cli + + ;; todo handle system calls. + + sti + iretq + +IntNormal 51 +IntNormal 52 +IntNormal 53 +IntNormal 54 +IntNormal 55 +IntNormal 56 +IntNormal 57 +IntNormal 58 +IntNormal 59 +IntNormal 60 + +%assign i 61 +%rep 195 + IntNormal i +%assign i i+1 +%endrep + +;; this one is doing a POST for us. +;; testing interrupts. +_ke_power_on_self_test: + int 0x32 + int 0x32 + int 0x32 + int 0x32 + + ret + +[global hal_load_gdt] + +hal_load_gdt: + lgdt [rcx] + push 0x08 + lea rax, [rel rt_reload_segments] + push rax + retfq +rt_reload_segments: + mov ax, 0x10 + mov ds, ax + mov es, ax + mov fs, ax + mov gs, ax + mov ss, ax + ret + +global hal_load_idt + +hal_load_idt: + lidt [rcx] + sti + ret + +section .data + +kInterruptVectorTable: + %assign i 0 + %rep 256 + dq __HCR_INT_%+i + %assign i i+1 + %endrep diff --git a/Kernel/HALKit/AMD64/HalKernelMain.cxx b/Kernel/HALKit/AMD64/HalKernelMain.cxx new file mode 100644 index 00000000..e2533241 --- /dev/null +++ b/Kernel/HALKit/AMD64/HalKernelMain.cxx @@ -0,0 +1,85 @@ +/* ------------------------------------------- + + Copyright SoftwareLabs + +------------------------------------------- */ + +#include <ArchKit/ArchKit.hpp> +#include <Builtins/Toolbox/Toolbox.hxx> +#include <FirmwareKit/Handover.hxx> +#include <KernelKit/FileManager.hpp> +#include <KernelKit/Framebuffer.hpp> +#include <KernelKit/KernelHeap.hpp> +#include <KernelKit/PEFCodeManager.hxx> +#include <KernelKit/ProcessScheduler.hpp> +#include <KernelKit/UserHeap.hpp> +#include <NewKit/Json.hpp> + +EXTERN_C NewOS::VoidPtr kInterruptVectorTable[]; +EXTERN_C void AppMain(); + +namespace NewOS::HAL +{ + /// @brief Gets the system cores using the MADT. + /// @param rsdPtr the RSD PTR. + extern void hal_system_get_cores(NewOS::voidPtr rsdPtr); +} // namespace NewOS::HAL + +EXTERN_C void hal_init_platform( + NewOS::HEL::HandoverInformationHeader* HandoverHeader) +{ + kHandoverHeader = HandoverHeader; + + if (kHandoverHeader->f_Magic != kHandoverMagic && + kHandoverHeader->f_Version != kHandoverVersion) + { + return; + } + + /// Setup kernel globals. + kKernelVirtualSize = HandoverHeader->f_VirtualSize; + kKernelVirtualStart = reinterpret_cast<NewOS::VoidPtr>( + reinterpret_cast<NewOS::UIntPtr>(HandoverHeader->f_VirtualStart) + kVirtualAddressStartOffset); + + kKernelPhysicalStart = HandoverHeader->f_PhysicalStart; + + STATIC NewOS::HAL::Detail::NewOSGDT GDT = { + {0, 0, 0, 0x00, 0x00, 0}, // null entry + {0, 0, 0, 0x9a, 0xaf, 0}, // kernel code + {0, 0, 0, 0x92, 0xaf, 0}, // kernel data + {0, 0, 0, 0x00, 0x00, 0}, // null entry + {0, 0, 0, 0x9a, 0xaf, 0}, // user code + {0, 0, 0, 0x92, 0xaf, 0}, // user data + }; + + NewOS::HAL::RegisterGDT gdtBase; + + gdtBase.Base = reinterpret_cast<NewOS::UIntPtr>(&GDT); + gdtBase.Limit = sizeof(NewOS::HAL::Detail::NewOSGDT) - 1; + + /// Load GDT. + + NewOS::HAL::GDTLoader gdt; + gdt.Load(gdtBase); + + /// Load IDT. + + NewOS::HAL::Register64 idtBase; + idtBase.Base = (NewOS::UIntPtr)kInterruptVectorTable; + idtBase.Limit = 0; + + NewOS::HAL::IDTLoader idt; + idt.Load(idtBase); + + /// START POST + + NewOS::HAL::Detail::_ke_power_on_self_test(); + + NewOS::HAL::hal_system_get_cores(kHandoverHeader->f_HardwareTables.f_RsdPtr); + + /// END POST + + AppMain(); + + NewOS::ke_stop(RUNTIME_CHECK_BOOTSTRAP); +} diff --git a/Kernel/HALKit/AMD64/HalKernelMouse.cxx b/Kernel/HALKit/AMD64/HalKernelMouse.cxx new file mode 100644 index 00000000..926a9d5a --- /dev/null +++ b/Kernel/HALKit/AMD64/HalKernelMouse.cxx @@ -0,0 +1,190 @@ +/* ------------------------------------------- + + Copyright SoftwareLabs + +------------------------------------------- */ + +#include <Builtins/PS2/PS2MouseInterface.hxx> +#include <Builtins/Toolbox/Toolbox.hxx> +#include <Builtins/Toolbox/Rsrc/Cursor.rsrc> +#include <KernelKit/Framebuffer.hpp> +#include <NewKit/Defines.hpp> + +// forward decl. +EXTERN_C NewOS::Boolean _hal_draw_mouse(); +EXTERN_C NewOS::Void _hal_init_mouse(); + +STATIC NewOS::Int32 kPrevX = 10; +STATIC NewOS::Int32 kPrevY = 10; +STATIC NewOS::Int32 kX = 10; +STATIC NewOS::Int32 kY = 10; +STATIC NewOS::Int32 kMouseCycle = 0; +STATIC NewOS::PS2MouseInterface kMousePS2; +STATIC NewOS::Char kMousePacket[4] = {}; +STATIC NewOS::Boolean kMousePacketReady = false; + +STATIC ToolboxInitRsrc(); + +#define kPS2Leftbutton 0b00000001 +#define kPS2Middlebutton 0b00000010 +#define kPS2Rightbutton 0b00000100 +#define kPS2XSign 0b00010000 +#define kPS2YSign 0b00100000 +#define kPS2XOverflow 0b01000000 +#define kPS2YOverflow 0b10000000 + +using namespace NewOS; + +Void hal_handle_mouse() +{ + NewOS::UInt8 data = HAL::In8(0x60); + + switch (kMouseCycle) + { + case 0: + if (kMousePacketReady) + break; + if ((data & 0b00001000) == 0) + break; + kMousePacket[0] = data; + kMouseCycle++; + break; + case 1: + if (kMousePacketReady) + break; + kMousePacket[1] = data; + kMouseCycle++; + break; + case 2: + if (kMousePacketReady) + break; + kMousePacket[2] = data; + kMousePacketReady = true; + kMouseCycle = 0; + break; + } + + // Notify PIC controller that we're done with it's interrupt. + + NewOS::HAL::Out8(0x20, 0x20); + NewOS::HAL::Out8(0xA0, 0x20); +} + +/// @brief Interrupt handler for the mouse. +EXTERN_C Void _hal_handle_mouse() +{ + hal_handle_mouse(); +} + +EXTERN_C Boolean _hal_left_button_pressed() +{ + return kMousePacket[0] & kPS2Leftbutton; +} +EXTERN_C Boolean _hal_right_button_pressed() +{ + return kMousePacket[0] & kPS2Rightbutton; +} +EXTERN_C Boolean _hal_middle_button_pressed() +{ + return kMousePacket[0] & kPS2Middlebutton; +} + +/// @brief Draws the kernel's mouse. +EXTERN_C Boolean _hal_draw_mouse() +{ + if (!kMousePacketReady) + return false; + + bool xNegative, yNegative, xOverflow, yOverflow; + + if (kMousePacket[0] & kPS2XSign) + { + xNegative = true; + } + else + xNegative = false; + + if (kMousePacket[0] & kPS2YSign) + { + yNegative = true; + } + else + yNegative = false; + + if (kMousePacket[0] & kPS2XOverflow) + { + xOverflow = true; + } + else + xOverflow = false; + + if (kMousePacket[0] & kPS2YOverflow) + { + yOverflow = true; + } + else + yOverflow = false; + + if (!xNegative) + { + kX += kMousePacket[1]; + if (xOverflow) + { + kX += 255; + } + } + else + { + kMousePacket[1] = 256 - kMousePacket[1]; + kX -= kMousePacket[1]; + if (xOverflow) + { + kX -= 255; + } + } + + if (!yNegative) + { + kY -= kMousePacket[2]; + if (yOverflow) + { + kY -= 255; + } + } + else + { + kMousePacket[2] = 256 - kMousePacket[2]; + kY += kMousePacket[2]; + if (yOverflow) + { + kY += 255; + } + } + + if (kX < 0) + kX = 0; + if (kX > kHandoverHeader->f_GOP.f_Width - 8) + kX = kHandoverHeader->f_GOP.f_Width - 8; + + if (kY < 0) + kY = 0; + if (kY > kHandoverHeader->f_GOP.f_Height - 16) + kY = kHandoverHeader->f_GOP.f_Height - 16; + + /// Draw mouse here. + + kPrevX = kX; + kPrevY = kY; + + kMousePacketReady = false; + return true; +} + +/// @brief Init kernel mouse. +EXTERN_C Void _hal_init_mouse() +{ + kMousePS2.Init(); + + HAL::Out8(0x21, 0b11111001); + HAL::Out8(0xA1, 0b11101111); +} diff --git a/Kernel/HALKit/AMD64/HalNewBoot.asm b/Kernel/HALKit/AMD64/HalNewBoot.asm new file mode 100644 index 00000000..7c60d363 --- /dev/null +++ b/Kernel/HALKit/AMD64/HalNewBoot.asm @@ -0,0 +1,41 @@ +;; /* +;; * ======================================================== +;; * +;; * NewOS +;; * Copyright SoftwareLabs, all rights reserved. +;; * +;; * ======================================================== +;; */ + +[bits 64] + +;; Global symbol of this unit +[global MainLong] +[global MainUnsupported] + +%define kTypeKernel 100 +%define kArchAmd64 122 +%define kHandoverMagic 0xBADCC + +section .NewBoot + +HandoverMagic: dq kHandoverMagic +HandoverType: dw kTypeKernel +HandoverArch: dw kArchAmd64 +;; This NewBootStart points to Main. +HandoverStart: dq __ImageStart + +section .text + +global __ImageStart +global __NewBootJumpProc + +extern hal_init_platform + +;; Just a simple setup, we'd also need to tell some before +__NewBootJumpProc: +__ImageStart: + push rcx + call hal_init_platform + pop rcx + ret diff --git a/Kernel/HALKit/AMD64/HalPageAlloc.cpp b/Kernel/HALKit/AMD64/HalPageAlloc.cpp new file mode 100644 index 00000000..db2aad73 --- /dev/null +++ b/Kernel/HALKit/AMD64/HalPageAlloc.cpp @@ -0,0 +1,103 @@ +/* ------------------------------------------- + + Copyright SoftwareLabs + +------------------------------------------- */ + +#include <ArchKit/ArchKit.hpp> +#include <HALKit/AMD64/HalPageAlloc.hpp> +#include <NewKit/Defines.hpp> +#include <NewKit/KernelCheck.hpp> + +STATIC NewOS::Boolean kAllocationInProgress = false; + +namespace NewOS +{ + namespace HAL + { + namespace Detail + { + struct VirtualMemoryHeader + { + UInt32 Magic; + Boolean Present; + Boolean ReadWrite; + Boolean User; + SizeT PageSize; + }; + + struct VirtualMemoryHeaderTraits + { + /// @brief Get next header. + /// @param current + /// @return + VirtualMemoryHeader* Next(VirtualMemoryHeader* current) + { + return current + sizeof(PTE) + current->PageSize; + } + + /// @brief Get previous header. + /// @param current + /// @return + VirtualMemoryHeader* Prev(VirtualMemoryHeader* current) + { + return current - sizeof(PTE) - current->PageSize; + } + }; + } // namespace Detail + + /// @brief Allocates a new page of memory. + /// @param sz the size of it. + /// @param rw read/write flag. + /// @param user user flag. + /// @return the page table of it. + STATIC auto hal_try_alloc_new_page(Boolean rw, Boolean user, SizeT size) -> VoidPtr + { + if (kAllocationInProgress) + return nullptr; + + kAllocationInProgress = true; + + constexpr auto cVMTMagic = 0xDEEFD00D; + + ///! fetch from the start. + Detail::VirtualMemoryHeader* vmHeader = reinterpret_cast<Detail::VirtualMemoryHeader*>(kKernelVirtualStart); + Detail::VirtualMemoryHeaderTraits traits; + + while (vmHeader->Present && + vmHeader->Magic != cVMTMagic) + { + vmHeader = traits.Next(vmHeader); + } + + vmHeader->Magic = cVMTMagic; + vmHeader->Present = true; + vmHeader->ReadWrite = rw; + vmHeader->User = user; + vmHeader->PageSize = size; + + kAllocationInProgress = false; + + return reinterpret_cast<VoidPtr>(vmHeader); + } + + /// @brief Allocate a new page to be used by the OS. + /// @param rw read/write bit. + /// @param user user bit. + /// @return + auto hal_alloc_page(Boolean rw, Boolean user, SizeT size) -> VoidPtr + { + /// Wait for a ongoing allocation to complete. + while (kAllocationInProgress) + { + ; + } + + if (size == 0) + ++size; + + /// allocate new page. + return hal_try_alloc_new_page(rw, user, size); + } + } // namespace HAL +} // namespace NewOS diff --git a/Kernel/HALKit/AMD64/HalPageAlloc.hpp b/Kernel/HALKit/AMD64/HalPageAlloc.hpp new file mode 100644 index 00000000..2831c87a --- /dev/null +++ b/Kernel/HALKit/AMD64/HalPageAlloc.hpp @@ -0,0 +1,88 @@ +/* ------------------------------------------- + + Copyright SoftwareLabs + +------------------------------------------- */ + +#pragma once + +/** --------------------------------------------------- + + * THIS FILE CONTAINS CODE FOR X86_64 PAGING. + +------------------------------------------------------- */ + +#include <NewKit/Defines.hpp> + +#ifndef kPTEMax +#define kPTEMax (0x200) +#endif //! kPTEMax + +#ifndef kPTEAlign +#define kPTEAlign (0x1000) +#endif //! kPTEAlign + +#ifndef kPTESize +#define kPTESize (0x1000) +#endif // !kPTESize + +EXTERN_C void hal_flush_tlb(); +EXTERN_C void hal_write_cr3(NewOS::UIntPtr pde); +EXTERN_C void hal_write_cr0(NewOS::UIntPtr bit); + +EXTERN_C NewOS::UIntPtr hal_read_cr0(); // @brief CPU control register. +EXTERN_C NewOS::UIntPtr hal_read_cr2(); // @brief Fault address. +EXTERN_C NewOS::UIntPtr hal_read_cr3(); // @brief Page table. + +namespace NewOS::HAL +{ + struct PACKED PageTable64 final + { + bool Present : 1; + bool Rw : 1; + bool User : 1; + bool Wt : 1; + bool Cache : 1; + bool Accessed : 1; + NewOS::Int32 Reserved : 6; + NewOS::UIntPtr PhysicalAddress : 36; + NewOS::Int32 Reserved1 : 15; + bool ExecDisable : 1; + }; + + namespace Detail + { + enum class ControlRegisterBits + { + ProtectedModeEnable = 0, + MonitorCoProcessor = 1, + Emulation = 2, + TaskSwitched = 3, + ExtensionType = 4, + NumericError = 5, + WriteProtect = 16, + AlignementMask = 18, + NotWriteThrough = 29, + CacheDisable = 30, + PageEnable = 31, + }; + + inline UInt8 control_register_cast(ControlRegisterBits reg) + { + return static_cast<UInt8>(reg); + } + } // namespace Detail + + struct PageDirectory64 final + { + PageTable64 ALIGN(kPTEAlign) Pte[kPTEMax]; + }; + + VoidPtr hal_alloc_page(Boolean rw, Boolean user, SizeT size); +} // namespace NewOS::HAL + +namespace NewOS +{ + typedef HAL::PageTable64 PTE; + typedef HAL::PageDirectory64 PDE; +} // namespace NewOS diff --git a/Kernel/HALKit/AMD64/HalProcessor.cpp b/Kernel/HALKit/AMD64/HalProcessor.cpp new file mode 100644 index 00000000..31cee72c --- /dev/null +++ b/Kernel/HALKit/AMD64/HalProcessor.cpp @@ -0,0 +1,97 @@ +/* ------------------------------------------- + + Copyright SoftwareLabs + +------------------------------------------- */ + +#include <HALKit/AMD64/Processor.hpp> + +/** + * @file Processor.cpp + * @brief This file is about processor specific functions (in/out/cli/std...) + */ + +namespace NewOS::HAL +{ + void Out8(UInt16 port, UInt8 value) + { + asm volatile("outb %%al, %1" + : + : "a"(value), "Nd"(port) + : "memory"); + } + + void Out16(UInt16 port, UInt16 value) + { + asm volatile("outw %%ax, %1" + : + : "a"(value), "Nd"(port) + : "memory"); + } + + void Out32(UInt16 port, UInt32 value) + { + asm volatile("outl %%eax, %1" + : + : "a"(value), "Nd"(port) + : "memory"); + } + + UInt8 In8(UInt16 port) + { + UInt8 value = 0UL; + asm volatile("inb %1, %%al" + : "=a"(value) + : "Nd"(port) + : "memory"); + + return value; + } + + UInt16 In16(UInt16 port) + { + UInt16 value = 0UL; + asm volatile("inw %1, %%ax" + : "=a"(value) + : "Nd"(port) + : "memory"); + + return value; + } + + UInt32 In32(UInt16 port) + { + UInt32 value = 0UL; + asm volatile("inl %1, %%eax" + : "=a"(value) + : "Nd"(port) + : "memory"); + + return value; + } + + void rt_halt() + { + asm volatile("hlt"); + } + + void rt_cli() + { + asm volatile("cli"); + } + + void rt_sti() + { + asm volatile("sti"); + } + + void rt_cld() + { + asm volatile("cld"); + } + + void rt_std() + { + asm volatile("std"); + } +} // namespace NewOS::HAL diff --git a/Kernel/HALKit/AMD64/HalRoutines.s b/Kernel/HALKit/AMD64/HalRoutines.s new file mode 100644 index 00000000..e4944111 --- /dev/null +++ b/Kernel/HALKit/AMD64/HalRoutines.s @@ -0,0 +1,12 @@ +.globl hal_load_idt +.globl hal_load_gdt +.globl rt_wait_400ns +.globl rt_get_current_context + +.section .text +rt_wait_400ns: + jmp .loop + .loop: + jmp .loop2 + .loop2: + ret diff --git a/Kernel/HALKit/AMD64/HalSMPCore.cxx b/Kernel/HALKit/AMD64/HalSMPCore.cxx new file mode 100644 index 00000000..a1310c4e --- /dev/null +++ b/Kernel/HALKit/AMD64/HalSMPCore.cxx @@ -0,0 +1,30 @@ +/* ------------------------------------------- + + Copyright SoftwareLabs + +------------------------------------------- */ + +#include <KernelKit/ProcessScheduler.hpp> + +using namespace NewOS; +Void ProcessHeader::SetEntrypoint(UIntPtr& imageStart) noexcept +{ + if (imageStart == 0) + this->Crash(); + + this->StackFrame->Rbp = imageStart; + this->StackFrame->Rsp = this->StackFrame->Rbp; +} + +namespace NewOS +{ + bool rt_check_stack(HAL::StackFramePtr stackPtr) + { + if (!stackPtr) + return false; + if (stackPtr->Rbp == 0 || stackPtr->Rsp == 0) + return false; + + return true; + } +} // namespace NewOS diff --git a/Kernel/HALKit/AMD64/HalSMPCoreManager.asm b/Kernel/HALKit/AMD64/HalSMPCoreManager.asm new file mode 100644 index 00000000..18f80398 --- /dev/null +++ b/Kernel/HALKit/AMD64/HalSMPCoreManager.asm @@ -0,0 +1,26 @@ +;; /* +;; * ======================================================== +;; * +;; * NewOS +;; * Copyright SoftwareLabs, all rights reserved. +;; * +;; * ======================================================== +;; */ + +[bits 64] + +[global rt_get_current_context] +[global rt_do_context_switch] + +section .text + +;; writes to rdx the stackframe inside rcx. +;; rcx: Stack Pointer +;; rdx: SMP core address. +rt_do_context_switch: + + retfq + +;; gets the current stack frame. +rt_get_current_context: + retfq diff --git a/Kernel/HALKit/AMD64/Hypervisor.hpp b/Kernel/HALKit/AMD64/Hypervisor.hpp new file mode 100644 index 00000000..9beaae42 --- /dev/null +++ b/Kernel/HALKit/AMD64/Hypervisor.hpp @@ -0,0 +1,26 @@ +/* ------------------------------------------- + + Copyright SoftwareLabs + +------------------------------------------- */ + +#pragma once + +#include <NewKit/Defines.hpp> + +namespace NewOS +{ + MAKE_STRING_ENUM(HYPERVISOR) + ENUM_STRING(Qemu, "TCGTCGTCGTCG"); + ENUM_STRING(KVM, " KVMKVMKVM "); + ENUM_STRING(VMWare, "VMwareVMware"); + ENUM_STRING(VirtualBox, "VBoxVBoxVBox"); + ENUM_STRING(Xen, "XenVMMXenVMM"); + ENUM_STRING(Microsoft, "Microsoft Hv"); + ENUM_STRING(Parallels, " prl hyperv "); + ENUM_STRING(ParallelsAlt, " lrpepyh vr "); + ENUM_STRING(Bhyve, "bhyve bhyve "); + ENUM_STRING(Qnx, " QNXQVMBSQG "); + + END_STRING_ENUM() +} // namespace NewOS diff --git a/Kernel/HALKit/AMD64/MBCI/.gitkeep b/Kernel/HALKit/AMD64/MBCI/.gitkeep new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/Kernel/HALKit/AMD64/MBCI/.gitkeep diff --git a/Kernel/HALKit/AMD64/PCI/Database.cxx b/Kernel/HALKit/AMD64/PCI/Database.cxx new file mode 100644 index 00000000..1c2628d0 --- /dev/null +++ b/Kernel/HALKit/AMD64/PCI/Database.cxx @@ -0,0 +1,11 @@ +/* ------------------------------------------- + + Copyright SoftwareLabs + +------------------------------------------- */ + +#include <KernelKit/PCI/Database.hpp> + +namespace NewOS +{ +} diff --git a/Kernel/HALKit/AMD64/PCI/Device.cxx b/Kernel/HALKit/AMD64/PCI/Device.cxx new file mode 100644 index 00000000..6f2265ae --- /dev/null +++ b/Kernel/HALKit/AMD64/PCI/Device.cxx @@ -0,0 +1,130 @@ +/* ------------------------------------------- + + Copyright SoftwareLabs + +------------------------------------------- */ + +#include <ArchKit/ArchKit.hpp> +#include <KernelKit/PCI/Device.hpp> + +NewOS::UInt NewOSPCIReadRaw(NewOS::UInt bar, NewOS::UShort bus, NewOS::UShort dev, NewOS::UShort fun) +{ + NewOS::UInt target = 0x80000000 | ((NewOS::UInt)bus << 16) | + ((NewOS::UInt)dev << 11) | ((NewOS::UInt)fun << 8) | + (bar & 0xFC); + + NewOS::HAL::Out32((NewOS::UShort)NewOS::PCI::PciConfigKind::ConfigAddress, + target); + + return NewOS::HAL::In32((NewOS::UShort)NewOS::PCI::PciConfigKind::ConfigData); +} + +void NewOSPCISetCfgTarget(NewOS::UInt bar, NewOS::UShort bus, NewOS::UShort dev, NewOS::UShort fun) +{ + NewOS::UInt target = 0x80000000 | ((NewOS::UInt)bus << 16) | + ((NewOS::UInt)dev << 11) | ((NewOS::UInt)fun << 8) | + (bar & ~3); + + NewOS::HAL::Out32((NewOS::UShort)NewOS::PCI::PciConfigKind::ConfigAddress, + target); +} + +namespace NewOS::PCI +{ + Device::Device(UShort bus, UShort device, UShort func, UShort bar) + : fBus(bus), fDevice(device), fFunction(func), fBar(bar) + { + } + + Device::~Device() + { + } + + UInt Device::Read(UInt bar, Size sz) + { + NewOSPCISetCfgTarget(bar, fBus, fDevice, fFunction); + + if (sz == 4) + return HAL::In32((UShort)PciConfigKind::ConfigData + (fBar & 3)); + if (sz == 2) + return HAL::In16((UShort)PciConfigKind::ConfigData + (fBar & 3)); + if (sz == 1) + return HAL::In8((UShort)PciConfigKind::ConfigData + (fBar & 3)); + + return 0xFFFF; + } + + void Device::Write(UInt bar, UIntPtr data, Size sz) + { + NewOSPCISetCfgTarget(bar, fBus, fDevice, fFunction); + + if (sz == 4) + HAL::Out32((UShort)PciConfigKind::ConfigData + (fBar & 3), (UInt)data); + if (sz == 2) + HAL::Out16((UShort)PciConfigKind::ConfigData + (fBar & 3), (UShort)data); + if (sz == 1) + HAL::Out8((UShort)PciConfigKind::ConfigData + (fBar & 3), (UChar)data); + } + + UShort Device::DeviceId() + { + return (UShort)(NewOSPCIReadRaw(0x0 >> 16, fBus, fDevice, fFunction)); + } + + UShort Device::VendorId() + { + return (UShort)(NewOSPCIReadRaw(0x0, fBus, fDevice, fFunction) >> 16); + } + + UShort Device::InterfaceId() + { + return (UShort)(NewOSPCIReadRaw(0x0, fBus, fDevice, fFunction) >> 16); + } + + UChar Device::Class() + { + return (UChar)(NewOSPCIReadRaw(0x08, fBus, fDevice, fFunction) >> 24); + } + + UChar Device::Subclass() + { + return (UChar)(NewOSPCIReadRaw(0x08, fBus, fDevice, fFunction) >> 16); + } + + UChar Device::ProgIf() + { + return (UChar)(NewOSPCIReadRaw(0x08, fBus, fDevice, fFunction) >> 8); + } + + UChar Device::HeaderType() + { + return (UChar)(NewOSPCIReadRaw(0xC, fBus, fDevice, fFunction) >> 16); + } + + void Device::EnableMmio() + { + bool enable = Read(0x04, sizeof(UChar)) | (1 << 1); + Write(0x04, enable, sizeof(UShort)); + } + + void Device::BecomeBusMaster() + { + bool enable = Read(0x04, sizeof(UShort)) | (1 << 2); + Write(0x04, enable, sizeof(UShort)); + } + + UShort Device::Vendor() + { + UShort vendor = VendorId(); + + if (vendor != (UShort)PciConfigKind::Invalid) + fDevice = (UShort)Read(0x0, sizeof(UShort)); + + return fDevice; + } + + Device::operator bool() + { + return VendorId() != (UShort)PciConfigKind::Invalid; + } +} // namespace NewOS::PCI diff --git a/Kernel/HALKit/AMD64/PCI/Dma.cxx b/Kernel/HALKit/AMD64/PCI/Dma.cxx new file mode 100644 index 00000000..aacbafd8 --- /dev/null +++ b/Kernel/HALKit/AMD64/PCI/Dma.cxx @@ -0,0 +1,82 @@ +/* ------------------------------------------- + + Copyright SoftwareLabs + +------------------------------------------- */ + +#include <KernelKit/PCI/Dma.hpp> + +namespace NewOS +{ + DMAWrapper::operator bool() + { + return fAddress; + } + + bool DMAWrapper::operator!() + { + return !fAddress; + } + + Boolean DMAWrapper::Check(UIntPtr offset) const + { + if (!fAddress) + return false; + if (offset == 0) + return true; + + kcout << "[DMAWrapper::IsIn] Checking offset..\n"; + return reinterpret_cast<UIntPtr>(fAddress) >= offset; + } + + bool DMAWrapper::Write(const UIntPtr& bit, const UIntPtr& offset) + { + if (!fAddress) + return false; + + kcout << "[DMAWrapper::Write] Writing at address..\n"; + + auto addr = + (volatile UIntPtr*)(reinterpret_cast<UIntPtr>(fAddress) + offset); + *addr = bit; + + return true; + } + + UIntPtr DMAWrapper::Read(const UIntPtr& offset) + { + kcout << "[DMAWrapper::Read] checking fAddress..\n"; + if (!fAddress) + return 0; + + kcout << "[DMAWrapper::Read] Reading fAddress..\n"; + return *(volatile UIntPtr*)(reinterpret_cast<UIntPtr>(fAddress) + offset); + ; + } + + UIntPtr DMAWrapper::operator[](const UIntPtr& offset) + { + return this->Read(offset); + } + + OwnPtr<IOBuf<Char*>> DMAFactory::Construct(OwnPtr<DMAWrapper>& dma) + { + if (!dma) + return {}; + + OwnPtr<IOBuf<Char*>> dmaOwnPtr = + make_ptr<IOBuf<Char*>, char*>(reinterpret_cast<char*>(dma->fAddress)); + + if (!dmaOwnPtr) + return {}; + + kcout << "Returning the new OwnPtr<IOBuf<Char*>>!\r"; + return dmaOwnPtr; + } + + DMAWrapper& DMAWrapper::operator=(voidPtr Ptr) + { + fAddress = Ptr; + return *this; + } +} // namespace NewOS diff --git a/Kernel/HALKit/AMD64/PCI/Express.cxx b/Kernel/HALKit/AMD64/PCI/Express.cxx new file mode 100644 index 00000000..4fde7ca2 --- /dev/null +++ b/Kernel/HALKit/AMD64/PCI/Express.cxx @@ -0,0 +1,11 @@ +/* ------------------------------------------- + + Copyright SoftwareLabs + +------------------------------------------- */ + +#include <KernelKit/PCI/Express.hpp> + +namespace NewOS +{ +} diff --git a/Kernel/HALKit/AMD64/PCI/IO.cxx b/Kernel/HALKit/AMD64/PCI/IO.cxx new file mode 100644 index 00000000..4bd4db4f --- /dev/null +++ b/Kernel/HALKit/AMD64/PCI/IO.cxx @@ -0,0 +1,7 @@ +/* ------------------------------------------- + + Copyright SoftwareLabs + +------------------------------------------- */ + +#include <KernelKit/PCI/IO.hpp> diff --git a/Kernel/HALKit/AMD64/PCI/Iterator.cxx b/Kernel/HALKit/AMD64/PCI/Iterator.cxx new file mode 100644 index 00000000..e1af15ad --- /dev/null +++ b/Kernel/HALKit/AMD64/PCI/Iterator.cxx @@ -0,0 +1,44 @@ +/* ------------------------------------------- + + Copyright SoftwareLabs + +------------------------------------------- */ + +#include <KernelKit/PCI/Iterator.hpp> + +#define PCI_ITERATOR_FIND_AND_UNWRAP(DEV, SZ) \ + if (DEV.Leak()) \ + return DEV.Leak(); + +namespace NewOS::PCI +{ + Iterator::Iterator(const Types::PciDeviceKind& type) + { + // probe devices. + for (int bus = 0; bus < NEWOS_BUS_COUNT; ++bus) + { + for (int device = 0; device < NEWOS_DEVICE_COUNT; ++device) + { + for (int function = 0; function < NEWOS_FUNCTION_COUNT; ++function) + { + Device dev(bus, device, function, 0); + + if (dev.Class() == (UChar)type) + { + fDevices[bus].Leak().Leak() = dev; + } + } + } + } + } + + Iterator::~Iterator() + { + } + + Ref<PCI::Device> Iterator::operator[](const Size& sz) + { + PCI_ITERATOR_FIND_AND_UNWRAP(fDevices[sz], sz); + return {}; + } +} // namespace NewOS::PCI diff --git a/Kernel/HALKit/AMD64/PCI/PCI.cxx b/Kernel/HALKit/AMD64/PCI/PCI.cxx new file mode 100644 index 00000000..71644f17 --- /dev/null +++ b/Kernel/HALKit/AMD64/PCI/PCI.cxx @@ -0,0 +1,7 @@ +/* ------------------------------------------- + + Copyright SoftwareLabs + +------------------------------------------- */ + +#include <KernelKit/PCI/PCI.hpp> diff --git a/Kernel/HALKit/AMD64/Processor.hpp b/Kernel/HALKit/AMD64/Processor.hpp new file mode 100644 index 00000000..69dc1acb --- /dev/null +++ b/Kernel/HALKit/AMD64/Processor.hpp @@ -0,0 +1,212 @@ +/* ------------------------------------------- + + Copyright SoftwareLabs + + File: Prcoessor.hxx + Purpose: AMD64 processor abstraction. + + Revision History: + + 30/01/24: Added file (amlel) + +------------------------------------------- */ + +#pragma once + +#include <NewKit/Array.hpp> +#include <NewKit/Defines.hpp> +#include <NewKit/Utils.hpp> +#include <FirmwareKit/Handover.hxx> + +#ifdef kCPUBackendName +#undef kCPUBackendName +#endif // ifdef kCPUBackendName + +#define kCPUBackendName "AMD64" + +#define IsActiveLow(FLG) (FLG & 2) +#define IsLevelTriggered(FLG) (FLG & 8) + +#define kInterruptGate (0x8E) +#define kTrapGate (0xEF) +#define kTaskGate (0b10001100) +#define kGdtCodeSelector (0x08) +#define kVirtualAddressStartOffset (0x10000000) + +namespace NewOS +{ + namespace Detail::AMD64 + { + struct PACKED InterruptDescriptorAMD64 final + { + UInt16 OffsetLow; // offset bits 0..15 + UInt16 Selector; // a code segment selector in GDT or LDT + UInt8 + Ist; // bits 0..2 holds Interrupt Stack Table offset, rest of bits zero. + UInt8 TypeAttributes; // gate type, dpl, and p fields + UInt16 OffsetMid; // offset bits 16..31 + UInt32 OffsetHigh; // offset bits 32..63 + UInt32 Zero; // reserved + }; + } // namespace Detail::AMD64 +} // namespace NewOS + +namespace NewOS::HAL +{ + EXTERN_C UChar In8(UInt16 port); + EXTERN_C UShort In16(UInt16 port); + EXTERN_C UInt In32(UInt16 port); + + EXTERN_C void Out16(UShort port, UShort byte); + EXTERN_C void Out8(UShort port, UChar byte); + EXTERN_C void Out32(UShort port, UInt byte); + + EXTERN_C void rt_wait_400ns(); + EXTERN_C void rt_halt(); + EXTERN_C void rt_cli(); + EXTERN_C void rt_sti(); + EXTERN_C void rt_cld(); + EXTERN_C void rt_std(); + + struct PACKED Register64 final + { + UShort Limit; + UIntPtr Base; + }; + + struct PACKED RegisterGDT final + { + UShort Limit; + UIntPtr Base; + }; + + using RawRegister = UInt64; + + using InterruptId = UShort; /* For each element in the IVT */ + using interruptTrap = UIntPtr(UIntPtr sp); + + typedef UIntPtr Reg; + + struct PACKED StackFrame final + { + Reg IntNum, Exception; + Reg Rdi, Rsi, Rbp, Rsp, Rbx, Rdx, Rcx, Rax; + Reg R8, R9, R10, R11, R12, R13, R14, R15; + Reg Gs, Fs; + }; + + typedef StackFrame* StackFramePtr; + + class InterruptDescriptor final + { + public: + UShort Offset; + UShort Selector; + UChar Ist; + UChar Atrributes; + + UShort SecondOffset; + UInt ThirdOffset; + UInt Zero; + + operator bool() + { + return Offset != 0xFFFF; + } + }; + + using InterruptDescriptorArray = Array<InterruptDescriptor, 256>; + + class SegmentDescriptor final + { + public: + UInt16 Base; + UInt8 BaseMiddle; + UInt8 BaseHigh; + + UShort Limit; + UChar Gran; + UChar AccessByte; + }; + + /*** + * @brief Segment Boolean operations + */ + class SegmentDescriptorComparator final + { + public: + bool IsValid(SegmentDescriptor& seg) + { + return seg.Base > seg.Limit; + } + bool Equals(SegmentDescriptor& seg, SegmentDescriptor& segRight) + { + return seg.Base == segRight.Base && seg.Limit == segRight.Limit; + } + }; + + using SegmentArray = Array<SegmentDescriptor, 6>; + + class GDTLoader final + { + public: + static void Load(RegisterGDT& gdt); + static void Load(Ref<RegisterGDT>& gdt); + }; + + class IDTLoader final + { + public: + static void Load(Register64& idt); + static void Load(Ref<Register64>& idt); + }; + + Void hal_system_get_cores(VoidPtr rsdPtr); + + /// @brief Processor specific structures. + namespace Detail + { + EXTERN_C void _ke_power_on_self_test(void); + + /** + @brief Global descriptor table entry, either null, code or data. +*/ + + struct PACKED NewOSGDTRecord final + { + UInt16 Limit0; + UInt16 Base0; + UInt8 Base1; + UInt8 AccessByte; + UInt8 Limit1_Flags; + UInt8 Base2; + }; + + struct PACKED ALIGN(0x1000) NewOSGDT final + { + NewOSGDTRecord Null; + NewOSGDTRecord KernCode; + NewOSGDTRecord KernData; + NewOSGDTRecord UserNull; + NewOSGDTRecord UserCode; + NewOSGDTRecord UserData; + }; + } // namespace Detail +} // namespace NewOS::HAL + +EXTERN_C void idt_handle_generic(NewOS::UIntPtr rsp); +EXTERN_C void idt_handle_gpf(NewOS::UIntPtr rsp); +EXTERN_C void idt_handle_math(NewOS::UIntPtr rsp); +EXTERN_C void idt_handle_pf(NewOS::UIntPtr rsp); + +EXTERN_C void hal_load_idt(NewOS::HAL::Register64 ptr); +EXTERN_C void hal_load_gdt(NewOS::HAL::RegisterGDT ptr); + +/// @brief Maximum size of the IDT. +#define kKernelIdtSize 0x100 +#define kKernelInterruptId 0x32 + +inline NewOS::VoidPtr kKernelVirtualStart = (NewOS::VoidPtr)kVirtualAddressStartOffset; +inline NewOS::UIntPtr kKernelVirtualSize = 0UL; + +inline NewOS::VoidPtr kKernelPhysicalStart = nullptr; diff --git a/Kernel/HALKit/AMD64/Storage/AHCI.cxx b/Kernel/HALKit/AMD64/Storage/AHCI.cxx new file mode 100644 index 00000000..109d9cb9 --- /dev/null +++ b/Kernel/HALKit/AMD64/Storage/AHCI.cxx @@ -0,0 +1,67 @@ +/* ------------------------------------------- + + Copyright SoftwareLabs + +------------------------------------------- */ + +/** + * @file AHCI.cxx + * @author Amlal El Mahrouss (amlalelmahrouss@icloud.com) + * @brief AHCI driver. + * @version 0.1 + * @date 2024-02-02 + * + * @copyright Copyright (c) SoftwareLabs + * + */ + +#include <Builtins/AHCI/AHCI.hxx> +#include <KernelKit/PCI/Iterator.hpp> + +#ifdef __AHCI__ +enum +{ + kSATAProgIfAHCI = 0x01, + kSATASubClass = 0x06 +}; + +static NewOS::PCI::Device kAhciDevice; + +/// @brief Initializes an AHCI disk. +/// @param PortsImplemented the amount of port that have been detected. +/// @return +NewOS::Boolean drv_std_init(NewOS::UInt16& PortsImplemented) +{ + using namespace NewOS; + + PCI::Iterator iterator(Types::PciDeviceKind::MassStorageController); + for (SizeT devIndex = 0; devIndex < NEWOS_BUS_COUNT; ++devIndex) + { + if (iterator[devIndex].Leak().Subclass() == kSATASubClass && + iterator[devIndex].Leak().ProgIf() == kSATAProgIfAHCI) + { + iterator[devIndex].Leak().EnableMmio(); /// enable the memory i/o for this ahci device. + kAhciDevice = iterator[devIndex].Leak(); /// and then leak the reference. + + kcout << "New Kernel: [PCI] Found AHCI controller.\r"; + + return true; + } + } + + return false; +} + +NewOS::Boolean drv_std_detected(NewOS::Void) +{ + return kAhciDevice.DeviceId() != 0xFFFF; +} + +NewOS::Void drv_std_read(NewOS::UInt64 Lba, NewOS::Char* Buf, NewOS::SizeT SectorSz, NewOS::SizeT Size) +{ +} + +NewOS::Void drv_std_write(NewOS::UInt64 Lba, NewOS::Char* Buf, NewOS::SizeT SectorSz, NewOS::SizeT Size) +{ +} +#endif // __AHCI__ diff --git a/Kernel/HALKit/AMD64/Storage/ATA-DMA.cxx b/Kernel/HALKit/AMD64/Storage/ATA-DMA.cxx new file mode 100644 index 00000000..97812bd8 --- /dev/null +++ b/Kernel/HALKit/AMD64/Storage/ATA-DMA.cxx @@ -0,0 +1,38 @@ +/* ------------------------------------------- + + Copyright SoftwareLabs + +------------------------------------------- */ + +/** + * @file ATA-DMA.cxx + * @author Amlal El Mahrouss (amlalelmahrouss@icloud.com) + * @brief ATA driver (DMA mode). + * @version 0.1 + * @date 2024-02-02 + * + * @copyright Copyright (c) SoftwareLabs + * + */ + +#include <StorageKit/PRDT.hpp> + +#include <Builtins/ATA/ATA.hxx> +#include <ArchKit/ArchKit.hpp> + +using namespace NewOS; + +EXTERN_C Int32 kPRDTTransferStatus; +STATIC PRDT kPRDT; + +#ifdef __ATA_DMA__ + +#ifdef __ATA_PIO__ +#error You cant have both PIO and DMA enabled! +#endif /* ifdef __ATA_PIO__ */ + +#ifdef __AHCI__ +#error You cant have both ATA and AHCI enabled! +#endif /* ifdef __AHCI__ */ + +#endif /* ifdef __ATA_DMA__ */ diff --git a/Kernel/HALKit/AMD64/Storage/ATA-PIO.cxx b/Kernel/HALKit/AMD64/Storage/ATA-PIO.cxx new file mode 100644 index 00000000..d09d9a67 --- /dev/null +++ b/Kernel/HALKit/AMD64/Storage/ATA-PIO.cxx @@ -0,0 +1,192 @@ +/* ------------------------------------------- + + Copyright SoftwareLabs + +------------------------------------------- */ + +/** + * @file ATA-PIO.cxx + * @author Amlal El Mahrouss (amlalelmahrouss@icloud.com) + * @brief ATA driver (PIO mode). + * @version 0.1 + * @date 2024-02-02 + * + * @copyright Copyright (c) SoftwareLabs + * + */ + +#include <Builtins/ATA/ATA.hxx> +#include <ArchKit/ArchKit.hpp> + +#ifdef __ATA_PIO__ + +using namespace NewOS; +using namespace NewOS::HAL; + +/// bugs: 0 + +#define kATADataLen 256 + +static Boolean kATADetected = false; +static Int32 kATADeviceType = kATADeviceCount; +static Char kATAData[kATADataLen] = {0}; + +Boolean drv_std_wait_io(UInt16 IO) +{ + for (int i = 0; i < 4; i++) + In8(IO + ATA_REG_STATUS); + +ATAWaitForIO_Retry: + auto statRdy = In8(IO + ATA_REG_STATUS); + + if ((statRdy & ATA_SR_BSY)) + goto ATAWaitForIO_Retry; + +ATAWaitForIO_Retry2: + statRdy = In8(IO + ATA_REG_STATUS); + + if (statRdy & ATA_SR_ERR) + return false; + + if (!(statRdy & ATA_SR_DRDY)) + goto ATAWaitForIO_Retry2; + + return true; +} + +Void drv_std_select(UInt16 Bus) +{ + if (Bus == ATA_PRIMARY_IO) + Out8(Bus + ATA_REG_HDDEVSEL, ATA_PRIMARY_SEL); + else + Out8(Bus + ATA_REG_HDDEVSEL, ATA_SECONDARY_SEL); +} + +Boolean drv_std_init(UInt16 Bus, UInt8 Drive, UInt16& OutBus, UInt8& OutMaster) +{ + if (drv_std_detected()) + return true; + + UInt16 IO = Bus; + + drv_std_select(IO); + + // Bus init, NEIN bit. + Out8(IO + ATA_REG_NEIN, 1); + + // identify until it's good. +ATAInit_Retry: + auto statRdy = In8(IO + ATA_REG_STATUS); + + if (statRdy & ATA_SR_ERR) + { + return false; + } + + if ((statRdy & ATA_SR_BSY)) + goto ATAInit_Retry; + + Out8(IO + ATA_REG_COMMAND, ATA_CMD_IDENTIFY); + + /// fetch serial info + /// model, speed, number of sectors... + + drv_std_wait_io(IO); + + for (SizeT indexData = 0ul; indexData < kATADataLen; ++indexData) + { + kATAData[indexData] = In16(IO + ATA_REG_DATA); + } + + OutBus = (Bus == ATA_PRIMARY_IO) ? ATA_PRIMARY_IO : ATA_SECONDARY_IO; + + OutMaster = (Bus == ATA_PRIMARY_IO) ? ATA_MASTER : ATA_SLAVE; + + return true; +} + +Void drv_std_read(UInt64 Lba, UInt16 IO, UInt8 Master, Char* Buf, SizeT SectorSz, SizeT Size) +{ + UInt8 Command = ((!Master) ? 0xE0 : 0xF0); + + Lba /= SectorSz; + + drv_std_wait_io(IO); + drv_std_select(IO); + + Out8(IO + ATA_REG_HDDEVSEL, (Command) | (((Lba) >> 24) & 0x0F)); + + /// Compute sector count. + Out8(IO + ATA_REG_SEC_COUNT0, SectorSz / (SectorSz / 2)); + + Out8(IO + ATA_REG_LBA0, (Lba)); + Out8(IO + ATA_REG_LBA1, (Lba) >> 8); + Out8(IO + ATA_REG_LBA2, (Lba) >> 16); + + Out8(IO + ATA_REG_COMMAND, ATA_CMD_READ_PIO); + + drv_std_wait_io(IO); + + for (SizeT IndexOff = 0; IndexOff < Size; ++IndexOff) + { + drv_std_wait_io(IO); + Buf[IndexOff] = In16(IO + ATA_REG_DATA); + drv_std_wait_io(IO); + } + + drv_std_wait_io(IO); +} + +Void drv_std_write(UInt64 Lba, UInt16 IO, UInt8 Master, Char* Buf, SizeT SectorSz, SizeT Size) +{ + UInt8 Command = ((!Master) ? 0xE0 : 0xF0); + + Lba /= SectorSz; + + drv_std_wait_io(IO); + drv_std_select(IO); + + /// Compute sector count. + Out8(IO + ATA_REG_HDDEVSEL, (Command) | (((Lba) >> 24) & 0x0F)); + + Out8(IO + ATA_REG_SEC_COUNT0, SectorSz / (SectorSz / 2)); + + Out8(IO + ATA_REG_LBA0, (Lba)); + Out8(IO + ATA_REG_LBA1, (Lba) >> 8); + Out8(IO + ATA_REG_LBA2, (Lba) >> 16); + + Out8(IO + ATA_REG_COMMAND, ATA_CMD_WRITE_PIO); + + drv_std_wait_io(IO); + + for (SizeT IndexOff = 0; IndexOff < Size; ++IndexOff) + { + drv_std_wait_io(IO); + Out16(IO + ATA_REG_DATA, Buf[IndexOff]); + drv_std_wait_io(IO); + } + + drv_std_wait_io(IO); +} + +/// @brief is ATA detected? +Boolean drv_std_detected(Void) +{ + return kATADetected; +} + +/*** + @brief Getter, gets the number of sectors inside the drive. +*/ +NewOS::SizeT drv_std_get_sector_count() +{ + return (kATAData[61] << 16) | kATAData[60]; +} + +/// @brief Get the drive size. +NewOS::SizeT drv_std_get_drv_size() +{ + return drv_std_get_sector_count() * kATASectorSize; +} + +#endif /* ifdef __ATA_PIO__ */ |
