diff --git a/.github/workflows/kernel-build.yml b/.github/workflows/kernel-build.yml index e29d091..bb1a811 100644 --- a/.github/workflows/kernel-build.yml +++ b/.github/workflows/kernel-build.yml @@ -15,6 +15,7 @@ jobs: steps: - name: Checkout sources uses: actions/checkout@v4 + with: { fetch-depth: 0 } - name: Install LLVM and Clang uses: KyleMayes/install-llvm-action@v2 diff --git a/.github/workflows/release-riscv64_pine64_star64.yml b/.github/workflows/release-riscv64_pine64_star64.yml index 9ac792b..f228b03 100644 --- a/.github/workflows/release-riscv64_pine64_star64.yml +++ b/.github/workflows/release-riscv64_pine64_star64.yml @@ -42,7 +42,6 @@ jobs: run: | make -C u-boot starfive_visionfive2_defconfig make -C u-boot -j$(nproc) spl/u-boot-spl.bin - make -C u-boot -j$(nproc) dtbs - name: Pack SPL image with StarFive spl_tool run: | diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index b99f1f7..b768835 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -101,4 +101,4 @@ jobs: Changes since `${{ steps.version.outputs.last }}`: ${{ steps.notes.outputs.notes }} - files: ${{ steps.collect.outputs.list }} + files: ${{ steps.renamed.outputs.list }} diff --git a/src/Common/Memory.h b/src/Common/Memory.h index db19655..6205cef 100644 --- a/src/Common/Memory.h +++ b/src/Common/Memory.h @@ -11,12 +11,12 @@ typedef struct Span##name { type* Pointer; size_t Length; } Span##name; \ typedef struct ReadOnlySpan##name { const type* Pointer; size_t Length; } ReadOnlySpan##name; \ \ - static inline Span##name MakeSpan##name(type* pointer, size_t length) \ + static inline Span##name CreateSpan##name(type* pointer, size_t length) \ { \ return (Span##name) { .Pointer = pointer, .Length = length }; \ } \ \ - static inline ReadOnlySpan##name MakeReadOnlySpan##name(const type* pointer, size_t length) \ + static inline ReadOnlySpan##name CreateReadOnlySpan##name(const type* pointer, size_t length) \ { \ return (ReadOnlySpan##name) { .Pointer = pointer, .Length = length }; \ } \ @@ -30,7 +30,7 @@ (__extension__ ({ \ static_assert((length) >= 0, "StackAlloc: length must be an integer-constant expression"); \ type array[(length)]; \ - MakeSpan##name(array, (size_t)(length)); \ + CreateSpan##name(array, (size_t)(length)); \ })) DefineSpan(Char, char) diff --git a/src/Common/String.c b/src/Common/String.c index 1f09819..0fb4f1b 100644 --- a/src/Common/String.c +++ b/src/Common/String.c @@ -2,7 +2,7 @@ ReadOnlySpanChar String(const char* string) { - return MakeReadOnlySpanChar(string, __builtin_strlen(string)); + return CreateReadOnlySpanChar(string, __builtin_strlen(string)); } bool StringEquals(ReadOnlySpanChar string1, ReadOnlySpanChar string2) diff --git a/src/Common/Types.h b/src/Common/Types.h index b939e47..b0f9edd 100644 --- a/src/Common/Types.h +++ b/src/Common/Types.h @@ -23,6 +23,14 @@ static_assert(sizeof(uintptr_t) == sizeof(void *), "uintptr_t is not pointer-siz #define PLATFORM_ARCHITECTURE_BITS (__SIZEOF_POINTER__ * 8) +typedef enum +{ + ByteOrder_LittleEndian = __ORDER_LITTLE_ENDIAN__, + ByteOrder_BigEndian = __ORDER_BIG_ENDIAN__ +} ByteOrder; + +#define PLATFORM_BYTE_ORDER __BYTE_ORDER__ + #define va_list __builtin_va_list #define va_start __builtin_va_start #define va_end __builtin_va_end diff --git a/src/Kernel/KernelMain.c b/src/Kernel/KernelMain.c index 452f3fb..64ffc7c 100644 --- a/src/Kernel/KernelMain.c +++ b/src/Kernel/KernelMain.c @@ -25,7 +25,7 @@ void KernelTrapHandler(CpuTrapFrame* trapFrame) CpuClearPendingInterrupts(CpuInterruptType_Timer); //CpuDisableInterrupts(CpuInterruptType_Timer); //SbiSetTimer((uint64_t)-1); - BiosSetTimer(CpuReadTime() + 10000000); + BiosSetTimer(CpuReadTime() + 10'000'000); auto programCounter = CpuTrapFrameGetProgramCounter(trapFrame); KernelConsolePrint(String("Kernel trap handler: %l (PC=%x).\n"), CpuReadTime(), programCounter); @@ -48,6 +48,10 @@ void KernelTrapHandler(CpuTrapFrame* trapFrame) errorName = String("Address error"); break; + case CpuTrapSynchronousType_Debug: + errorName = String("Debug not implemented"); + break; + case CpuTrapSynchronousType_PageError: errorName = String("Page error"); break; @@ -82,13 +86,22 @@ void KernelMain() KernelConsolePrint(String("(%s %d-bit)\n\n"), platformInformation.Name.Pointer, platformInformation.ArchitectureBits); KernelConsoleResetStyle(); + KernelConsolePrint(String("Boot Cpu ID: %d\n"), platformInformation.BootCpuId); + + auto platformDevices = PlatformGetDevices(); + + + BiosSetTimer(CpuReadTime() + 10'000'000); CpuSetTrapHandler(KernelTrapHandler); - BiosSetTimer(CpuReadTime() + 10000000); + + // TODO: Test Timer only when the hardware is running fine CpuEnableInterrupts(CpuInterruptType_Timer); while (true) { - CpuGenerateInvalidInstruction(); + KernelConsolePrint(String("WFI\n")); + + //CpuGenerateInvalidInstruction(); CpuWaitForInterrupt(); } } diff --git a/src/Kernel/Platform.h b/src/Kernel/Platform.h index c445db4..d340f34 100644 --- a/src/Kernel/Platform.h +++ b/src/Kernel/Platform.h @@ -11,10 +11,16 @@ typedef struct { ReadOnlySpanChar Name; uint32_t ArchitectureBits; + uint8_t BootCpuId; } PlatformInformation; -PlatformInformation PlatformGetInformation(); +// TODO: We should maybe put that in common and call it SystemDevice or SystemStaticDevice +typedef struct +{ +} PlatformDevices; +PlatformInformation PlatformGetInformation(); +PlatformDevices PlatformGetDevices(); // -------------------------------------------------------------------------------------- // Cpu @@ -22,10 +28,10 @@ PlatformInformation PlatformGetInformation(); typedef enum { - CpuInterruptType_None = 0, - CpuInterruptType_Software = 1, - CpuInterruptType_Timer = 2, - CpuInterruptType_External = 4, + CpuInterruptType_None = 0x00, + CpuInterruptType_Software = 0x01, + CpuInterruptType_Timer = 0x02, + CpuInterruptType_External = 0x04, CpuInterruptType_All = 0xFF, } CpuInterruptType; diff --git a/src/Kernel/Platforms/RiscV/Boot.S b/src/Kernel/Platforms/RiscV/Boot.S index 27a2d2c..a714660 100644 --- a/src/Kernel/Platforms/RiscV/Boot.S +++ b/src/Kernel/Platforms/RiscV/Boot.S @@ -18,7 +18,13 @@ boot: addi t0, t0, 1 blt t0, t1, .Lclear_bss_loop -.Lrun_init_array: + # Save boot parameters + la t0, globalBootHartId + save_pointer a0, (t0) + + la t0, globalDeviceTreeData + save_pointer a1, (t0) + # Run init array la t2, __INIT_ARRAY_START la t3, __INIT_ARRAY_END diff --git a/src/Kernel/Platforms/RiscV/Cpu.c b/src/Kernel/Platforms/RiscV/Cpu.c index c72409a..e2e558d 100644 --- a/src/Kernel/Platforms/RiscV/Cpu.c +++ b/src/Kernel/Platforms/RiscV/Cpu.c @@ -149,7 +149,7 @@ inline uint64_t CpuReadCycle() #endif inline void CpuGenerateInvalidInstruction() -{ +{ __asm__ volatile ("unimp"); } @@ -197,8 +197,9 @@ inline void CpuSetTrapHandler(CpuTrapHandler trapHandler) if (trapHandler) { __asm__ volatile( - "csrw stvec, %0\n" - "csrsi sstatus, 2" + "csrw sie, zero\n" + "csrci sstatus, 2\n" + "csrw stvec, %0" : : "r" (kernel_trap_entry)); } @@ -213,7 +214,8 @@ inline void CpuEnableInterrupts(CpuInterruptType types) auto mask = ComputeCpuInterruptMask(types); __asm__ volatile ( - "csrs sie, %0" + "csrs sie, %0\n" + "csrsi sstatus, 2" : : "r"(mask) : "memory" @@ -251,7 +253,6 @@ inline void CpuWaitForInterrupt() void LogRegister(ReadOnlySpanChar name, uintptr_t value, uint8_t padding, bool insertTab) { - // TODO: Color the register name with the keyword blue of VScode? KernelConsoleSetForegroundColor(KernelConsoleColorKeyword); KernelConsolePrint(String("%s"), name); KernelConsoleResetStyle(); diff --git a/src/Kernel/Platforms/RiscV/KernelTrapEntry.S b/src/Kernel/Platforms/RiscV/KernelTrapEntry.S index b718b9f..5a6c3b4 100644 --- a/src/Kernel/Platforms/RiscV/KernelTrapEntry.S +++ b/src/Kernel/Platforms/RiscV/KernelTrapEntry.S @@ -1,6 +1,6 @@ #include "AsmCommon.h" -.global kernel_trap_entry # TODO: Rename +.global kernel_trap_entry .section .text.interrupt diff --git a/src/Kernel/Platforms/RiscV/Platform.c b/src/Kernel/Platforms/RiscV/Platform.c index aeb390a..a14ad09 100644 --- a/src/Kernel/Platforms/RiscV/Platform.c +++ b/src/Kernel/Platforms/RiscV/Platform.c @@ -1,12 +1,181 @@ #include "../../Platform.h" +#include "Memory.h" #include "String.h" +#include "Types.h" + +// TODO: Add tests + +uintptr_t globalBootHartId; +uintptr_t globalDeviceTreeData; PlatformInformation PlatformGetInformation() { return (PlatformInformation) { .Name = String("RISC-V"), - .ArchitectureBits = PLATFORM_ARCHITECTURE_BITS + .ArchitectureBits = PLATFORM_ARCHITECTURE_BITS, + .BootCpuId = globalBootHartId + }; +} + +// TODO: Put that in a common binary reader or similar and do tests +// TODO: We should have a create binary reader that take the encoding and the pointer +// TODO: It would be cool if it could work with streams but it seems too much +// TODO: This function should take into account the endianness of the platform +uint32_t BinaryReadUint32Old(uintptr_t pointer) +{ + // TODO: For now big endian -> little endian conversion + auto result = *(uint32_t*)pointer; + + if (PLATFORM_BYTE_ORDER == ByteOrder_LittleEndian) + { + result = __builtin_bswap32(result); + } + + return result; +} + +typedef struct +{ + ReadOnlySpanUint8 Data; + ByteOrder ByteOrder; + size_t CurrentOffset; +} BinaryReader; + +BinaryReader CreateBinaryReader(ReadOnlySpanUint8 data, ByteOrder byteOrder) +{ + return (BinaryReader) + { + .Data = data, + .ByteOrder = byteOrder, + .CurrentOffset = 0 }; } +uint32_t BinaryReadUint32(BinaryReader* reader) +{ + auto span = SpanSliceFrom(reader->Data, reader->CurrentOffset); + // TODO: For now big endian -> little endian conversion + // TODO: Do the other conversions + auto result = *(uint32_t*)span.Pointer; + + if (PLATFORM_BYTE_ORDER == ByteOrder_LittleEndian) + { + result = __builtin_bswap32(result); + } + + reader->CurrentOffset += sizeof(uint32_t); + + return result; +} + +// TODO: When we have memoryarena we can maybe do better +void BinaryReadString(BinaryReader* reader, SpanChar* output) +{ + auto span = SpanSliceFrom(reader->Data, reader->CurrentOffset); + // TODO: For now big endian -> little endian conversion + // TODO: Do the other conversions + + uint32_t length = 0; + + while (span.Pointer[length] != '\0') + { + output->Pointer[length] = span.Pointer[length]; + length++; + } + + output->Length = length; + reader->CurrentOffset += length + 1; +} + +void BinarySetOffset(BinaryReader* reader, size_t offset) +{ + reader->CurrentOffset = offset; +} + +void DeviceTreeReadNode(BinaryReader* reader, size_t stringDataOffset) +{ + auto testNode = BinaryReadUint32(reader); + + if (testNode == 0x01) + { + auto name = StackAllocChar(1024); + BinaryReadString(reader, &name); + BinarySetOffset(reader, MemoryAlignUp(reader->CurrentOffset, 4)); + + KernelConsolePrint(String("BeginNode: '%s'\n"), name); + } + else if (testNode == 0x02) + { + KernelConsolePrint(String("EndNode\n")); + } + else if (testNode == 0x03) + { + auto length = BinaryReadUint32(reader); + auto nameOffset = BinaryReadUint32(reader); + + if (length != 4) + { + KernelConsolePrint(String(" Unknown length: %d\n"), length); + } + + auto value = BinaryReadUint32(reader); + + auto offset = reader->CurrentOffset; + BinarySetOffset(reader, stringDataOffset + nameOffset); + + auto name = StackAllocChar(1024); + BinaryReadString(reader, &name); + + BinarySetOffset(reader, MemoryAlignUp(offset, 4)); + KernelConsolePrint(String(" Property: %s, %d\n"), name, value); + } + else + { + KernelConsolePrint(String("Unknown Node: %d\n"), testNode); + } +} + +PlatformDevices PlatformGetDevices() +{ + auto dtbMagic = BinaryReadUint32Old(globalDeviceTreeData); + auto sizeInBytes = BinaryReadUint32Old(globalDeviceTreeData + sizeof(uint32_t)); + + // TODO: Check magic + // TODO: Check boot_cpuid_phys + + auto dataSpan = CreateReadOnlySpanUint8((const uint8_t*)globalDeviceTreeData, sizeInBytes); + auto reader = CreateBinaryReader(dataSpan, ByteOrder_BigEndian); + BinarySetOffset(&reader, sizeof(uint32_t) * 2); + + auto structureOffset = BinaryReadUint32(&reader); + auto stringDataOffset = BinaryReadUint32(&reader); + + // TODO: Parse the rest of the header + + BinarySetOffset(&reader, structureOffset); + + DeviceTreeReadNode(&reader, stringDataOffset); + DeviceTreeReadNode(&reader, stringDataOffset); + DeviceTreeReadNode(&reader, stringDataOffset); + + DeviceTreeReadNode(&reader, stringDataOffset); + DeviceTreeReadNode(&reader, stringDataOffset); + DeviceTreeReadNode(&reader, stringDataOffset); + + + /* This is a property node parsing + testNode = BinaryReadUint32(&reader); + length = BinaryReadUint32(&reader); + nameOffset = BinaryReadUint32(&reader); + KernelConsolePrint(String("TestNode: %d, %d, %d\n"), testNode, length, nameOffset); + auto test = SpanSliceFrom(dataSpan, stringDataOffset + nameOffset); + KernelConsolePrint(String("Test: %s\n"), test); + */ + + + // TODO: We parse DTB here for now but it will be moved in Kernel/Devices/DTB + return (PlatformDevices) + { + }; +}