From bd468f087deb35460cfa704e90950048ed9aa480 Mon Sep 17 00:00:00 2001 From: souldbminersmwc Date: Mon, 24 Aug 2026 21:21:50 -0400 Subject: [PATCH] hocclk: add bpmpfw loading --- Source/hoc-clk/bpmpfw/Makefile | 44 +++++ Source/hoc-clk/bpmpfw/bpmpfw.ld | 151 ++++++++++++++++++ Source/hoc-clk/bpmpfw/out/bpmpfw.bin | Bin 0 -> 272 bytes Source/hoc-clk/bpmpfw/source/main.cpp | 9 ++ Source/hoc-clk/bpmpfw/source/regs.hpp | 42 +++++ Source/hoc-clk/bpmpfw/source/start.s | 65 ++++++++ Source/hoc-clk/build.sh | 9 ++ Source/hoc-clk/sysmodule/Makefile | 2 +- Source/hoc-clk/sysmodule/src/board/board.cpp | 12 +- Source/hoc-clk/sysmodule/src/board/board.hpp | 2 +- Source/hoc-clk/sysmodule/src/bpmp/bpmp.cpp | 140 ++++++++++++++++ Source/hoc-clk/sysmodule/src/bpmp/bpmp.hpp | 23 +++ .../hoc-clk/sysmodule/src/mapping/mem_map.cpp | 24 +++ .../hoc-clk/sysmodule/src/mapping/mem_map.hpp | 2 + 14 files changed, 522 insertions(+), 3 deletions(-) create mode 100644 Source/hoc-clk/bpmpfw/Makefile create mode 100644 Source/hoc-clk/bpmpfw/bpmpfw.ld create mode 100644 Source/hoc-clk/bpmpfw/out/bpmpfw.bin create mode 100644 Source/hoc-clk/bpmpfw/source/main.cpp create mode 100644 Source/hoc-clk/bpmpfw/source/regs.hpp create mode 100644 Source/hoc-clk/bpmpfw/source/start.s create mode 100644 Source/hoc-clk/sysmodule/src/bpmp/bpmp.cpp create mode 100644 Source/hoc-clk/sysmodule/src/bpmp/bpmp.hpp diff --git a/Source/hoc-clk/bpmpfw/Makefile b/Source/hoc-clk/bpmpfw/Makefile new file mode 100644 index 00000000..0631e56b --- /dev/null +++ b/Source/hoc-clk/bpmpfw/Makefile @@ -0,0 +1,44 @@ +ifeq ($(strip $(DEVKITARM)),) +$(error "Please set DEVKITARM in your environment. export DEVKITARM=devkitARM") +endif +include $(DEVKITARM)/base_rules + +TARGET := bpmpfw +BUILDDIR := build +OUTPUTDIR := out +SOURCEDIR := source + +OBJS := $(BUILDDIR)/start.o $(BUILDDIR)/main.o + +ARCH := -march=armv4t -mtune=arm7tdmi -mthumb-interwork +CXXFLAGS := $(ARCH) -O2 -g -ffreestanding -nostdlib -fno-exceptions -fno-rtti \ + -fno-unwind-tables -fno-threadsafe-statics -ffunction-sections -fdata-sections \ + -fomit-frame-pointer -std=gnu++20 -Wall -Wextra $(CUSTOMDEFINES) +ASFLAGS := $(ARCH) -g +LDFLAGS := $(ARCH) -nostartfiles -nodefaultlibs -Wl,--nmagic,--gc-sections \ + -T $(SOURCEDIR)/../bpmpfw.ld -lgcc + +BIN_TARGET := $(OUTPUTDIR)/$(TARGET).bin + +.PHONY: all clean + +all: $(BIN_TARGET) + +$(BIN_TARGET): $(BUILDDIR)/$(TARGET).elf + @mkdir -p $(OUTPUTDIR) + $(OBJCOPY) -S -O binary $< $@ + +$(BUILDDIR)/$(TARGET).elf: $(OBJS) + @$(CXX) $(LDFLAGS) $(OBJS) -o $@ + +$(BUILDDIR)/%.o: $(SOURCEDIR)/%.cpp | $(BUILDDIR) + @$(CXX) $(CXXFLAGS) -I$(SOURCEDIR) -c $< -o $@ + +$(BUILDDIR)/%.o: $(SOURCEDIR)/%.s | $(BUILDDIR) + @$(CXX) $(ASFLAGS) -I$(SOURCEDIR) -c $< -o $@ + +$(BUILDDIR): + @mkdir -p $(BUILDDIR) + +clean: + @rm -rf $(BUILDDIR) $(OUTPUTDIR) diff --git a/Source/hoc-clk/bpmpfw/bpmpfw.ld b/Source/hoc-clk/bpmpfw/bpmpfw.ld new file mode 100644 index 00000000..dc63a2ad --- /dev/null +++ b/Source/hoc-clk/bpmpfw/bpmpfw.ld @@ -0,0 +1,151 @@ +OUTPUT_ARCH(arm) +ENTRY(reset) + +MEMORY +{ + bpmpfw : ORIGIN = 0x40004000, LENGTH = 32K +} + +SECTIONS +{ + PROVIDE(__start__ = ORIGIN(bpmpfw)); + . = __start__; + __code_start = . ; + + .vectors : + { + KEEP (*(.vectors .vectors.*)) + . = ALIGN(8); + } >bpmpfw + + .text : + { + *(.text.unlikely .text.*_unlikely .text.unlikely.*) + *(.text.exit .text.exit.*) + *(.text.startup .text.startup.*) + *(.text.hot .text.hot.*) + *(.text .stub .text.* .gnu.linkonce.t.*) + . = ALIGN(8); + } >bpmpfw + + .init : + { + KEEP( *(.init) ) + . = ALIGN(8); + } >bpmpfw + + .plt : + { + *(.plt) + *(.iplt) + . = ALIGN(8); + } >bpmpfw + + .fini : + { + KEEP( *(.fini) ) + . = ALIGN(8); + } >bpmpfw + + . = ALIGN(8); + __rodata_start = . ; + + .rodata : + { + *(.rodata .rodata.* .gnu.linkonce.r.*) + . = ALIGN(8); + } >bpmpfw + + .eh_frame_hdr : { __eh_frame_hdr_start = .; *(.eh_frame_hdr) *(.eh_frame_entry .eh_frame_entry.*) __eh_frame_hdr_end = .; } >bpmpfw + .eh_frame : ONLY_IF_RO { KEEP (*(.eh_frame)) *(.eh_frame.*) } >bpmpfw + .gcc_except_table : ONLY_IF_RO { *(.gcc_except_table .gcc_except_table.*) } >bpmpfw + .gnu_extab : ONLY_IF_RO { *(.gnu_extab*) } >bpmpfw + + .hash : { *(.hash) } >bpmpfw + + . = ALIGN(8); + __data_start = . ; + + .eh_frame : ONLY_IF_RW { KEEP (*(.eh_frame)) *(.eh_frame.*) } >bpmpfw + .gcc_except_table : ONLY_IF_RW { *(.gcc_except_table .gcc_except_table.*) } >bpmpfw + .gnu_extab : ONLY_IF_RW { *(.gnu_extab*) } >bpmpfw + .exception_ranges : ONLY_IF_RW { *(.exception_ranges .exception_ranges*) } >bpmpfw + + .preinit_array ALIGN(8) : + { + PROVIDE (__preinit_array_start = .); + KEEP (*(.preinit_array)) + PROVIDE (__preinit_array_end = .); + } >bpmpfw + + .init_array ALIGN(8) : + { + PROVIDE (__init_array_start = .); + KEEP (*(SORT(.init_array.*))) + KEEP (*(.init_array)) + PROVIDE (__init_array_end = .); + } >bpmpfw + + .fini_array ALIGN(8) : + { + PROVIDE (__fini_array_start = .); + KEEP (*(.fini_array)) + KEEP (*(SORT(.fini_array.*))) + PROVIDE (__fini_array_end = .); + } >bpmpfw + + .ctors ALIGN(8) : + { + KEEP (*crtbegin.o(.ctors)) /* MUST be first -- GCC requires it */ + KEEP (*(EXCLUDE_FILE (*crtend.o) .ctors)) + KEEP (*(SORT(.ctors.*))) + KEEP (*(.ctors)) + } >bpmpfw + + .dtors ALIGN(8) : + { + KEEP (*crtbegin.o(.dtors)) + KEEP (*(EXCLUDE_FILE (*crtend.o) .dtors)) + KEEP (*(SORT(.dtors.*))) + KEEP (*(.dtors)) + } >bpmpfw + + __got_start__ = .; + + .got : { *(.got) *(.igot) } >bpmpfw + .got.plt : { *(.got.plt) *(.igot.plt) } >bpmpfw + + __got_end__ = .; + + .data ALIGN(8) : + { + *(.data .data.* .gnu.linkonce.d.*) + SORT(CONSTRUCTORS) + } >bpmpfw + + __bss_start__ = .; + .bss ALIGN(8) : + { + *(.dynbss) + *(.bss .bss.* .gnu.linkonce.b.*) + *(COMMON) + . = ALIGN(16); + } >bpmpfw + __bss_end__ = .; + + __end__ = ABSOLUTE(.) ; + + __stack_top = ORIGIN(bpmpfw) + LENGTH(bpmpfw) - 0x10; + + /DISCARD/ : { *(.group .comment .note .interp .ARM.attributes) } + + .stab 0 : { *(.stab) } + .stabstr 0 : { *(.stabstr) } + .debug_info 0 : { *(.debug_info) } + .debug_abbrev 0 : { *(.debug_abbrev) } + .debug_line 0 : { *(.debug_line) } + .debug_frame 0 : { *(.debug_frame) } + .debug_str 0 : { *(.debug_str) } + .debug_loc 0 : { *(.debug_loc) } + .debug_macinfo 0 : { *(.debug_macinfo) } +} diff --git a/Source/hoc-clk/bpmpfw/out/bpmpfw.bin b/Source/hoc-clk/bpmpfw/out/bpmpfw.bin new file mode 100644 index 0000000000000000000000000000000000000000..8f7b8bdf1930cf30adf7cd862c2737682ba60da6 GIT binary patch literal 272 zcmWe)V0fhh#L)r^9_uj7f2yM}|7nQ9q^AlD!jJ#_|Ig(h(Dam1;KNe}hQP-^{{NQ} z0Llv(%zw&a(Dd~0|NpN(I50RcBrp^JVZsRp28RP5G#+36p!vAs!u+QdK=UdD=09an zSn!yUA>bh+1H&p7g@z};f%;M$=08mdnE#ZOA><)5NStBH6aEJa9t!-|fA|w9f9wDM z*B(IqG6wyR7zHjr0ol*Nz`!M;QBpOs$oIM`}(^zCv12ey)O3fNy}VTR0a30|Nj>N_6%B literal 0 HcmV?d00001 diff --git a/Source/hoc-clk/bpmpfw/source/main.cpp b/Source/hoc-clk/bpmpfw/source/main.cpp new file mode 100644 index 00000000..bcbb764d --- /dev/null +++ b/Source/hoc-clk/bpmpfw/source/main.cpp @@ -0,0 +1,9 @@ +#include "regs.hpp" + +extern "C" void main() { + UartPuts("[bpmpfw]: Hello from BPMP-FW\n"); + + for (;;) { + FlowCtlrHaltUsec(200); + } +} diff --git a/Source/hoc-clk/bpmpfw/source/regs.hpp b/Source/hoc-clk/bpmpfw/source/regs.hpp new file mode 100644 index 00000000..dc7d3761 --- /dev/null +++ b/Source/hoc-clk/bpmpfw/source/regs.hpp @@ -0,0 +1,42 @@ +#pragma once +#include + +using u8 = std::uint8_t; +using u16 = std::uint16_t; +using u32 = std::uint32_t; + +#define MMIO32(addr) (*reinterpret_cast(addr)) + +constexpr u32 FlowCtlrBase = 0x60007000; +constexpr u32 FlowCtlrHaltCopEvents = 0x004; + +constexpr u32 HaltModeWaitEvent = (2u << 29); +constexpr u32 HaltUsec = (0u << 24); + +inline void FlowCtlrHaltUsec(u32 usec) { + MMIO32(FlowCtlrBase + FlowCtlrHaltCopEvents) = HaltModeWaitEvent | HaltUsec | (usec & 0xFFFFFFu); +} + +constexpr u32 UartBBase = 0x70006040; +constexpr u32 UartThr = 0x00; +constexpr u32 UartLsr = 0x14; +constexpr u32 UartLsrThre = (1u << 5); + +inline void UartPutc(char c) { + while (!(MMIO32(UartBBase + UartLsr) & UartLsrThre)) + ; + MMIO32(UartBBase + UartThr) = static_cast(static_cast(c)); +} + +inline void UartPuts(const char *s) { + while (*s) { + UartPutc(*s++); + } +} + +inline void UartPutHex32(u32 v) { + static const char digits[] = "0123456789ABCDEF"; + for (int i = 28; i >= 0; i -= 4) { + UartPutc(digits[(v >> i) & 0xF]); + } +} diff --git a/Source/hoc-clk/bpmpfw/source/start.s b/Source/hoc-clk/bpmpfw/source/start.s new file mode 100644 index 00000000..afabaa9c --- /dev/null +++ b/Source/hoc-clk/bpmpfw/source/start.s @@ -0,0 +1,65 @@ +.section .vectors, "ax", %progbits +.align 3 +.global reset +reset: + b _start + b _panic + +.section .text.start, "ax", %progbits +.align 3 +.global _start +.extern main +_start: + /* Mask IRQ + FIQ, enter SVC mode. */ + msr cpsr_f, #0xC0 + msr cpsr_cf, #0xD3 + + /* Set the stack pointer. */ + ldr sp, =__stack_top + + /* Zero .bss. */ + ldr r0, =__bss_start__ + ldr r1, =__bss_end__ + mov r2, #0 +1: + cmp r0, r1 + bge 2f + str r2, [r0], #4 + b 1b +2: + + /* Run global constructors. */ + ldr r4, =__init_array_start + ldr r5, =__init_array_end +3: + cmp r4, r5 + bge 4f + ldr r0, [r4], #4 + mov lr, pc + bx r0 + b 3b +4: + + bl main + +.global _panic +_panic: + ldr r0, =0x70006040 /* UART_B_BASE */ + adr r3, _panic_msg +7: + ldrb r1, [r3], #1 + cmp r1, #0 + beq _panic_hang +8: + ldr r2, [r0, #0x14] /* UART_LSR */ + tst r2, #0x20 /* UART_LSR_THRE */ + beq 8b + str r1, [r0] + b 7b + +_panic_msg: + .asciz "[bpmpfw] PANIC\n" + .align 2 + +_panic_hang: + b _panic_hang diff --git a/Source/hoc-clk/build.sh b/Source/hoc-clk/build.sh index b3de7e5f..f06780ec 100755 --- a/Source/hoc-clk/build.sh +++ b/Source/hoc-clk/build.sh @@ -42,6 +42,15 @@ mkdir -p "$DIST_DIR/switch/.overlays" cp -vf "$ROOT_DIR/overlay/out/horizon-oc-overlay.ovl" "$DIST_DIR/switch/.overlays/horizon-oc-overlay.ovl" echo +echo "*** Compiling bpmpfw ***" +pushd "$ROOT_DIR/bpmpfw" +make -j$CORES +popd > /dev/null + +mkdir -p "$DIST_DIR/config/horizon-oc" +cp -vf "$ROOT_DIR/bpmpfw/out/bpmpfw.bin" "$DIST_DIR/config/horizon-oc/bpmpfw.bin" +echo + echo "*** Copying assets ***" mkdir -p "$DIST_DIR/config/horizon-oc" cp -vf "$ROOT_DIR/config.ini.template" "$DIST_DIR/config/horizon-oc/config.ini.template" diff --git a/Source/hoc-clk/sysmodule/Makefile b/Source/hoc-clk/sysmodule/Makefile index 03b7eb07..01693f80 100644 --- a/Source/hoc-clk/sysmodule/Makefile +++ b/Source/hoc-clk/sysmodule/Makefile @@ -22,7 +22,7 @@ CONFIG_DIR := horizon-oc BUILD := build OUTDIR := out RESOURCES := res -SOURCES := src src/hos src/i2c src/ipc src/board src/display src/tsensor src/mgr src/file src/soc src/mapping src/pwr src/util +SOURCES := src src/hos src/i2c src/ipc src/board src/bpmp src/display src/tsensor src/mgr src/file src/soc src/mapping src/pwr src/util DATA := data INCLUDES := ../common/include src/hos src/soc src/i2c src/util src/pwr src/ipc EXEFS_SRC := exefs_src diff --git a/Source/hoc-clk/sysmodule/src/board/board.cpp b/Source/hoc-clk/sysmodule/src/board/board.cpp index 8923374a..8bfeb2bb 100644 --- a/Source/hoc-clk/sysmodule/src/board/board.cpp +++ b/Source/hoc-clk/sysmodule/src/board/board.cpp @@ -35,6 +35,7 @@ #include #include +#include "../bpmp/bpmp.hpp" #include "../display/display_refresh_rate.hpp" #include "../file/file_utils.hpp" #include "../hos/apm_ext.h" @@ -52,7 +53,7 @@ namespace board { - u64 clkVirtAddr, dsiVirtAddr, apbVirtAddr, fuseVirtAddr; + u64 clkVirtAddr, dsiVirtAddr, apbVirtAddr, fuseVirtAddr, sysVirtAddr, actmonVirtAddr; HocClkSocType gSocType; u8 gDramID; @@ -153,6 +154,10 @@ namespace board { rc = QueryMemoryMapping(&fuseVirtAddr, 0x7000F000, 0x1000); ASSERT_RESULT_OK(rc, "QueryMemoryMapping (fuse)"); + rc = QueryMemoryMapping(&sysVirtAddr, 0x6000C000, 0x1000); + ASSERT_RESULT_OK(rc, "QueryMemoryMapping (sys)"); + actmonVirtAddr = sysVirtAddr + 0x800; + FetchHardwareInfos(); Result nvCheck = 1; @@ -173,6 +178,11 @@ namespace board { tsensor::InitializeSoctherm(); // SOCTHERM must be init before AOTAG + Result bpmpfwRc = bpmp::StartBpmfwExecution(); + if (R_FAILED(bpmpfwRc)) { + fileUtils::LogLine("[bpmp] StartBpmfwExecution failed: 0x%x", bpmpfwRc); + } + // PMC exosphere check SecmonArgs args = {}; args.X[0] = 0xF0000002; diff --git a/Source/hoc-clk/sysmodule/src/board/board.hpp b/Source/hoc-clk/sysmodule/src/board/board.hpp index 0a50622b..313400af 100644 --- a/Source/hoc-clk/sysmodule/src/board/board.hpp +++ b/Source/hoc-clk/sysmodule/src/board/board.hpp @@ -42,7 +42,7 @@ #define HOSSVC_HAS_TC (hosversionAtLeast(5, 0, 0)) namespace board { - extern u64 clkVirtAddr, dsiVirtAddr, apbVirtAddr, fuseVirtAddr; + extern u64 clkVirtAddr, dsiVirtAddr, apbVirtAddr, fuseVirtAddr, sysVirtAddr, actmonVirtAddr; extern HocClkSocType gSocType; extern u8 gDramID; extern HocClkConsoleType gConsoleType; diff --git a/Source/hoc-clk/sysmodule/src/bpmp/bpmp.cpp b/Source/hoc-clk/sysmodule/src/bpmp/bpmp.cpp new file mode 100644 index 00000000..e7390bdc --- /dev/null +++ b/Source/hoc-clk/sysmodule/src/bpmp/bpmp.cpp @@ -0,0 +1,140 @@ +/* + * Copyright (c) Souldbminer, Lightos and Horizon OC Contributors + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +#include +#include +#include + +#include "../board/board.hpp" +#include "../file/file_utils.hpp" +#include "../mapping/mem_map.hpp" +#include "bpmp.hpp" + +namespace bpmp { + + namespace { + + constexpr u64 FlowCtlrPhysBase = 0x60007000; + constexpr u64 EvpPhysBase = 0x6000F000; + + constexpr u32 ClkRstRstDevLSet = 0x300; + constexpr u32 ClkRstRstDevLClr = 0x304; + constexpr u32 RstDevLCopRstBit = (1u << 1); /* SWR_COP_RST */ + + constexpr u32 ApbMiscSlaveSecurityReg0 = 0xC00; + constexpr u32 ApbMiscSlaveSecurityReg1 = 0xC04; + constexpr u32 ApbMiscSlaveSecurityReg2 = 0xC08; + + /* Relative to actmonVirtAddr */ + constexpr u32 ActmonCopCtrl = 0xC0; + constexpr u32 ActmonCopIntrStatus = 0xE4; + + constexpr u32 EvpCopResetVector = 0x200; + constexpr u32 EvpCopUndefVector = 0x204; + constexpr u32 EvpCopSwiVector = 0x208; + constexpr u32 EvpCopPrefetchAbortVector = 0x20C; + constexpr u32 EvpCopDataAbortVector = 0x210; + constexpr u32 EvpCopRsvdVector = 0x214; + constexpr u32 EvpCopIrqVector = 0x218; + constexpr u32 EvpCopFiqVector = 0x21C; + + constexpr u32 FlowCtlrHaltCopEvents = 0x004; + constexpr u32 FlowModeNone = 0x00000000; + + constexpr u64 FwIramPhysBase = 0x40004000; + constexpr u32 FwStagingSize = 0x8000; + + alignas(4096) u8 s_fwStageBuf[FwStagingSize]; + + inline volatile u32 &Mmio(u64 base_va, u32 offset) { + return *reinterpret_cast(base_va + offset); + } + + } // namespace + + Result StartBpmfwExecution() { + if (!IsPatchedExosphere()) { + fileUtils::LogLine("[bpmp] Cannot start without patched exosphere"); + return (Result)1; + } + + std::memset(s_fwStageBuf, 0, sizeof(s_fwStageBuf)); + + FILE *f = fopen("sdmc:/config/horizon-oc/bpmpfw.bin", "rb"); + if (!f) { + fileUtils::LogLine("[bpmp] StartBpmfwExecution: bpmpfw.bin not found"); + return (Result)1; + } + + const size_t fw_size = fread(s_fwStageBuf, 1, sizeof(s_fwStageBuf), f); + fclose(f); + + if (fw_size == 0) { + fileUtils::LogLine("[bpmp] StartBpmfwExecution: bpmpfw.bin is empty"); + return (Result)1; + } + + fileUtils::LogLine("[bpmp] StartBpmfwExecution: loaded %zu bytes, loading at 0x%llx", + fw_size, static_cast(FwIramPhysBase)); + + /* Set BPMP reset */ + Mmio(board::clkVirtAddr, ClkRstRstDevLSet) = RstDevLCopRstBit; + + /* Grant BPMP access to all a bunch of registers that are useful */ + Mmio(board::apbVirtAddr, ApbMiscSlaveSecurityReg0) = 0; + Mmio(board::apbVirtAddr, ApbMiscSlaveSecurityReg1) = 0; + Mmio(board::apbVirtAddr, ApbMiscSlaveSecurityReg2) = 0; + + /* Set up exeption vectors for bpmp */ + const u32 fw_reset_vector = static_cast(FwIramPhysBase + 0x0); + const u32 fw_panic_vector = static_cast(FwIramPhysBase + 0x4); + + SmcReadWriteRegister(EvpPhysBase + EvpCopResetVector, 0xFFFFFFFF, fw_reset_vector); + SmcReadWriteRegister(EvpPhysBase + EvpCopUndefVector, 0xFFFFFFFF, fw_panic_vector); + SmcReadWriteRegister(EvpPhysBase + EvpCopSwiVector, 0xFFFFFFFF, fw_panic_vector); + SmcReadWriteRegister(EvpPhysBase + EvpCopPrefetchAbortVector, 0xFFFFFFFF, fw_panic_vector); + SmcReadWriteRegister(EvpPhysBase + EvpCopDataAbortVector, 0xFFFFFFFF, fw_panic_vector); + SmcReadWriteRegister(EvpPhysBase + EvpCopRsvdVector, 0xFFFFFFFF, fw_panic_vector); + SmcReadWriteRegister(EvpPhysBase + EvpCopIrqVector, 0xFFFFFFFF, fw_panic_vector); + SmcReadWriteRegister(EvpPhysBase + EvpCopFiqVector, 0xFFFFFFFF, fw_panic_vector); + + /* Disable actmon monitoring to avoid hang on FW >4.0.0 */ + Mmio(board::actmonVirtAddr, ActmonCopCtrl) = 0; + Mmio(board::actmonVirtAddr, ActmonCopIntrStatus) = Mmio(board::actmonVirtAddr, ActmonCopIntrStatus); + + /* Load the BPMPFW into iram per page. TODO: determine if this is nessesary */ + constexpr size_t PageSize = 4096; + for (size_t ofs = 0; ofs < fw_size; ofs += PageSize) { + const size_t chunk = (fw_size - ofs) < PageSize ? (fw_size - ofs) : PageSize; + + Result copy_rc = SmcCopyToIram(FwIramPhysBase + ofs, s_fwStageBuf + ofs, static_cast(chunk)); + if (R_FAILED(copy_rc)) { + fileUtils::LogLine("[bpmp] SmcCopyToIram failed at +0x%zx: 0x%x", ofs, copy_rc); + return copy_rc; + } + } + + /* Clear BPMP reset. */ + Mmio(board::clkVirtAddr, ClkRstRstDevLClr) = RstDevLCopRstBit; + + /* Clear the halt written by bootloader. */ + SmcReadWriteRegister(FlowCtlrPhysBase + FlowCtlrHaltCopEvents, 0xFFFFFFFF, FlowModeNone); + + return 0; + } + +} // namespace bpmp diff --git a/Source/hoc-clk/sysmodule/src/bpmp/bpmp.hpp b/Source/hoc-clk/sysmodule/src/bpmp/bpmp.hpp new file mode 100644 index 00000000..e860f662 --- /dev/null +++ b/Source/hoc-clk/sysmodule/src/bpmp/bpmp.hpp @@ -0,0 +1,23 @@ +/* + * Copyright (c) Souldbminer, Lightos and Horizon OC Contributors + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +#pragma once +#include + +namespace bpmp { + Result StartBpmfwExecution(); +} diff --git a/Source/hoc-clk/sysmodule/src/mapping/mem_map.cpp b/Source/hoc-clk/sysmodule/src/mapping/mem_map.cpp index ae34021a..08d3a9d3 100644 --- a/Source/hoc-clk/sysmodule/src/mapping/mem_map.cpp +++ b/Source/hoc-clk/sysmodule/src/mapping/mem_map.cpp @@ -65,4 +65,28 @@ Result SmcCopyToIram(uintptr_t dest, const void *src, u32 size) { rc = (26u | ((u32)args.X[0] << 9u)); } return rc; +} + +bool IsPatchedExosphere() { + constexpr u64 EvpPhysBase = 0x6000F000; + constexpr u64 EvpCopResetVector = 0x200; + + SecmonArgs args = {}; + args.X[0] = 0xF0000002; + args.X[1] = EvpPhysBase + EvpCopResetVector; + args.X[2] = 0; + args.X[3] = 0; + svcCallSecureMonitor(&args); + + return args.X[0] == 0; +} + +u32 SmcReadWriteRegister(u64 phys_addr, u32 mask, u32 value) { + SecmonArgs args = {}; + args.X[0] = 0xF0000002; + args.X[1] = phys_addr; + args.X[2] = mask; + args.X[3] = value; + svcCallSecureMonitor(&args); + return (u32)args.X[1]; } \ No newline at end of file diff --git a/Source/hoc-clk/sysmodule/src/mapping/mem_map.hpp b/Source/hoc-clk/sysmodule/src/mapping/mem_map.hpp index 6cb6e1be..fa5900aa 100644 --- a/Source/hoc-clk/sysmodule/src/mapping/mem_map.hpp +++ b/Source/hoc-clk/sysmodule/src/mapping/mem_map.hpp @@ -22,3 +22,5 @@ Result QueryMemoryMapping(u64 *virtaddr, u64 physaddr, u64 size); Result MapAddress(u64 &va, const u64 &physAddr, const char *name); Result SmcCopyFromIram(void *dest, uintptr_t src, u32 size); Result SmcCopyToIram(uintptr_t dest, const void *src, u32 size); +bool IsPatchedExosphere(); +u32 SmcReadWriteRegister(u64 phys_addr, u32 mask, u32 value);