├── .gitignore ├── .gitmodules ├── DumpOnChipBlRemnants ├── Makefile ├── _start.S ├── _start.o ├── dump-on-chip-bl-remnants.elf └── dump-on-chip-bl-remnants.raw ├── InjectSvc6 ├── Makefile ├── main.c ├── psp-patch-addr.h ├── psp-svc-inject.c ├── psp-svc-inject.ld ├── psp-svc-inject.s ├── psp-svc-inject_head.o └── psp-svc-trace.h ├── LICENSE ├── Lib ├── _cm-start.S ├── _start.S ├── _start_zen2.S ├── _svc-start.S ├── include │ ├── binloader.h │ ├── cdefs.h │ ├── checkpoint.h │ ├── err.h │ ├── io.h │ ├── log.h │ ├── misc.h │ ├── mmio.h │ ├── platform.h │ ├── psp.h │ ├── smn-map.h │ ├── string.h │ ├── svc.h │ ├── tm.h │ ├── types.h │ ├── uart.h │ ├── x86-map.h │ └── x86mem.h └── src │ ├── checkpoint.S │ ├── log.c │ ├── misc.c │ ├── platform.c │ ├── smn-map.c │ ├── string.c │ ├── svc.S │ ├── tm.c │ ├── uart.c │ ├── x86-map.c │ └── x86mem.c ├── PspSerialStub ├── Makefile ├── main.c ├── pdu-transp-spi-em100.c ├── pdu-transp-spi-flash.c ├── pdu-transp-uart.c ├── pdu-transp.h ├── psp-serial-stub-internal.h ├── thumb-interwork.S └── utils.S ├── PspStub ├── Makefile └── main.c ├── PspUartHelloWorld ├── Makefile └── main.c ├── README.md ├── StubCodeModules └── HelloWorld │ ├── Makefile │ └── main.c ├── Tools └── psp-log-dump.py └── build ├── cm-linker.ld ├── linker.ld ├── linker_binload.ld ├── linker_zen2.ld └── svc-linker.ld /.gitignore: -------------------------------------------------------------------------------- 1 | *.o 2 | *.raw 3 | *.elf 4 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "include"] 2 | path = include 3 | url = https://github.com/AlexanderEichner/psp-includes 4 | -------------------------------------------------------------------------------- /DumpOnChipBlRemnants/Makefile: -------------------------------------------------------------------------------- 1 | CROSS_COMPILE=arm-none-eabi- 2 | CFLAGS=-Os -I../include -I../Lib/include -std=gnu99 -fomit-frame-pointer -nostartfiles -ffreestanding -Wextra -Werror 3 | VPATH=../Lib/src 4 | 5 | all : dump-on-chip-bl-remnants.elf dump-on-chip-bl-remnants.raw 6 | 7 | clean: 8 | rm -f _start.o dump-on-chip-bl-remnants.elf dump-on-chip-bl-remnants.raw 9 | 10 | %.o: %.S 11 | $(CROSS_COMPILE)gcc $(CFLAGS) -c -o $@ $^ 12 | 13 | dump-on-chip-bl-remnants.elf : ../build/linker.ld _start.o 14 | $(CROSS_COMPILE)ld -T $^ -o $@ 15 | 16 | dump-on-chip-bl-remnants.raw: dump-on-chip-bl-remnants.elf 17 | $(CROSS_COMPILE)objcopy -O binary $^ $@ 18 | 19 | 20 | -------------------------------------------------------------------------------- /DumpOnChipBlRemnants/_start.S: -------------------------------------------------------------------------------- 1 | .extern main 2 | _start: 3 | ldr r0, =0x38500 4 | ldr r1, =0x40000 5 | ldr r2, =0x02aab000 6 | 7 | _loop_head: 8 | cmp r0, r1 9 | beq _exit 10 | ldr r3, [r0] 11 | str r3, [r2] 12 | add r0, r0, #4 13 | add r2, r2, #4 14 | b _loop_head 15 | 16 | _exit: 17 | mov r0, #0 18 | 19 | /* Exit gracefully */ 20 | svc $0x0 21 | 22 | /* vim: ft=gas : 23 | */ 24 | -------------------------------------------------------------------------------- /DumpOnChipBlRemnants/_start.o: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PSPReverse/psp-apps/bc865a2a2703a2343a625ebf71424cd3c30d0b9c/DumpOnChipBlRemnants/_start.o -------------------------------------------------------------------------------- /DumpOnChipBlRemnants/dump-on-chip-bl-remnants.elf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PSPReverse/psp-apps/bc865a2a2703a2343a625ebf71424cd3c30d0b9c/DumpOnChipBlRemnants/dump-on-chip-bl-remnants.elf -------------------------------------------------------------------------------- /DumpOnChipBlRemnants/dump-on-chip-bl-remnants.raw: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PSPReverse/psp-apps/bc865a2a2703a2343a625ebf71424cd3c30d0b9c/DumpOnChipBlRemnants/dump-on-chip-bl-remnants.raw -------------------------------------------------------------------------------- /InjectSvc6/Makefile: -------------------------------------------------------------------------------- 1 | CROSS_COMPILE=arm-none-eabi- 2 | CFLAGS=-Os -g -DPSP_VERSION=1 -DIN_PSP -I../include -I../Lib/include -std=gnu99 -fomit-frame-pointer -nostartfiles -ffreestanding -Wextra -Werror 3 | VPATH=../Lib/src 4 | 5 | OBJS = main.o string.o svc.o x86mem.o uart.o 6 | 7 | all : inject-svc-6.elf inject-svc-6.raw 8 | 9 | clean: 10 | rm -f _start.o $(OBJS) inject-svc-6.elf inject-svc-6.raw psp-svc-inject.h psp-svc-inject.o psp-svc-inject.bin psp-svc-inject.elf 11 | 12 | %.o: %.c 13 | $(CROSS_COMPILE)gcc $(CFLAGS) -c -o $@ $^ 14 | 15 | %.o: %.S 16 | $(CROSS_COMPILE)gcc $(CFLAGS) -c -o $@ $^ 17 | 18 | psp-svc-inject.h: psp-svc-inject.bin 19 | ./bin2c $^ $@ psp_svc_inject 20 | 21 | psp-svc-inject.bin: psp-svc-inject.elf 22 | $(CROSS_COMPILE)objcopy -O binary $^ $@ 23 | 24 | psp-svc-inject.elf : psp-svc-inject.ld psp-svc-inject_head.o psp-svc-inject.o 25 | $(CROSS_COMPILE)ld -T $^ -o $@ 26 | 27 | psp-svc-inject.o: psp-svc-inject.c 28 | $(CROSS_COMPILE)gcc $(CFLAGS) -c -march=armv7-a -mthumb -fno-toplevel-reorder -o $@ $^ 29 | 30 | psp-svc-inject_head.o: psp-svc-inject.s 31 | $(CROSS_COMPILE)as -march=armv7-a -mcpu=cortex-a8 -o $@ $^ 32 | 33 | _start.o: ../Lib/_start.S 34 | $(CROSS_COMPILE)as -march=armv7-a -mcpu=cortex-a8 -o $@ $^ 35 | 36 | main.o: main.c psp-svc-inject.h 37 | $(CROSS_COMPILE)gcc $(CFLAGS) -c -o $@ main.c 38 | 39 | inject-svc-6.elf : ../build/linker.ld _start.o $(OBJS) 40 | $(CROSS_COMPILE)ld -T $^ -o $@ 41 | 42 | inject-svc-6.raw: inject-svc-6.elf 43 | $(CROSS_COMPILE)objcopy -O binary $^ $@ 44 | 45 | 46 | -------------------------------------------------------------------------------- /InjectSvc6/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include "psp-svc-inject.h" 10 | #include "psp-patch-addr.h" 11 | 12 | /** The address we patch the svc 0x6 replacement into. */ 13 | #define PSP_FW_SVC_6_PATCH_ADDR ((void *)0x12000) 14 | 15 | #if 0 16 | static void puts(const char *pszStr) 17 | { 18 | size_t cchStr = strlen(pszStr); 19 | size_t cchAlign = cchStr & ~(uint32_t)0x3; 20 | size_t cchRem = cchStr - cchAlign; 21 | 22 | *(volatile uint32_t *)0x01AAB000 = 0xdeadc0de; 23 | 24 | while (cchAlign > 0) 25 | { 26 | *(volatile uint32_t *)0x01AAB000 = *(uint32_t *)pszStr; 27 | cchAlign -= sizeof(uint32_t); 28 | pszStr += sizeof(uint32_t); 29 | } 30 | 31 | switch (cchRem) 32 | { 33 | case 0: 34 | break; 35 | case 1: 36 | *(volatile uint32_t *)0x01AAB000 = (uint32_t)*pszStr; 37 | break; 38 | case 2: 39 | *(volatile uint32_t *)0x01AAB000 = (uint32_t)(pszStr[0] | (pszStr[1] << 8)); 40 | break; 41 | case 3: 42 | *(volatile uint32_t *)0x01AAB000 = (uint32_t)(pszStr[0] | (pszStr[1] << 8) | (pszStr[2] << 16)); 43 | break; 44 | default: 45 | do { } while (1); 46 | } 47 | 48 | *(volatile uint32_t *)0x01AAB000 = 0xc0dedead; 49 | } 50 | 51 | static void put_dword(uint32_t u32) 52 | { 53 | *(volatile uint32_t *)0x01AAB000 = 0xdeadc0de; 54 | *(volatile uint32_t *)0x01AAB000 = u32; 55 | *(volatile uint32_t *)0x01AAB000 = 0xc0dedead; 56 | } 57 | 58 | static void dump_bytes(const uint8_t *pb, uint32_t cb) 59 | { 60 | *(volatile uint32_t *)0x01AAB000 = 0xdeadc0de; 61 | for (unsigned i = 0; i < cb; i++) 62 | *(volatile uint32_t *)0x01AAB000 = *pb++ << 24; 63 | *(volatile uint32_t *)0x01AAB000 = 0xc0dedead; 64 | } 65 | #endif 66 | 67 | /** 68 | * x86 UART register read callback. 69 | */ 70 | static int pspStubX86UartRegRead(PCPSPIODEVIF pIfIoDev, uint32_t offReg, void *pvBuf, size_t cbRead) 71 | { 72 | /* UART supports only 1 byte wide register accesses. */ 73 | if (cbRead != 1) return ERR_INVALID_STATE; 74 | 75 | psp_x86_mmio_read(0xfffdfc0003f8 + offReg, pvBuf, cbRead); 76 | return 0; 77 | } 78 | 79 | 80 | /** 81 | * x86 UART register write callback. 82 | */ 83 | static int pspStubX86UartRegWrite(PCPSPIODEVIF pIfIoDev, uint32_t offReg, const void *pvBuf, size_t cbWrite) 84 | { 85 | /* UART supports only 1 byte wide register accesses. */ 86 | if (cbWrite != 1) return ERR_INVALID_STATE; 87 | 88 | psp_x86_mmio_write(0xfffdfc0003f8 + offReg, pvBuf, cbWrite); 89 | return 0; 90 | } 91 | 92 | 93 | void main(void) 94 | { 95 | /* Make sure the memory containing the page tables is cleared. */ 96 | svc_invalidate_mem(SVC_INV_MEM_OP_CLEAN_AND_INVALIDATE, 0, (void *)0x14000, 4096); 97 | svc_invalidate_mem(SVC_INV_MEM_OP_CLEAN_AND_INVALIDATE, 0, (void *)0x13000, 4096); 98 | svc_invalidate_mem(SVC_INV_MEM_OP_CLEAN_AND_INVALIDATE, 0, (void *)0x9000, 4096); 99 | 100 | volatile uint8_t *pbDst = (uint8_t *)PSP_FW_SVC_6_PATCH_ADDR; 101 | volatile uint8_t *pbSrc = (uint8_t *)psp_svc_inject; 102 | for (int i = 0; i < psp_svc_inject_length; i++) 103 | *pbDst++ = *pbSrc++; 104 | 105 | svc_invalidate_mem(SVC_INV_MEM_OP_CLEAN_AND_INVALIDATE, 0, (void *)0x12000, 4096); 106 | 107 | /* Patch the branch to the syscall handler and override with our address. */ 108 | *(volatile uint32_t *)PSP_FW_SVC_HANDLER_PATCH_ADDR = (uint32_t)PSP_FW_SVC_6_PATCH_ADDR; 109 | //*(volatile uint32_t *)PSP_FW_SVC_APP_CLEANUP_HANDLER_PATCH_ADDR = (uint32_t)PSP_FW_SVC_6_PATCH_ADDR; 110 | 111 | svc_dbg_print("Activating the svc interceptor\n"); /* DO NOT REMOVE OR EVERYTHING WILL FALL APART! */ 112 | svc_invalidate_mem(SVC_INV_MEM_OP_CLEAN_AND_INVALIDATE, 0, (void *)0x0, 12 * 4096); 113 | 114 | /* Only master accesses UART, everyone else traps. */ 115 | if (*(volatile uint8_t *)(0x3f000 + 0xa50) == 0) 116 | { 117 | PSPIODEVIF IfIoDev; 118 | PSPUART Uart; 119 | 120 | IfIoDev.pfnRegRead = pspStubX86UartRegRead; 121 | IfIoDev.pfnRegWrite = pspStubX86UartRegWrite; 122 | 123 | int rc = PSPUartCreate(&Uart, &IfIoDev); 124 | if (!rc) 125 | { 126 | svc_dbg_print("UART created\n"); 127 | rc = PSPUartParamsSet(&Uart, 115200, PSPUARTDATABITS_8BITS, PSPUARTPARITY_NONE, PSPUARTSTOPBITS_1BIT); 128 | if (!rc) 129 | { 130 | svc_dbg_print("UART configured\n"); 131 | PSPUartWrite(&Uart, "Hello World!\n", sizeof("Hello World!\n") - 1, NULL); 132 | } 133 | 134 | svc_dbg_print("UART done\n"); 135 | } 136 | else 137 | svc_dbg_print("UART creation failed\n"); 138 | } 139 | else 140 | svc_dbg_print("Skipping UART test\n"); 141 | 142 | #if 0 143 | svc_dbg_print("Overwriting x86 memory protection\n"); 144 | *(uint8_t *)0x3360 = 0x4f; 145 | *(uint8_t *)0x3361 = 0xf4; 146 | *(uint8_t *)0x3362 = 0x90; 147 | *(uint8_t *)0x3363 = 0x33; /* mov.w r3, #0x12000 */ 148 | 149 | *(uint8_t *)0x3364 = 0x03; 150 | *(uint8_t *)0x3365 = 0xf5; 151 | *(uint8_t *)0x3366 = 0x20; 152 | *(uint8_t *)0x3367 = 0x63; /* add.w r3, #0xa00 */ 153 | 154 | *(uint8_t *)0x3368 = 0x03; 155 | *(uint8_t *)0x3369 = 0xf1; 156 | *(uint8_t *)0x336a = 0x69; 157 | *(uint8_t *)0x336b = 0x03; /* add.w r3, #0x69 */ 158 | 159 | *(uint8_t *)0x336c = 0x18; 160 | *(uint8_t *)0x336d = 0x47; /* bx r3 */ 161 | 162 | svc_dbg_print("Overwriting x86 memory protection finished\n"); 163 | svc_invalidate_mem(SVC_INV_MEM_OP_CLEAN_AND_INVALIDATE, 0, (void *)0x3000, 4096); 164 | #endif 165 | } 166 | -------------------------------------------------------------------------------- /InjectSvc6/psp-patch-addr.h: -------------------------------------------------------------------------------- 1 | #ifndef psp_patch_addr_h 2 | #define psp_patch_addr_h 3 | 4 | #if PSP_VERSION == 1 5 | #define PSP_FW_SVC_APP_CLEANUP_HANDLER_PATCH_ADDR (0x540) 6 | #define PSP_FW_SVC_HANDLER_PATCH_ADDR (0x544) 7 | #define PSP_FW_TRAP_HANDLER_PATCH_ADDR (0x53c) 8 | #define PSP_MAP_X86_HOST_MEMORY_EX_ADDR (0x6090) 9 | #define PSP_SVC_HANDLER_ADDR (0x9518) 10 | #define PSP_INV_MEM_ADDR (0x170c) 11 | #else 12 | # error "Unknown PSP version set" 13 | #endif 14 | 15 | #endif /* !psp_patch_addr_h */ 16 | 17 | -------------------------------------------------------------------------------- /InjectSvc6/psp-svc-inject.ld: -------------------------------------------------------------------------------- 1 | 2 | SECTIONS 3 | { 4 | . = 0x12000; 5 | .text ALIGN(0x1): { *(.text) } 6 | } 7 | -------------------------------------------------------------------------------- /InjectSvc6/psp-svc-inject.s: -------------------------------------------------------------------------------- 1 | 2 | .section .text 3 | .extern svc_inject_handler 4 | .extern svc_app_cleanup_inject_handler 5 | 6 | /* 7 | * Wrapper for main syscall handler of the PSP firmware 8 | */ 9 | _svc_entry: 10 | stmfd sp!, { r0, r1, lr } 11 | sub sp, #4 12 | mov r2, sp 13 | bl svc_inject_handler 14 | mov r2, r0 15 | cmp r2, #0 16 | bne _svc_not_handled 17 | ldr r0, [sp] /* Adjust the return value. */ 18 | add sp, #4 19 | ldmia sp!, { r0, r1, lr } 20 | mov pc, lr 21 | _svc_not_handled: 22 | add sp, #4 23 | ldmia sp!, { r0, r1, lr } 24 | ldr r2, =_svc_orig_addr 25 | ldr r2, [r2] 26 | bx r2 27 | 28 | /* 29 | * Wrapper for the cleanup userspace app handler of the PSP firmware 30 | */ 31 | /* 32 | _svc_cleanup_entry: 33 | stmfd sp!, { r0, r1, lr } 34 | bl svc_app_cleanup_inject_handler 35 | ldmia sp!, { r0, r1, lr } 36 | ldr r2, =_svc_app_cleanup_orig_addr 37 | ldr r2, [r2] 38 | bx r2 39 | */ 40 | 41 | _svc_orig_addr: 42 | .word 0x9519 43 | /*_svc_app_cleanup_orig_addr: 44 | .word 0x9e59 */ 45 | /* vim: ft=gas : 46 | */ 47 | -------------------------------------------------------------------------------- /InjectSvc6/psp-svc-inject_head.o: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PSPReverse/psp-apps/bc865a2a2703a2343a625ebf71424cd3c30d0b9c/InjectSvc6/psp-svc-inject_head.o -------------------------------------------------------------------------------- /Lib/_cm-start.S: -------------------------------------------------------------------------------- 1 | /** @file 2 | * Code Module support - startup code which comes first. 3 | */ 4 | 5 | /* 6 | * Copyright (C) 2020 Alexander Eichner 7 | * 8 | * This library is free software; you can redistribute it and/or 9 | * modify it under the terms of the GNU Lesser General Public 10 | * License as published by the Free Software Foundation; either 11 | * version 2.1 of the License, or (at your option) any later version. 12 | * 13 | * This library is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 16 | * Lesser General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU Lesser General Public 19 | * License along with this library; if not, write to the Free Software 20 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 21 | */ 22 | 23 | /** 24 | * This is all ugly AF but in order two mix and match ARM with Thumb code 25 | * we need our entry to set everything up correctly because the calling code 26 | * assumes ARM mode (and can't know whether a code mocule contains Thumb code). 27 | */ 28 | .extern main 29 | _start: 30 | push {lr} 31 | ldr lr, [sp, #4] /* Relocate the last two arguments on the stack */ 32 | push {lr} 33 | ldr lr, [sp, #12] 34 | push {lr} 35 | blx main 36 | pop {lr} 37 | pop {lr} 38 | pop {lr} 39 | bx lr 40 | 41 | -------------------------------------------------------------------------------- /Lib/_start.S: -------------------------------------------------------------------------------- 1 | .extern SCRATCH_STACK_TOP 2 | .extern BSS_START 3 | .extern BSS_END 4 | .extern main 5 | .extern memset 6 | _start: 7 | mov r4, r0 /* Save the arguments. */ 8 | mov r5, r1 9 | mov r6, r2 10 | mov r7, r3 11 | ldr sp, =SCRATCH_STACK_TOP 12 | mov r0, $0x3b000 /* Start address of main stack */ 13 | mov r1, $0x3d000 /* End address of main stack */ 14 | mov r2, sp /* Address where to return the mapped memory area */ 15 | svc $1 /* Call map stack service call. */ 16 | ldr r0, [sp, #0x0] /* Load stack address from scratch stack. */ 17 | mov sp, r0 /* Switch to the new stack. */ 18 | mov r0, r4 /* Restore arguments. */ 19 | mov r1, r5 20 | mov r2, r6 21 | mov r3, r7 22 | blx main 23 | 24 | /* Exit gracefully */ 25 | svc $0x0 26 | 27 | /* vim: ft=gas : 28 | */ 29 | -------------------------------------------------------------------------------- /Lib/_start_zen2.S: -------------------------------------------------------------------------------- 1 | .extern SCRATCH_STACK_TOP 2 | .extern BSS_START 3 | .extern BSS_END 4 | .extern main 5 | .extern memset 6 | _start: 7 | mov r4, r0 /* Save the arguments. */ 8 | mov r5, r1 9 | mov r6, r2 10 | mov r7, r3 11 | ldr sp, =SCRATCH_STACK_TOP 12 | mov r0, $0x4b000 /* Start address of main stack */ 13 | mov r1, $0x4d000 /* End address of main stack */ 14 | mov r2, sp /* Address where to return the mapped memory area */ 15 | svc $1 /* Call map stack service call. */ 16 | ldr r0, [sp, #0x0] /* Load stack address from scratch stack. */ 17 | mov sp, r0 /* Switch to the new stack. */ 18 | mov r0, r4 /* Restore arguments. */ 19 | mov r1, r5 20 | mov r2, r6 21 | mov r3, r7 22 | blx main 23 | 24 | /* Exit gracefully */ 25 | svc $0x0 26 | 27 | /* vim: ft=gas : 28 | */ 29 | -------------------------------------------------------------------------------- /Lib/_svc-start.S: -------------------------------------------------------------------------------- 1 | /** @file 2 | * PSP serial stub - SVC startup code. 3 | */ 4 | 5 | /* 6 | * Copyright (C) 2020 Alexander Eichner 7 | * 8 | * This library is free software; you can redistribute it and/or 9 | * modify it under the terms of the GNU Lesser General Public 10 | * License as published by the Free Software Foundation; either 11 | * version 2.1 of the License, or (at your option) any later version. 12 | * 13 | * This library is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 16 | * Lesser General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU Lesser General Public 19 | * License along with this library; if not, write to the Free Software 20 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 21 | */ 22 | .extern SCRATCH_STACK_TOP_SVC 23 | .extern SCRATCH_STACK_TOP_UNDEF 24 | .extern SCRATCH_STACK_TOP_ABORT 25 | .extern SCRATCH_STACK_TOP_IRQ 26 | .extern SCRATCH_STACK_TOP_FIQ 27 | .extern BSS_START 28 | .extern BSS_END 29 | .extern main 30 | .extern memset 31 | .extern ExcpUndefInsn 32 | .extern ExcpSwi 33 | .extern ExcpPrefAbrt 34 | .extern ExcpDataAbrt 35 | .extern ExcpIrq 36 | .extern ExcpFiq 37 | 38 | 39 | /** 40 | * Macro generating a an exception handler entry point. 41 | * 42 | * @param a_Name Name of the entry point 43 | * @param a_FnCall The function to call. 44 | */ 45 | .macro EXCP_ENTRY_POINT_GEN a_Name a_FnCall 46 | \a_Name: 47 | stmfd sp!, {lr} /* Save LR */ 48 | mrs lr, spsr /* Save SPSR */ 49 | stmfd sp!, {lr} 50 | stmfd sp!, {r0-r12} /* Save register set. */ 51 | mov r0, sp 52 | blx \a_FnCall 53 | ldmfd sp!, {r0-r12} /* Restore register set. */ 54 | ldmfd sp!, {lr} /* Restore SPSR */ 55 | msr spsr, lr 56 | ldmfd sp!, {lr} /* Restore LR */ 57 | subs pc, lr, #0 /* Switch back to where we came from, lr gets adjusted in the respective exception C handlers */ 58 | .endm 59 | 60 | _g_aExcpVectors: 61 | ldr pc, =_start 62 | ldr pc, =_undef_insn 63 | ldr pc, =_swi 64 | ldr pc, =_prefetch_abort 65 | ldr pc, =_data_abort 66 | nop 67 | ldr pc, =_irq 68 | ldr pc, =_fiq 69 | 70 | _start: 71 | mrc p15, #0x0, r1, cr1, cr0, #0x0 /* Read MMU control register and clear V bit to set the exception vector table address to the low range */ 72 | bic r1, r1, #0x2000 73 | mcr p15, #0x0, r1, cr1, cr0, #0x0 74 | ldr r1, =_g_aExcpVectors /* Set the exception vector table address. */ 75 | mcr p15, #0x0, r1, cr12, cr0, #0x0 76 | msr cpsr, #0xd2 77 | ldr sp, =SCRATCH_STACK_TOP_IRQ 78 | msr cpsr, #0xd1 79 | ldr sp, =SCRATCH_STACK_TOP_FIQ 80 | msr cpsr, #0xd7 81 | ldr sp, =SCRATCH_STACK_TOP_ABORT 82 | msr cpsr, #0xdb 83 | ldr sp, =SCRATCH_STACK_TOP_UNDEF 84 | msr cpsr, #0x53 85 | ldr sp, =SCRATCH_STACK_TOP_SVC 86 | ldr r0, =BSS_START 87 | mov r1, #0 88 | ldr r2, =BSS_END 89 | sub r2, r2, r0 90 | blx memset /* Clear BSS section. */ 91 | blx main 92 | 93 | /* Generate default exception handlers. */ 94 | EXCP_ENTRY_POINT_GEN _undef_insn ExcpUndefInsn 95 | EXCP_ENTRY_POINT_GEN _prefetch_abort ExcpPrefAbrt 96 | EXCP_ENTRY_POINT_GEN _data_abort ExcpDataAbrt 97 | EXCP_ENTRY_POINT_GEN _irq ExcpIrq 98 | 99 | _swi: 100 | blx ExcpSwi 101 | b fault 102 | 103 | _fiq: 104 | blx ExcpFiq 105 | b fault 106 | 107 | fault: 108 | b fault 109 | 110 | -------------------------------------------------------------------------------- /Lib/include/binloader.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Binary loader interface. 3 | */ 4 | #ifndef __include_binloader_h 5 | #define __include_binloader_h 6 | 7 | #include 8 | #include 9 | 10 | /** Load address of the payload. */ 11 | #define BIN_LOADER_LOAD_ADDR (0x1d000) 12 | 13 | /** 14 | * Helper struct passed to the entry point containing some useful data about the environment. 15 | */ 16 | typedef struct BINLDRHLP 17 | { 18 | /** The CCD ID of the invoked PSP. */ 19 | uint32_t idCcd; 20 | /** Number of CCDs in the system. */ 21 | uint32_t cCcds; 22 | /** The passed pCmdBuf argument in main. */ 23 | void *pvCmdBuf; 24 | /** Logging function. */ 25 | void (*pfnLog)(const char *pszFmt, ...); 26 | } BINLDRHLP; 27 | typedef BINLDRHLP *PBINLDRHLP; 28 | typedef const BINLDRHLP *PCBINLDRHLP; 29 | 30 | /** Entry point for the binary loader payload. */ 31 | typedef void *FNBINLOADENTRY(void *pvState, PCBINLDRHLP pHlp, X86PADDR PhysX86AddrCmdBuf, uint32_t idCmd, uint8_t fFirstRun); 32 | typedef FNBINLOADENTRY *PFNBINLOADENTRY; 33 | 34 | #endif 35 | -------------------------------------------------------------------------------- /Lib/include/cdefs.h: -------------------------------------------------------------------------------- 1 | /** @file 2 | * General definitions 3 | */ 4 | 5 | /* 6 | * Copyright (C) 2019 Alexander Eichner 7 | * 8 | * This library is free software; you can redistribute it and/or 9 | * modify it under the terms of the GNU Lesser General Public 10 | * License as published by the Free Software Foundation; either 11 | * version 2.1 of the License, or (at your option) any later version. 12 | * 13 | * This library is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 16 | * Lesser General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU Lesser General Public 19 | * License along with this library; if not, write to the Free Software 20 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 21 | */ 22 | #ifndef __cdefs_h 23 | #define __cdefs_h 24 | 25 | #include 26 | 27 | #endif 28 | -------------------------------------------------------------------------------- /Lib/include/checkpoint.h: -------------------------------------------------------------------------------- 1 | /** @file 2 | * PSP internal interfaces - Checkpoint API. 3 | */ 4 | 5 | /* 6 | * Copyright (C) 2020 Alexander Eichner 7 | * 8 | * This library is free software; you can redistribute it and/or 9 | * modify it under the terms of the GNU Lesser General Public 10 | * License as published by the Free Software Foundation; either 11 | * version 2.1 of the License, or (at your option) any later version. 12 | * 13 | * This library is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 16 | * Lesser General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU Lesser General Public 19 | * License along with this library; if not, write to the Free Software 20 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 21 | */ 22 | #ifndef INCLUDED_Lib_include_checkpoint_h 23 | #define INCLUDED_Lib_include_checkpoint_h 24 | 25 | #if defined(IN_PSP) 26 | # include 27 | #else 28 | # error "Invalid environment" 29 | #endif 30 | 31 | /** PSP checkpoint. */ 32 | typedef union PSPCHCKPT 33 | { 34 | /** Array view. */ 35 | uint32_t au32Regs[17]; 36 | /** Field view. */ 37 | struct 38 | { 39 | uint32_t u32R0; 40 | uint32_t u32R1; 41 | uint32_t u32R2; 42 | uint32_t u32R3; 43 | uint32_t u32R4; 44 | uint32_t u32R5; 45 | uint32_t u32R6; 46 | uint32_t u32R7; 47 | uint32_t u32R8; 48 | uint32_t u32R9; 49 | uint32_t u32R10; 50 | uint32_t u32R11; 51 | uint32_t u32R12; 52 | uint32_t u32SP; 53 | uint32_t u32LR; 54 | uint32_t u32PC; 55 | uint32_t u32Cpsr; 56 | } Regs; 57 | } PSPCHCKPT; 58 | /** Pointer to a checkpoint. */ 59 | typedef PSPCHCKPT *PPSPCHCKPT; 60 | /** Pointer to a const checkpoint. */ 61 | typedef const PSPCHCKPT *PCPSPCHCKPT; 62 | 63 | 64 | /** 65 | * Sets an execution checkpoint. 66 | * 67 | * @returns true if the checkpoint was set, false if we restarted from the previously set checkpoint. 68 | * @param pChkPt Where to store the checkpoint state. 69 | */ 70 | bool PSPCheckPointSet(PPSPCHCKPT pChkPt); 71 | 72 | #endif /* !INCLUDED_Lib_include_checkpoint_h */ 73 | 74 | -------------------------------------------------------------------------------- /Lib/include/err.h: -------------------------------------------------------------------------------- 1 | #ifndef __include_err_h 2 | #define __include_err_h 3 | 4 | #define PSPSTATUS_SUCCESS (0) 5 | 6 | /** Status code success indicator. */ 7 | #define INF_SUCCESS (0) 8 | 9 | /** Operation still pending, try again later. */ 10 | #define INF_TRY_AGAIN (1) 11 | /** Invalid parameter passed. */ 12 | #define ERR_INVALID_PARAMETER (-1) 13 | /** Buffer overflow. */ 14 | #define ERR_BUFFER_OVERFLOW (-2) 15 | /** Not implemented at the moment. */ 16 | #define ERR_NOT_IMPLEMENTED (-3) 17 | /** Invalid state encountered. */ 18 | #define ERR_INVALID_STATE (-4) 19 | 20 | /** 21 | * USS specific error codes. 22 | */ 23 | /** The remaining data of the telegram is too short to get the requested value. */ 24 | #define ERR_USS_TLG_TOO_SHORT (-100) 25 | /** The telegram parser is not in the correct state to execute the request. */ 26 | #define ERR_USS_TLG_PARSER_INVALID_STATE (-101) 27 | /** The telegram still has unparsed data left. */ 28 | #define WRN_USS_TLG_PARSER_DATA_LEFT (100) 29 | 30 | /** 31 | * USS transport driver specific error codes. 32 | */ 33 | /** No time keeping manager was given during creation. The periodic telegram feature 34 | * is not available. */ 35 | #define ERR_USS_TRANSP_NO_TIMER (-200) 36 | /** The periodic callback was already set. */ 37 | #define ERR_USS_TRANSP_PERIODIC_TLG_CALLBACK_ALREADY_SET (-201) 38 | 39 | /** 40 | * TM (Timekeeping manager) specific error codes. 41 | */ 42 | /** There are no free slots left in the time keeping manager. */ 43 | #define ERR_TM_OUT_OF_SLOTS (-300) 44 | 45 | /** 46 | * NORD frequency inverter error codes. 47 | */ 48 | /** There is a mismatch between the size of the telegrams. */ 49 | #define ERR_NORD_MISMATCH_TELEGRAM_SIZE (-400) 50 | /** The frequency inverter is not responding in a timely fashion. */ 51 | #define ERR_NORD_NOT_RESPONDING (-401) 52 | 53 | /** 54 | * Flow controller error codes. 55 | */ 56 | /** There are not enough datapoints collected to get a trend. */ 57 | #define ERR_FLOWCTL_NOT_ENOUGH_DATAPOINTS_FOR_TREND (-500) 58 | 59 | #endif 60 | -------------------------------------------------------------------------------- /Lib/include/io.h: -------------------------------------------------------------------------------- 1 | /** @file 2 | * PSP internal interfaces - Device register read/write callbacks. 3 | */ 4 | 5 | /* 6 | * Copyright (C) 2020 Alexander Eichner 7 | * 8 | * Permission is hereby granted, free of charge, to any person obtaining a copy 9 | * of this software and associated documentation files (the "Software"), to deal 10 | * in the Software without restriction, including without limitation the rights 11 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | * copies of the Software, and to permit persons to whom the Software is 13 | * furnished to do so, subject to the following conditions: 14 | * 15 | * The above copyright notice and this permission notice shall be included in all 16 | * copies or substantial portions of the Software. 17 | * 18 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 24 | * SOFTWARE. 25 | */ 26 | #ifndef __include_io_h 27 | #define __include_io_h 28 | 29 | #if defined(IN_PSP) 30 | # include 31 | #else 32 | # error "Invalid environment" 33 | #endif 34 | 35 | /** Pointer to a I/O device interface. */ 36 | typedef struct PSPIODEVIF *PPSPIODEVIF; 37 | /** Pointer to a const I/O device interface. */ 38 | typedef const struct PSPIODEVIF *PCPSPIODEVIF; 39 | 40 | 41 | /** I/O device interface. */ 42 | typedef struct PSPIODEVIF 43 | { 44 | /** 45 | * Register read callback. 46 | * 47 | * @returns Status code. 48 | * @param pIfIoDev Pointer to the interface containing the callback. 49 | * @param offReg Offset of the register to read from. 50 | * @param pvBuf Where to store the read data. 51 | * @param cbRead How much to read. 52 | */ 53 | int (*pfnRegRead) (PCPSPIODEVIF pIfIoDev, uint32_t offReg, void *pvBuf, size_t cbRead); 54 | 55 | /** 56 | * Register write callback. 57 | * 58 | * @returns Status code. 59 | * @param pIfIoDev Pointer to the interface containing the callback. 60 | * @param offReg Offset of the register to start writing to. 61 | * @param pvBuf The data to write. 62 | * @param cbRead How much to write. 63 | */ 64 | int (*pfnRegWrite) (PCPSPIODEVIF pIfIoDev, uint32_t offReg, const void *pvBuf, size_t cbWrite); 65 | 66 | } PSPIODEVIF; 67 | 68 | 69 | /** 70 | * Reads from the register a the given offset. 71 | * 72 | * @returns 73 | */ 74 | static inline int PSPIoDevRegRead(PCPSPIODEVIF pIfIoDev, uint32_t offReg, void *pvBuf, size_t cbRead) 75 | { 76 | return pIfIoDev->pfnRegRead(pIfIoDev, offReg, pvBuf, cbRead); 77 | } 78 | 79 | 80 | static inline int PSPIoDevRegWrite(PCPSPIODEVIF pIfIoDev, uint32_t offReg, const void *pvBuf, size_t cbWrite) 81 | { 82 | return pIfIoDev->pfnRegWrite(pIfIoDev, offReg, pvBuf, cbWrite); 83 | } 84 | 85 | #endif /* !__include_uart_h */ 86 | 87 | -------------------------------------------------------------------------------- /Lib/include/log.h: -------------------------------------------------------------------------------- 1 | /** @file 2 | * Logging API and macros - inspired by the VirtualBox IPRT Logging API which is really neat. 3 | */ 4 | 5 | /* 6 | * Copyright (C) 2013 Alexander Eichner 7 | * 8 | * This library is free software; you can redistribute it and/or 9 | * modify it under the terms of the GNU Lesser General Public 10 | * License as published by the Free Software Foundation; either 11 | * version 2.1 of the License, or (at your option) any later version. 12 | * 13 | * This library is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 16 | * Lesser General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU Lesser General Public 19 | * License along with this library; if not, write to the Free Software 20 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 21 | */ 22 | #ifndef __log_h 23 | #define __log_h 24 | 25 | #include 26 | #include 27 | 28 | #include 29 | #include 30 | 31 | /** Log flush callback. */ 32 | typedef void FNLOGGERFLUSH(void *pvUser, uint8_t *pbBuf, size_t cbBuf); 33 | /** Pointer to a flush callback. */ 34 | typedef FNLOGGERFLUSH *PFNLOGGERFLUSH; 35 | 36 | /** A new line was started, the log ID and timestamp might be prepended. */ 37 | #define LOG_LOGGER_FLAGS_NEW_LINE BIT(10) 38 | 39 | /** 40 | * Logging instance. 41 | */ 42 | typedef struct LOGGER 43 | { 44 | /** Scratch buffer used for formatting. */ 45 | char achScratch[1024]; 46 | /** offset into the scratch buffer. */ 47 | unsigned offScratch; 48 | /** Logger identifier given during creation. */ 49 | const char *pszLogId; 50 | /** Pointer to the time manager to get timestamps. */ 51 | PTM pTm; 52 | /** Pointer to log flush callback. */ 53 | PFNLOGGERFLUSH pfnFlush; 54 | /** Opaque user data for the flush callback. */ 55 | void *pvUser; 56 | /** Internal flags for the logger. */ 57 | uint32_t fFlags; 58 | } LOGGER; 59 | /** Pointer to a logging instance. */ 60 | typedef LOGGER *PLOGGER; 61 | 62 | /** Debug logging workers, taking LOG_ENABLED into account. */ 63 | #ifdef LOG_ENABLED 64 | # define Log(a_pszFmt, ...) LOGLogger(NULL, a_pszFmt, ##__VA_ARGS__) 65 | #else 66 | # define Log(a_pszFmt, ...) do {} while (0) 67 | #endif 68 | 69 | /** Release logger worker, always logs no matter whether LOG_ENABLED is set. */ 70 | #define LogRel(a_pszFmt, ...) LOGLogger(NULL, a_pszFmt, ##__VA_ARGS__) 71 | 72 | /** The timestamp output format will be HH:MM:SS.mmm instead of just 73 | * millisecond. */ 74 | #define LOG_LOGGER_INIT_FLAGS_TS_FMT_HHMMSS BIT(0) 75 | 76 | /** 77 | * Initialises a new logger instance. 78 | * 79 | * @returns status code. 80 | * @param pLogger Pointer to the logger instance data to initialise. 81 | * @param pfnFlush Logging flush callback. 82 | * @param pvUser Opaque user data for the flush callback. 83 | * @param pszLogId Optional logging ID which is prepended before the actual message. 84 | * @param pTm Optional timekeeping manager to get timestamps in the log. 85 | * @param fFlags Flags for the logger, see LOG_LOGGER_INIT_FLAGS_* defines. 86 | */ 87 | int LOGLoggerInit(PLOGGER pLogger, PFNLOGGERFLUSH pfnFlush, void *pvUser, 88 | const char *pszLogId, PTM pTm, uint32_t fFlags); 89 | 90 | /** 91 | * Returns the default logging instance. 92 | * 93 | * @returns default logging instance or NULL if none was set. 94 | */ 95 | PLOGGER LOGLoggerGetDefaultInstance(void); 96 | 97 | /** 98 | * Sets a new default logging instance and returns the old one. 99 | * 100 | * @returns default logging instance or NULL if none was set. 101 | * @param pLogger The new default logging instance. 102 | */ 103 | PLOGGER LOGLoggerSetDefaultInstance(PLOGGER pLogger); 104 | 105 | /** 106 | * Main logging function. 107 | * 108 | * @returns nothing. 109 | * @param pLogger The logger instance to use, if NULL the default instance is used. 110 | * @param pszFmt Format string. 111 | * @param ... Format arguments. 112 | */ 113 | void LOGLogger(PLOGGER pLogger, const char *pszFmt, ...); 114 | 115 | void LOGLoggerV(PLOGGER pLogger, const char *pszFmt, va_list hArgs); 116 | 117 | #endif /* __log_h */ 118 | -------------------------------------------------------------------------------- /Lib/include/misc.h: -------------------------------------------------------------------------------- 1 | /** @file Miscellaneous functions. 2 | */ 3 | 4 | /* 5 | * Copyright (C) 2020 Alexander Eichner 6 | * Copyright (C) 2020 Robert Buhren 7 | * 8 | * This library is free software; you can redistribute it and/or 9 | * modify it under the terms of the GNU Lesser General Public 10 | * License as published by the Free Software Foundation; either 11 | * version 2.1 of the License, or (at your option) any later version. 12 | * 13 | * This library is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 16 | * Lesser General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU Lesser General Public 19 | * License along with this library; if not, write to the Free Software 20 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 21 | */ 22 | 23 | #ifndef __include_misc_h 24 | #define __include_misc_h 25 | 26 | #include 27 | #include 28 | #include 29 | 30 | uint32_t pspGetPhysDieId(void); 31 | 32 | static inline void pspIrqDisable(void) 33 | { 34 | asm volatile("dsb #0xf\n" 35 | "isb #0xf\n" 36 | "cpsid if\n": : :"memory"); 37 | } 38 | 39 | #endif 40 | -------------------------------------------------------------------------------- /Lib/include/mmio.h: -------------------------------------------------------------------------------- 1 | /** @file PSP MMIO helper functions. 2 | */ 3 | 4 | /* 5 | * Copyright (C) 2020 Alexander Eichner 6 | * Copyright (C) 2020 Robert Buhren 7 | * 8 | * This library is free software; you can redistribute it and/or 9 | * modify it under the terms of the GNU Lesser General Public 10 | * License as published by the Free Software Foundation; either 11 | * version 2.1 of the License, or (at your option) any later version. 12 | * 13 | * This library is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 16 | * Lesser General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU Lesser General Public 19 | * License along with this library; if not, write to the Free Software 20 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 21 | */ 22 | #ifndef __include_mmio_h 23 | #define __include_mmio_h 24 | 25 | #include 26 | 27 | /** 28 | * Does a MMIO read/write of the given length. 29 | * 30 | * @returns nothing. 31 | * @param pvDst The destination. 32 | * @param pvSrc The source. 33 | * @param cb Number of bytes to access. 34 | */ 35 | static inline void pspMmioAccess(void *pvDst, const void *pvSrc, size_t cb) 36 | { 37 | switch (cb) 38 | { 39 | case 1: 40 | *(volatile uint8_t *)pvDst = *(volatile const uint8_t *)pvSrc; 41 | break; 42 | case 2: 43 | *(volatile uint16_t *)pvDst = *(volatile const uint16_t *)pvSrc; 44 | break; 45 | case 4: 46 | *(volatile uint32_t *)pvDst = *(volatile const uint32_t *)pvSrc; 47 | break; 48 | case 8: 49 | *(volatile uint64_t *)pvDst = *(volatile const uint64_t *)pvSrc; 50 | break; 51 | default: 52 | break; 53 | } 54 | } 55 | 56 | #endif /* !__include_mmio_h */ 57 | -------------------------------------------------------------------------------- /Lib/include/platform.h: -------------------------------------------------------------------------------- 1 | /** @file Platform specific initialization routines. 2 | */ 3 | 4 | /* 5 | * Copyright (C) 2020 Alexander Eichner 6 | * Copyright (C) 2020 Robert Buhren 7 | * 8 | * This library is free software; you can redistribute it and/or 9 | * modify it under the terms of the GNU Lesser General Public 10 | * License as published by the Free Software Foundation; either 11 | * version 2.1 of the License, or (at your option) any later version. 12 | * 13 | * This library is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 16 | * Lesser General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU Lesser General Public 19 | * License along with this library; if not, write to the Free Software 20 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 21 | */ 22 | #define TARGET_PRIME_X370 1 23 | #define TARGET_H11DSU_IN 2 24 | 25 | /** Initializes the SOC and the SuperIO corresponding to the target */ 26 | void pspPlatformInit(void); 27 | -------------------------------------------------------------------------------- /Lib/include/psp.h: -------------------------------------------------------------------------------- 1 | /** 2 | * PSP privileged firmware part interfaces and defined structures. 3 | */ 4 | #ifndef __include_psp_h 5 | #define __include_psp_h 6 | 7 | #include 8 | 9 | /** 10 | * PSP register frame for the syscall handler. 11 | */ 12 | typedef struct PSPREGFRAME 13 | { 14 | uint32_t auGprs[13]; 15 | } PSPREGFRAME; 16 | 17 | #define REG_IDX_LR 12 18 | 19 | /** Pointer to a register frame. */ 20 | typedef PSPREGFRAME *PPSPREGFRAME; 21 | 22 | #endif 23 | -------------------------------------------------------------------------------- /Lib/include/smn-map.h: -------------------------------------------------------------------------------- 1 | /** @file 2 | * PSP internal interfaces - UART driver. 3 | */ 4 | 5 | /* 6 | * Copyright (C) 2020 Alexander Eichner 7 | * Copyright (C) 2020 Robert Buhren 8 | * 9 | * This library is free software; you can redistribute it and/or 10 | * modify it under the terms of the GNU Lesser General Public 11 | * License as published by the Free Software Foundation; either 12 | * version 2.1 of the License, or (at your option) any later version. 13 | * 14 | * This library is distributed in the hope that it will be useful, 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 17 | * Lesser General Public License for more details. 18 | * 19 | * You should have received a copy of the GNU Lesser General Public 20 | * License along with this library; if not, write to the Free Software 21 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 22 | */ 23 | 24 | #ifndef __include_smn_map_h 25 | #define __include_smn_map_h 26 | 27 | #include 28 | 29 | /** 30 | * SMN mapping slot. 31 | */ 32 | typedef struct PSPSMNMAPPING 33 | { 34 | /** Base SMN address being mapped (aligned to a 1MB boundary). */ 35 | SMNADDR SmnAddrBase; 36 | /* Reference counter for this mapping, the mapping gets cleand up if it reaches 0. */ 37 | uint32_t cRefs; 38 | } PSPSMNMAPPING; 39 | 40 | /** Pointer to a SMN mapping slot. */ 41 | typedef PSPSMNMAPPING *PPSPSMNMAPPING; 42 | 43 | /** Pointer to a const SMN mapping slot. */ 44 | typedef const PSPSMNMAPPING *PCPSPSMNMAPPING; 45 | 46 | /** 47 | * Maps the given SMN address into the PSP address space. 48 | * 49 | * @returns Status code. 50 | * @param SmnAddr The SMN address to map. 51 | * @param ppv Where to store the pointer to the mapping on success. 52 | */ 53 | int pspSmnMap(SMNADDR SmnAddr, void **ppv); 54 | 55 | /** 56 | * Unmaps a previously mapped SMN address. 57 | * 58 | * @returns Status code. 59 | * @param pv Pointer to the mapping as returned by a successful call to pspStubSmnMap(). 60 | */ 61 | int pspSmnUnmapByPtr(void *pv); 62 | 63 | /** 64 | * Stores a 32 bit value at the provided SMN address. 65 | * 66 | * @param SmnAddr SMN target address. 67 | * @param u32Val Value to store at "SmnAddr". 68 | */ 69 | void pspSmnWrU32(SMNADDR SmnAddr, uint32_t u32Val); 70 | 71 | #endif /* !__include_smn_map_h */ 72 | -------------------------------------------------------------------------------- /Lib/include/string.h: -------------------------------------------------------------------------------- 1 | #ifndef __include_string_h 2 | #define __include_string_h 3 | 4 | #include 5 | 6 | size_t strlen(const char *pszStr); 7 | 8 | void memcpy(void *pvDst, const void *pvSrc, size_t cb); 9 | 10 | void memset(void *pvDst, uint8_t ch, size_t cb); 11 | 12 | int memcmp(const void *pv1, const void *pv2, size_t cb); 13 | 14 | #endif 15 | -------------------------------------------------------------------------------- /Lib/include/svc.h: -------------------------------------------------------------------------------- 1 | #ifndef __include_svc_h 2 | #define __include_svc_h 3 | 4 | #include 5 | #include 6 | 7 | typedef enum SVC_INV_MEM_OP 8 | { 9 | SVC_INV_MEM_OP_CLEAN = 0x0, 10 | SVC_INV_MEM_OP_INVALIDATE = 0x1, 11 | SVC_INV_MEM_OP_CLEAN_AND_INVALIDATE = 0x2, 12 | SVC_INV_MEM_OP_32BIT_HACK = 0x7fffffff /**< Blow the type up to 32bit. */ 13 | } SVC_INV_MEM_OP; 14 | 15 | typedef enum PSP_X86_MEM_TYPE 16 | { 17 | PSP_X86_MEM_TYPE_UNKNOWN_1 = 0x1, 18 | PSP_X86_MEM_TYPE_UNKNOWN_4 = 0x4, 19 | PSP_X86_MEM_TYPE_UNKNOWN_6 = 0x6, 20 | PSP_X86_MEM_TYPE_32BIT_HACK = 0x7fffffff 21 | } PSP_X86_MEM_TYPE; 22 | 23 | typedef struct PSPX86MEMCOPYREQ 24 | { 25 | X86PADDR PhysX86AddrSrc; 26 | void *pvDst; 27 | uint32_t cbCopy; 28 | PSP_X86_MEM_TYPE enmMemType; 29 | } PSPX86MEMCOPYREQ; 30 | typedef PSPX86MEMCOPYREQ *PPSPX86MEMCOPYREQ; 31 | 32 | #define svc(code) asm volatile ("svc %[immediate]"::[immediate] "I" (code)) 33 | 34 | void svc_exit(unsigned int code); 35 | 36 | void svc_dbg_print(const char *pszStr); 37 | 38 | void svc_get_dbg_key(char* sp_dst, char* dst, unsigned int length); 39 | 40 | void svc_invalidate_mem(SVC_INV_MEM_OP enmOp, uint32_t fInsnMem, void *pvStart, uint32_t cbMem); 41 | 42 | void *svc_get_state_buffer(size_t cbBuf); 43 | 44 | uint32_t svc_x86_host_memory_copy_from(X86PADDR PhysX86AddrSrc, void *pvDst, size_t cbCopy); 45 | 46 | void *svc_x86_host_memory_map(X86PADDR PhysX86AddrMap, uint32_t enmMemType); 47 | 48 | uint32_t svc_x86_host_memory_unmap(void *pvMapped); 49 | 50 | uint32_t svc_query_two_64bit_values(uint64_t *pu64Val1, uint64_t *pu64Val2); 51 | 52 | uint16_t svc_x86_host_memory_copy_to_psp(PPSPX86MEMCOPYREQ pReq); 53 | 54 | uint16_t svc_x86_host_memory_copy_from_psp(PPSPX86MEMCOPYREQ pReq); 55 | 56 | uint32_t svc_call_other_psp(uint32_t idCcx, void *pvReq, size_t cbReq); 57 | 58 | void * svc_smn_map_ex(uint32_t u32SmnAddr, uint32_t idCcxTgt); 59 | 60 | uint32_t svc_smn_unmap(void *pvUnmap); 61 | 62 | void svc_unknown_id_16(void* pvArg0); 63 | 64 | void svc_unknown_id_4b(uint64_t* pvArg0); 65 | 66 | void svc_load_app(uint32_t idApp, void *pvDst, uint32_t *pvCbDst); 67 | 68 | /** Own injected syscalls. */ 69 | 70 | void *svc_injected_map_x86_host_memory_ex(X86PADDR PhysX86AddrMap, uint32_t enmType, uint32_t fFlags); 71 | 72 | void svc_log_char_buf(const char *pbBuf, size_t cchBuf); 73 | 74 | uint32_t svc_dbg_marker_1(void); 75 | uint32_t svc_dbg_marker_2(void); 76 | uint32_t svc_dbg_marker_3(void); 77 | uint32_t svc_dbg_marker_4(void); 78 | uint32_t svc_dbg_marker_5(void); 79 | 80 | uint32_t svc_template(uint32_t u32R0, uint32_t u32R1, uint32_t u32R2, uint32_t u32R3); 81 | 82 | #endif 83 | -------------------------------------------------------------------------------- /Lib/include/tm.h: -------------------------------------------------------------------------------- 1 | /** @file 2 | * Timekeeping manager. 3 | */ 4 | 5 | /* 6 | * Copyright (C) 2013 Alexander Eichner 7 | * 8 | * This library is free software; you can redistribute it and/or 9 | * modify it under the terms of the GNU Lesser General Public 10 | * License as published by the Free Software Foundation; either 11 | * version 2.1 of the License, or (at your option) any later version. 12 | * 13 | * This library is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 16 | * Lesser General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU Lesser General Public 19 | * License along with this library; if not, write to the Free Software 20 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 21 | */ 22 | #ifndef ___tm_h 23 | #define ___tm_h 24 | 25 | #include 26 | 27 | /** Number of slots for timer callbacks. */ 28 | #ifndef TM_TIMER_CALLBACK_SLOT_COUNT 29 | # define TM_TIMER_CALLBACK_SLOT_COUNT 10 30 | #endif 31 | 32 | /** Special milliseconds timer value for a disabled callback. */ 33 | #define TM_TIMER_CALLBACK_DISABLED UINT32_MAX 34 | 35 | /* A few required forward declarations. */ 36 | 37 | /** Pointer to a timer callback slot. */ 38 | typedef struct TMCLBKSLOT *PTMCLBKSLOT; 39 | /** Pointer to a timekeeping manager instance. */ 40 | typedef struct TM *PTM; 41 | 42 | /** 43 | * Timer callback. 44 | * 45 | * @returns nothing. 46 | * @param pTm The timekeeping manager this callback belongs to. 47 | * @param pTmClbk The particular slot the callbak is registered in. 48 | * @param pvUser Opaque user data given during registration. 49 | */ 50 | typedef void FNTMCLBK(PTM pTm, PTMCLBKSLOT pTmClbk, void *pvUser); 51 | /** Pointer to a timer callback. */ 52 | typedef FNTMCLBK *PFNTMCLBK; 53 | 54 | /** 55 | * Timer callback slot. 56 | * 57 | * @note: Everything in this struct is private, don't access directly. 58 | */ 59 | typedef struct TMCLBKSLOT 60 | { 61 | /** Index in the slot array. */ 62 | uint32_t idxSlot; 63 | /** When the callback should be fired again. */ 64 | volatile uint32_t cMilliesNext; 65 | /** Callback to execute. */ 66 | PFNTMCLBK pfnTmClbk; 67 | /** Opaque user data to pass in the callback. */ 68 | void *pvUser; 69 | } TMCLBKSLOT; 70 | 71 | /** 72 | * Timekeeping manager instance data. 73 | * 74 | * @note: Everything in this struct is private, don't access directly. 75 | */ 76 | typedef struct TM 77 | { 78 | /** Current microsecond count. */ 79 | volatile uint64_t cMicroSec; 80 | /** Number of timer callbacks registered. */ 81 | volatile uint32_t cTimerCallbacks; 82 | /** Padding. */ 83 | uint32_t u32Pad0; 84 | /** Array of timer callbacks. */ 85 | TMCLBKSLOT aClbkSlots[TM_TIMER_CALLBACK_SLOT_COUNT]; 86 | } TM; 87 | 88 | /** 89 | * Initialise the time keeping manager. 90 | * After this succeeded you can use TMTick() immediately. 91 | * 92 | * @returns Status code. 93 | * @param pTm The timekeeping manager to initialise. 94 | */ 95 | int TMInit(PTM pTm); 96 | 97 | /** 98 | * Advances the clock of the timekeeping manager by one tick and 99 | * calls all expired callbacks. 100 | * 101 | * @note: This should be called every microsecond to get an accurate time source. 102 | * 103 | * @returns nothing. 104 | * @param pTm The timekeeping manager to use. 105 | */ 106 | void TMTick(PTM pTm); 107 | 108 | /** 109 | * Advances the clock of the timekeeping manager by the given amount of ticks and 110 | * calls all expired callbacks. 111 | * 112 | * @returns nothing. 113 | * @param pTm The timekeeping manager to use. 114 | * @param cMicroSecs Number of microseconds to advance the clock. 115 | * 116 | * @note Timers are only run once after the milliseconds where updated. 117 | */ 118 | void TMTickMultiple(PTM pTm, uint64_t cMicroSecs); 119 | 120 | /** 121 | * Return the current microseconds value since the clock started ticking. 122 | * 123 | * @returns Number of microseconds since the clock started. 124 | * @param pTm The timekeeping manager to use. 125 | */ 126 | uint64_t TMGetMicros(PTM pTm); 127 | 128 | /** 129 | * Return the current milliseconds value since the clock started ticking. 130 | * 131 | * @returns Number of milliseconds since the clock started. 132 | * @param pTm The timekeeping manager to use. 133 | */ 134 | uint32_t TMGetMillies(PTM pTm); 135 | 136 | /** 137 | * Delay execution for the given amount of milliseconds. 138 | * 139 | * @returns nothing. 140 | * @param pTm The timekeeping manager to use. 141 | * @param cMillies Amount of milliseconds to delay. 142 | */ 143 | void TMDelayMillies(PTM pTm, uint32_t cMillies); 144 | 145 | /** 146 | * Delay execution for the given amount of microseconds. 147 | * 148 | * @returns nothing. 149 | * @param pTm The timekeeping manager to use. 150 | * @param cMicros Amount of microseconds to delay. 151 | */ 152 | void TMDelayMicros(PTM pTm, uint64_t cMicros); 153 | 154 | /** 155 | * Register a new timer callback with the timekeeping manager. 156 | * 157 | * @returns status code. 158 | * @retval ERR_TM_OUT_OF_SLOTS if there is no empty slot left. 159 | * @param pTm The timekeeping manager to use. 160 | * @param pfnTmClbk The callback to call. 161 | * @param pvUser Opaque user data to pass in the callback. 162 | * @param ppTmSlot Where to store the pointer to the slot on success. 163 | */ 164 | int TMCallbackRegister(PTM pTm, PFNTMCLBK pfnTmClbk, void *pvUser, PTMCLBKSLOT *ppTmSlot); 165 | 166 | /** 167 | * Deregister the given timer slot. 168 | * 169 | * @returns status code. 170 | * @param pTm The timekeeping manager to use. 171 | * @param pTmSlot The slot to deregister. 172 | * 173 | * @note Never ever deregister a timer slot in a timer callback 174 | * and make sure that TMTick() is not called during that operation. 175 | */ 176 | int TMCallbackDeregister(PTM pTm, PTMCLBKSLOT pTmSlot); 177 | 178 | /** 179 | * Sets the expiration timer for the given slot to the absolute amount of 180 | * milliseconds since the clock started ticking. 181 | * 182 | * @returns status code. 183 | * @param pTm The timekeeping manager to use. 184 | * @param pTmSlot The timer slot to set the expiration for. 185 | * @param cMillies The absolute amount in milliseconds when the timer should expire. 186 | */ 187 | int TMCallbackSetExpirationAbsolute(PTM pTm, PTMCLBKSLOT pTmSlot, uint32_t cMillies); 188 | 189 | /** 190 | * Sets the expiration timer for the given slot to the relative amount of 191 | * milliseconds starting from the current clock value. 192 | * 193 | * @returns status code. 194 | * @param pTm The timekeeping manager to use. 195 | * @param pTmSlot The timer slot to set the expiration for. 196 | * @param cMillies The relative amount in milliseconds when the timer should expire. 197 | */ 198 | int TMCallbackSetExpirationRelative(PTM pTm, PTMCLBKSLOT pTmSlot, uint32_t cMillies); 199 | 200 | /** 201 | * Stops the timer on the given slot. 202 | * 203 | * @returns status code. 204 | * @param pTm The timekeeping manager to use. 205 | * @param pTmSlot The timer slot to stop. 206 | */ 207 | int TMCallbackStop(PTM pTm, PTMCLBKSLOT pTmSlot); 208 | 209 | #endif /* __tm_h */ 210 | -------------------------------------------------------------------------------- /Lib/include/types.h: -------------------------------------------------------------------------------- 1 | /** @file 2 | * General types 3 | */ 4 | 5 | /* 6 | * Copyright (C) 2019 Alexander Eichner 7 | * 8 | * This library is free software; you can redistribute it and/or 9 | * modify it under the terms of the GNU Lesser General Public 10 | * License as published by the Free Software Foundation; either 11 | * version 2.1 of the License, or (at your option) any later version. 12 | * 13 | * This library is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 16 | * Lesser General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU Lesser General Public 19 | * License along with this library; if not, write to the Free Software 20 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 21 | */ 22 | #ifndef __types_h 23 | #define __types_h 24 | 25 | #include 26 | 27 | /** 28 | * IRQ exception frame. 29 | */ 30 | typedef struct PSPIRQREGFRAME 31 | { 32 | /** Saved GPRs. */ 33 | uint32_t aGprs[13]; 34 | /** SPSR register */ 35 | uint32_t uRegSpsr; 36 | /** LR register. */ 37 | uint32_t uRegLr; 38 | } PSPIRQREGFRAME; 39 | /** Pointer to the IRQ exception frame. */ 40 | typedef PSPIRQREGFRAME *PPSPIRQREGFRAME; 41 | 42 | #endif 43 | -------------------------------------------------------------------------------- /Lib/include/uart.h: -------------------------------------------------------------------------------- 1 | /** @file 2 | * PSP internal interfaces - UART driver. 3 | */ 4 | 5 | /* 6 | * Copyright (C) 2020 Alexander Eichner 7 | * 8 | * This library is free software; you can redistribute it and/or 9 | * modify it under the terms of the GNU Lesser General Public 10 | * License as published by the Free Software Foundation; either 11 | * version 2.1 of the License, or (at your option) any later version. 12 | * 13 | * This library is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 16 | * Lesser General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU Lesser General Public 19 | * License along with this library; if not, write to the Free Software 20 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 21 | */ 22 | #ifndef __include_uart_h 23 | #define __include_uart_h 24 | 25 | #if defined(IN_PSP) 26 | # include 27 | #else 28 | # error "Invalid environment" 29 | #endif 30 | 31 | #include 32 | 33 | 34 | /** 35 | * UART data bits config enum. 36 | */ 37 | typedef enum PSPUARTDATABITS 38 | { 39 | /** Invalid value, do not use. */ 40 | PSPUARTDATABITS_INVALID = 0, 41 | /** 8 data bits. */ 42 | PSPUARTDATABITS_8BITS, 43 | /** 32bit hack. */ 44 | PSPUARTDATABITS_32BIT_HACK = 0x7fffffff 45 | } PSPUARTDATABITS; 46 | 47 | 48 | /** 49 | * UART parity config enum. 50 | */ 51 | typedef enum PSPUARTPARITY 52 | { 53 | /** Invalid value, do not use. */ 54 | PSPUARTPARITY_INVALID = 0, 55 | /** No parity. */ 56 | PSPUARTPARITY_NONE, 57 | /** 32bit hack. */ 58 | PSPUARTPARITY_32BIT_HACK = 0x7fffffff 59 | } PSPUARTPARITY; 60 | 61 | 62 | /** 63 | * UART stop bits config enum. 64 | */ 65 | typedef enum PSPUARTSTOPBITS 66 | { 67 | /** Invalid value, do not use. */ 68 | PSPUARTSTOPBITS_INVALID = 0, 69 | /** 1 stop bit. */ 70 | PSPUARTSTOPBITS_1BIT, 71 | /** 32bit hack. */ 72 | PSPUARTSTOPBITS_32BIT_HACK = 0x7fffffff 73 | } PSPUARTSTOPBITS; 74 | 75 | 76 | /** 77 | * UART driver instance state, treat as private. 78 | */ 79 | typedef struct PSPUART 80 | { 81 | /** Pointer to the device I/O interface given during construction. */ 82 | PCPSPIODEVIF pIfDevIo; 83 | /** @todo State members. */ 84 | } PSPUART; 85 | /** Pointer to a UART driver instance. */ 86 | typedef PSPUART *PPSPUART; 87 | /** Pointer to a const UART driver instance. */ 88 | typedef const PSPUART *PCPSPUART; 89 | 90 | 91 | /** 92 | * Create a new UART driver instance. 93 | * 94 | * @returns Status code. 95 | * @param pUart Pointer to the uninitialized UART driver instance. 96 | * @param pIfDevIo The device I/O interface pointer. 97 | */ 98 | int PSPUartCreate(PPSPUART pUart, PCPSPIODEVIF pIfDevIo); 99 | 100 | 101 | /** 102 | * Destroys the given UART driver instance. 103 | * 104 | * @returns nothing. 105 | * @param pUart The UART driver instance to destroy. 106 | */ 107 | void PSPUartDestroy(PPSPUART pUart); 108 | 109 | 110 | /** 111 | * Sets the UART connection parameters. 112 | * 113 | * @returns Status code. 114 | * @param pUart The UART driver instance. 115 | * @param uBps Baud rate to configure. 116 | * @param enmDataBits Number of data bits to use. 117 | * @param enmParity The parity to use. 118 | * @param enmStopBits Number of stop bits to use. 119 | */ 120 | int PSPUartParamsSet(PPSPUART pUart, uint32_t uBps, PSPUARTDATABITS enmDataBits, 121 | PSPUARTPARITY enmParity, PSPUARTSTOPBITS enmStopBits); 122 | 123 | 124 | /** 125 | * Returns the number of bytes available for reading. 126 | * 127 | * @returns Number of bytes available for reading, 0 if nothing is available. 128 | * @param pUart The UART driver instance. 129 | */ 130 | size_t PSPUartGetDataAvail(PPSPUART pUart); 131 | 132 | 133 | /** 134 | * Returns the amount of bytes available in the transmitter queue. 135 | * 136 | * @returns Number of bytes available in the transmitter queue. 137 | * @param pUart The UART driver instance. 138 | */ 139 | size_t PSPUartGetTxSpaceAvail(PPSPUART pUart); 140 | 141 | 142 | /** 143 | * Read the given amount of data from the given UART device instance. 144 | * 145 | * @returns Status code. 146 | * @param pUart The UART driver instance. 147 | * @param pvBuf Where to store the read data. 148 | * @param cbRead Number of bytes to read. 149 | * @param pcbRead Where to store the number of bytes actually read, optional. 150 | */ 151 | int PSPUartRead(PPSPUART pUart, void *pvBuf, size_t cbRead, size_t *pcbRead); 152 | 153 | 154 | /** 155 | * Read the given amount of data from the given UART device instance - non blocking. 156 | * 157 | * @returns Status code. 158 | * @param pUart The UART driver instance. 159 | * @param pvBuf Where to store the read data. 160 | * @param cbRead Number of bytes to read. 161 | * @param pcbRead Where to store the number of bytes actually read. 162 | */ 163 | int PSPUartReadNB(PPSPUART pUart, void *pvBuf, size_t cbRead, size_t *pcbRead); 164 | 165 | 166 | /** 167 | * Write the given amount of data to the given UART device instance. 168 | * 169 | * @returns Status code. 170 | * @param pUart The UART driver instance. 171 | * @param pvBuf The data to write. 172 | * @param cbWrite Number of bytes to write. 173 | * @param pcbWritten Where to store the number of bytes actually written, optional. 174 | */ 175 | int PSPUartWrite(PPSPUART pUart, const void *pvBuf, size_t cbWrite, size_t *pcbWritten); 176 | 177 | 178 | /** 179 | * Write the given amount of data to the given UART device instance - non blocking. 180 | * 181 | * @returns Status code. 182 | * @param pUart The UART driver instance. 183 | * @param pvBuf The data to write. 184 | * @param cbWrite Number of bytes to write. 185 | * @param pcbWritten Where to store the number of bytes actually written. 186 | */ 187 | int PSPUartWriteNB(PPSPUART pUart, const void *pvBuf, size_t cbWrite, size_t *pcbWritten); 188 | 189 | 190 | #endif /* !__include_uart_h */ 191 | 192 | -------------------------------------------------------------------------------- /Lib/include/x86-map.h: -------------------------------------------------------------------------------- 1 | /** @file 2 | * PSP internal interfaces - UART driver. 3 | */ 4 | 5 | /* Copyright (C) 2020 Alexander Eichner 6 | * Copyright (C) 2020 Robert Buhren 7 | * 8 | * This library is free software; you can redistribute it and/or 9 | * modify it under the terms of the GNU Lesser General Public 10 | * License as published by the Free Software Foundation; either 11 | * version 2.1 of the License, or (at your option) any later version. 12 | * 13 | * This library is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 16 | * Lesser General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU Lesser General Public 19 | * License along with this library; if not, write to the Free Software 20 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 21 | */ 22 | #ifndef __include_x86_map_h 23 | #define __include_x86_map_h 24 | 25 | #include 26 | 27 | /** 28 | * x86 memory mapping slot. 29 | */ 30 | typedef struct PSPX86MAPPING 31 | { 32 | /** The base X86 address being mapped (aligned to a 64MB boundary). */ 33 | X86PADDR PhysX86AddrBase; 34 | /** The memory type being used. */ 35 | uint32_t uMemType; 36 | /** Reference counter for this mapping, the mapping gets cleaned up if it reaches 0. */ 37 | uint32_t cRefs; 38 | } PSPX86MAPPING; 39 | 40 | /** Pointer to an x86 memory mapping slot. */ 41 | typedef PSPX86MAPPING *PPSPX86MAPPING; 42 | 43 | /** Pointer to a const x86 memory mapping slot. */ 44 | typedef const PSPX86MAPPING *PCPSPX86MAPPING; 45 | 46 | /** 47 | * Maps the given x86 physical address into the PSP address space. 48 | * 49 | * @returns Status code. 50 | * @param PhysX86Addr The x86 physical address to map. 51 | * @param fMmio Flag whether this a MMIO address. 52 | * @param ppv Where to store the pointer to the mapping on success. 53 | */ 54 | int pspX86PhysMap(X86PADDR PhysX86Addr, bool fMmio, void **ppv); 55 | 56 | /** 57 | * Unmaps a previously mapped x86 physical address. 58 | * 59 | * @returns Status code. 60 | * @param pv Pointer to the mapping as returned by a successful call to pspStubX86PhysMap(). 61 | */ 62 | int pspX86PhysUnmapByPtr(void *pv); 63 | 64 | /** 65 | * Stores a 32 bit value at the provided x86 address. 66 | * 67 | * @param PhysX86Addr x86 target address. 68 | * @param u32Val Value to store at "PhysX86Addr". 69 | */ 70 | void pspX86MmioWriteU32(X86PADDR PhysX86Addr, uint32_t u32Val); 71 | 72 | /** 73 | * Stores a 8 bit value at the provided x86 address. 74 | * 75 | * @param PhysX86Addr x86 target address. 76 | * @param bVal Value to store at "PhysX86Addr". 77 | */ 78 | void pspX86MmioWriteU8(X86PADDR PhysX86Addr, uint8_t bVal); 79 | 80 | #endif /* !__include_x86_map_h */ 81 | -------------------------------------------------------------------------------- /Lib/include/x86mem.h: -------------------------------------------------------------------------------- 1 | /** @file 2 | * X86 host memory related APIs. 3 | */ 4 | 5 | /* 6 | * Copyright (C) 2019 Alexander Eichner 7 | * 8 | * This library is free software; you can redistribute it and/or 9 | * modify it under the terms of the GNU Lesser General Public 10 | * License as published by the Free Software Foundation; either 11 | * version 2.1 of the License, or (at your option) any later version. 12 | * 13 | * This library is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 16 | * Lesser General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU Lesser General Public 19 | * License along with this library; if not, write to the Free Software 20 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 21 | */ 22 | #ifndef ___x86mem_h 23 | #define ___x86mem_h 24 | 25 | #include 26 | 27 | /** 28 | * Fallback method to copy memory from the x86 host using svc 0x26 to copy 4 bytes at a time. 29 | */ 30 | int psp_x86_memory_copy_from_host_fallback(X86PADDR PhysX86AddrSrc, void *pvDst, size_t cbCopy); 31 | 32 | int psp_x86_mmio_read(X86PADDR PhysX86AddrSrc, void *pvDst, size_t cbRead); 33 | 34 | int psp_x86_mmio_write(X86PADDR PhysX86AddrDst, const void *pvSrc, size_t cbWrite); 35 | 36 | #endif /* ___x86mem_h */ 37 | -------------------------------------------------------------------------------- /Lib/src/checkpoint.S: -------------------------------------------------------------------------------- 1 | /** @file 2 | * PSP internal interfaces - Checkpoint API. 3 | */ 4 | 5 | /* 6 | * Copyright (C) 2020 Alexander Eichner 7 | * 8 | * This library is free software; you can redistribute it and/or 9 | * modify it under the terms of the GNU Lesser General Public 10 | * License as published by the Free Software Foundation; either 11 | * version 2.1 of the License, or (at your option) any later version. 12 | * 13 | * This library is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 16 | * Lesser General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU Lesser General Public 19 | * License along with this library; if not, write to the Free Software 20 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 21 | */ 22 | .section .text 23 | 24 | /* bool PSPCheckPointSet(PSPCHCKPT *pChkPt) */ 25 | .globl PSPCheckPointSet; 26 | PSPCheckPointSet: 27 | str r0, [r0] 28 | str r1, [r0, #4] 29 | str r2, [r0, #8] 30 | str r3, [r0, #12] 31 | str r4, [r0, #16] 32 | str r5, [r0, #20] 33 | str r6, [r0, #24] 34 | str r7, [r0, #28] 35 | str r8, [r0, #32] 36 | str r9, [r0, #36] 37 | str r10, [r0, #40] 38 | str r11, [r0, #44] 39 | str r12, [r0, #48] 40 | str sp, [r0, #52] 41 | str lr, [r0, #56] 42 | 43 | ldr r1, =_PSPCheckPointRestart; 44 | str r1, [r0, #60] 45 | mrs r1, cpsr 46 | str r1, [r0, #64] 47 | ldr r1, [r0, #4] 48 | mov r0, #1 49 | mov pc, lr 50 | 51 | _PSPCheckPointRestart: 52 | /* r0 should be restored at that point already and point to the checkpoint state to use. */ 53 | ldr r1, [r0, #4] 54 | ldr r2, [r0, #8] 55 | ldr r3, [r0, #12] 56 | ldr r4, [r0, #16] 57 | ldr r5, [r0, #20] 58 | ldr r6, [r0, #24] 59 | ldr r7, [r0, #28] 60 | ldr r8, [r0, #32] 61 | ldr r9, [r0, #36] 62 | ldr r10, [r0, #40] 63 | ldr r11, [r0, #44] 64 | ldr r12, [r0, #48] 65 | ldr sp, [r0, #52] 66 | ldr lr, [r0, #56] 67 | 68 | mov r0, #0 69 | mov pc, lr 70 | .type PSPCheckPointSet, %function; 71 | 72 | -------------------------------------------------------------------------------- /Lib/src/log.c: -------------------------------------------------------------------------------- 1 | /** @file 2 | * Logging API and macros - inspired by the VirtualBox IPRT Logging API which is really neat. 3 | */ 4 | 5 | /* 6 | * Copyright (C) 2013 Alexander Eichner 7 | * 8 | * This library is free software; you can redistribute it and/or 9 | * modify it under the terms of the GNU Lesser General Public 10 | * License as published by the Free Software Foundation; either 11 | * version 2.1 of the License, or (at your option) any later version. 12 | * 13 | * This library is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 16 | * Lesser General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU Lesser General Public 19 | * License along with this library; if not, write to the Free Software 20 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 21 | */ 22 | #include 23 | #include 24 | 25 | #include 26 | #include 27 | #include 28 | #include 29 | 30 | /** The default logging instance, one of the few global variables in the library 31 | * we can't avoid without making everything else more difficult. */ 32 | static PLOGGER g_pLoggerDef = NULL; 33 | 34 | /** 35 | * Flushes the given logging instance. 36 | * 37 | * @returns nothing. 38 | * @param pLogger The logger to flush. 39 | */ 40 | static void logLoggerFlush(PLOGGER pLogger) 41 | { 42 | if (pLogger->offScratch > 0) 43 | { 44 | pLogger->pfnFlush(pLogger->pvUser, (uint8_t *)&pLogger->achScratch[0], pLogger->offScratch); 45 | pLogger->offScratch = 0; 46 | } 47 | } 48 | 49 | /** 50 | * Appends a single character to the given logger instance. 51 | * 52 | * @returns nothing. 53 | * @param pLogger The logger instance. 54 | * @param ch The character to append. 55 | */ 56 | static void logLoggerAppendChar(PLOGGER pLogger, const char ch) 57 | { 58 | if (pLogger->offScratch == sizeof(pLogger->achScratch)) 59 | logLoggerFlush(pLogger); 60 | 61 | pLogger->achScratch[pLogger->offScratch] = ch; 62 | pLogger->offScratch++; 63 | } 64 | 65 | /** 66 | * Converts a given unsigned 32bit integer into a string and appends it to the scratch buffer. 67 | * 68 | * @returns nothing. 69 | * @param pLogger The logger instance. 70 | * @param u32 The value to log. 71 | * @param cDigits Minimum number of digits to log, if the number has fewer 72 | * the gap is prepended with 0. 73 | */ 74 | static void logLoggerAppendU32(PLOGGER pLogger, uint32_t u32, uint32_t cDigits) 75 | { 76 | char achDigits[] = "0123456789"; 77 | char aszBuf[32]; 78 | unsigned offBuf = 0; 79 | 80 | /** @todo: Optimize. */ 81 | 82 | while (u32) 83 | { 84 | uint8_t u8Val = u32 % 10; 85 | u32 /= 10; 86 | 87 | aszBuf[offBuf++] = achDigits[u8Val]; 88 | } 89 | 90 | /* Prepend 0. */ 91 | if (offBuf < cDigits) 92 | { 93 | while (cDigits - offBuf > 0) 94 | { 95 | logLoggerAppendChar(pLogger, '0'); 96 | cDigits--; 97 | } 98 | } 99 | 100 | while (offBuf-- > 0) 101 | logLoggerAppendChar(pLogger, aszBuf[offBuf]); 102 | } 103 | 104 | #if 0 105 | /** 106 | * Converts a given unsigned 64bit integer into a string and appends it to the scratch buffer. 107 | * 108 | * @returns nothing. 109 | * @param pLogger The logger instance. 110 | * @param u64 The value to log. 111 | * @param cDigits Minimum number of digits to log, if the number has fewer 112 | * the gap is prepended with 0. 113 | */ 114 | static void logLoggerAppendU64(PLOGGER pLogger, uint64_t u64, uint32_t cDigits) 115 | { 116 | char achDigits[] = "0123456789"; 117 | char aszBuf[32]; 118 | unsigned offBuf = 0; 119 | 120 | /** @todo: Optimize. */ 121 | 122 | while (u64) 123 | { 124 | uint8_t u8Val = u64 % 10; 125 | u64 /= 10; 126 | 127 | aszBuf[offBuf++] = achDigits[u8Val]; 128 | } 129 | 130 | /* Prepend 0. */ 131 | if (offBuf < cDigits) 132 | { 133 | while (cDigits - offBuf > 0) 134 | { 135 | logLoggerAppendChar(pLogger, '0'); 136 | cDigits--; 137 | } 138 | } 139 | 140 | while (offBuf-- > 0) 141 | logLoggerAppendChar(pLogger, aszBuf[offBuf]); 142 | } 143 | #endif 144 | 145 | /** 146 | * Converts a given unsigned 32bit integer into a string as hex and appends it to the scratch buffer. 147 | * 148 | * @returns nothing. 149 | * @param pLogger The logger instance. 150 | * @param u32 The value to log. 151 | * @param cDigits Minimum number of digits to log, if the number has fewer 152 | * the gap is prepended with 0. 153 | */ 154 | static void logLoggerAppendHexU32(PLOGGER pLogger, uint32_t u32, uint32_t cDigits) 155 | { 156 | char achDigits[] = "0123456789abcdef"; 157 | char aszBuf[10]; 158 | unsigned offBuf = 0; 159 | 160 | /** @todo: Optimize. */ 161 | 162 | while (u32) 163 | { 164 | uint8_t u8Val = u32 & 0xf; 165 | u32 >>= 4; 166 | 167 | aszBuf[offBuf++] = achDigits[u8Val]; 168 | } 169 | 170 | /* Prepend 0. */ 171 | if (offBuf < cDigits) 172 | { 173 | while (cDigits - offBuf > 0) 174 | { 175 | logLoggerAppendChar(pLogger, '0'); 176 | cDigits--; 177 | } 178 | } 179 | 180 | while (offBuf-- > 0) 181 | logLoggerAppendChar(pLogger, aszBuf[offBuf]); 182 | } 183 | 184 | /** 185 | * Converts a given unsigned 64bit integer into a string as hex and appends it to the scratch buffer. 186 | * 187 | * @returns nothing. 188 | * @param pLogger The logger instance. 189 | * @param u64 The value to log. 190 | * @param cDigits Minimum number of digits to log, if the number has fewer 191 | * the gap is prepended with 0. 192 | */ 193 | static void logLoggerAppendHexU64(PLOGGER pLogger, uint64_t u64, uint32_t cDigits) 194 | { 195 | char achDigits[] = "0123456789abcdef"; 196 | char aszBuf[20]; 197 | unsigned offBuf = 0; 198 | 199 | /** @todo: Optimize. */ 200 | 201 | while (u64) 202 | { 203 | uint8_t u8Val = u64 & 0xf; 204 | u64 >>= 4; 205 | 206 | aszBuf[offBuf++] = achDigits[u8Val]; 207 | } 208 | 209 | /* Prepend 0. */ 210 | if (offBuf < cDigits) 211 | { 212 | while (cDigits - offBuf > 0) 213 | { 214 | logLoggerAppendChar(pLogger, '0'); 215 | cDigits--; 216 | } 217 | } 218 | 219 | while (offBuf-- > 0) 220 | logLoggerAppendChar(pLogger, aszBuf[offBuf]); 221 | } 222 | 223 | /** 224 | * Converts a given signed 32bit integer into a string and appends it to the scratch buffer. 225 | * 226 | * @returns nothing. 227 | * @param pLogger The logger instance. 228 | * @param i32 The value to log. 229 | * @param cDigits Minimum number of digits to log, if the number has fewer 230 | * the gap is prepended with 0. 231 | */ 232 | static void logLoggerAppendS32(PLOGGER pLogger, int32_t i32, uint32_t cDigits) 233 | { 234 | /* Add sign? */ 235 | if (i32 < 0) 236 | { 237 | logLoggerAppendChar(pLogger, '-'); 238 | i32 = ABS(i32); 239 | } 240 | 241 | /* Treat as unsigned from here on. */ 242 | logLoggerAppendU32(pLogger, (uint32_t)i32, cDigits); 243 | } 244 | 245 | /** 246 | * Appends a given string to the logger instance. 247 | * 248 | * @returns nothing. 249 | * @param pLogger The logger instance. 250 | * @param psz The string to append. 251 | */ 252 | static void logLoggerAppendString(PLOGGER pLogger, const char *psz) 253 | { 254 | /** @todo: Optimize */ 255 | if (!psz) 256 | { 257 | logLoggerAppendString(pLogger, ""); 258 | return; 259 | } 260 | 261 | while (*psz) 262 | logLoggerAppendChar(pLogger, *psz++); 263 | } 264 | 265 | /** 266 | * Adds the log id and a timestamp to the logger. 267 | * 268 | * @returns nothing. 269 | * @param pLogger Logger instance to use. 270 | */ 271 | static void logLoggerAddLogIdAndTimestamp(PLOGGER pLogger) 272 | { 273 | if (pLogger->pTm) 274 | { 275 | uint32_t cMs = TMGetMillies(pLogger->pTm); 276 | if (pLogger->fFlags & LOG_LOGGER_INIT_FLAGS_TS_FMT_HHMMSS) 277 | { 278 | uint16_t uHour, uMin, uSec, uMs; 279 | 280 | uSec = MSEC_TO_SEC(cMs); 281 | uMs = MSEC_TO_SEC_REMAINDER(cMs); 282 | 283 | uMin = SEC_TO_MIN(uSec); 284 | uHour = MIN_TO_HOUR(uMin); 285 | 286 | uMin = MIN_TO_HOUR_REMAINDER(uMin); 287 | uSec = SEC_TO_MIN_REMAINDER(uSec); 288 | 289 | logLoggerAppendU32(pLogger, uHour, 2); 290 | logLoggerAppendChar(pLogger, ':'); 291 | logLoggerAppendU32(pLogger, uMin, 2); 292 | logLoggerAppendChar(pLogger, ':'); 293 | logLoggerAppendU32(pLogger, uSec, 2); 294 | logLoggerAppendChar(pLogger, '.'); 295 | logLoggerAppendU32(pLogger, uMs, 3); 296 | } 297 | else 298 | logLoggerAppendU32(pLogger, cMs, 6); 299 | logLoggerAppendChar(pLogger, ' '); 300 | } 301 | 302 | if (pLogger->pszLogId) 303 | { 304 | logLoggerAppendString(pLogger, pLogger->pszLogId); 305 | logLoggerAppendChar(pLogger, ' '); 306 | } 307 | } 308 | 309 | int LOGLoggerInit(PLOGGER pLogger, PFNLOGGERFLUSH pfnFlush, void *pvUser, 310 | const char *pszLogId, PTM pTm, uint32_t fFlags) 311 | { 312 | int rc = INF_SUCCESS; 313 | 314 | pLogger->offScratch = 0; 315 | pLogger->pszLogId = pszLogId; 316 | pLogger->pTm = pTm; 317 | pLogger->pfnFlush = pfnFlush; 318 | pLogger->pvUser = pvUser; 319 | pLogger->fFlags = LOG_LOGGER_FLAGS_NEW_LINE | fFlags; 320 | 321 | return rc; 322 | } 323 | 324 | PLOGGER LOGLoggerGetDefaultInstance(void) 325 | { 326 | return g_pLoggerDef; 327 | } 328 | 329 | PLOGGER LOGLoggerSetDefaultInstance(PLOGGER pLogger) 330 | { 331 | PLOGGER pLoggerOld = g_pLoggerDef; 332 | 333 | g_pLoggerDef = pLogger; 334 | 335 | return pLoggerOld; 336 | } 337 | 338 | void LOGLoggerV(PLOGGER pLogger, const char *pszFmt, va_list hArgs) 339 | { 340 | /* Try default logger if none is given. */ 341 | if (!pLogger) 342 | { 343 | if (!g_pLoggerDef) 344 | return; 345 | 346 | pLogger = g_pLoggerDef; 347 | } 348 | 349 | while (*pszFmt) 350 | { 351 | char ch = *pszFmt++; 352 | 353 | if (pLogger->fFlags & LOG_LOGGER_FLAGS_NEW_LINE) 354 | { 355 | logLoggerAddLogIdAndTimestamp(pLogger); 356 | pLogger->fFlags &= ~LOG_LOGGER_FLAGS_NEW_LINE; 357 | } 358 | 359 | switch (ch) 360 | { 361 | case '\n': 362 | { 363 | logLoggerAppendChar(pLogger, ch); 364 | pLogger->fFlags |= LOG_LOGGER_FLAGS_NEW_LINE; 365 | break; 366 | } 367 | case '%': 368 | { 369 | /* Format specifier. */ 370 | char chFmt = *pszFmt; 371 | pszFmt++; 372 | 373 | if (chFmt == '#') 374 | { 375 | logLoggerAppendString(pLogger, "0x"); 376 | chFmt = *pszFmt++; 377 | } 378 | 379 | switch (chFmt) 380 | { 381 | case '%': 382 | { 383 | logLoggerAppendChar(pLogger, '%'); 384 | break; 385 | } 386 | case 'u': 387 | { 388 | uint32_t u32 = va_arg(hArgs, uint32_t); 389 | logLoggerAppendU32(pLogger, u32, 1); 390 | break; 391 | } 392 | #if 0 393 | case 'U': 394 | { 395 | uint64_t u64 = va_arg(hArgs, uint64_t); 396 | logLoggerAppendU64(pLogger, u64, 1); 397 | break; 398 | } 399 | #endif 400 | case 'd': 401 | { 402 | int32_t i32 = va_arg(hArgs, int32_t); 403 | logLoggerAppendS32(pLogger, i32, 1); 404 | break; 405 | } 406 | case 's': 407 | { 408 | const char *psz = va_arg(hArgs, const char *); 409 | logLoggerAppendString(pLogger, psz); 410 | break; 411 | } 412 | case 'x': 413 | { 414 | uint32_t u32 = va_arg(hArgs, uint32_t); 415 | logLoggerAppendHexU32(pLogger, u32, 1); 416 | break; 417 | } 418 | case 'X': 419 | { 420 | uint64_t u64 = va_arg(hArgs, uint64_t); 421 | logLoggerAppendHexU64(pLogger, u64, 1); 422 | break; 423 | } 424 | case 'p': /** @todo: Works only on 32bit... */ 425 | { 426 | void *pv = va_arg(hArgs, void *); 427 | logLoggerAppendString(pLogger, "0x"); 428 | if (sizeof(void *) == 4) 429 | logLoggerAppendHexU32(pLogger, (uint32_t)pv, 8); 430 | #ifdef __AMD64__ 431 | else if (sizeof(void *) == 8) 432 | logLoggerAppendHexU64(pLogger, (uint64_t)pv, 16); 433 | #endif 434 | else 435 | logLoggerAppendString(pLogger, ""); 436 | } 437 | default: 438 | /** @todo: Ignore or assert? */ 439 | ; 440 | } 441 | break; 442 | } 443 | default: 444 | logLoggerAppendChar(pLogger, ch); 445 | } 446 | } 447 | 448 | logLoggerFlush(pLogger); 449 | } 450 | 451 | void LOGLogger(PLOGGER pLogger, const char *pszFmt, ...) 452 | { 453 | va_list hArgs; 454 | va_start(hArgs, pszFmt); 455 | 456 | LOGLoggerV(pLogger, pszFmt, hArgs); 457 | 458 | va_end(hArgs); 459 | } 460 | 461 | -------------------------------------------------------------------------------- /Lib/src/misc.c: -------------------------------------------------------------------------------- 1 | /** @file Miscellaneous functions. 2 | */ 3 | 4 | /* 5 | * Copyright (C) 2020 Alexander Eichner 6 | * Copyright (C) 2020 Robert Buhren 7 | * 8 | * This library is free software; you can redistribute it and/or 9 | * modify it under the terms of the GNU Lesser General Public 10 | * License as published by the Free Software Foundation; either 11 | * version 2.1 of the License, or (at your option) any later version. 12 | * 13 | * This library is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 16 | * Lesser General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU Lesser General Public 19 | * License along with this library; if not, write to the Free Software 20 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 21 | */ 22 | 23 | #include 24 | #include 25 | #include 26 | 27 | uint32_t pspGetPhysDieId(void) 28 | { 29 | void *pvMap = NULL; 30 | int rc = pspSmnMap(0x5a078, &pvMap); 31 | if (!rc) 32 | { 33 | uint32_t uVal; 34 | pspMmioAccess(&uVal, (void *)pvMap, sizeof(uint32_t)); 35 | pspSmnUnmapByPtr(pvMap); 36 | return uVal & 0x3; 37 | } 38 | 39 | return 0xffffffff; 40 | } 41 | -------------------------------------------------------------------------------- /Lib/src/platform.c: -------------------------------------------------------------------------------- 1 | /** @file Platform specific initialization routines. 2 | */ 3 | 4 | /* 5 | * Copyright (C) 2020 Alexander Eichner 6 | * Copyright (C) 2020 Robert Buhren 7 | * 8 | * This library is free software; you can redistribute it and/or 9 | * modify it under the terms of the GNU Lesser General Public 10 | * License as published by the Free Software Foundation; either 11 | * version 2.1 of the License, or (at your option) any later version. 12 | * 13 | * This library is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 16 | * Lesser General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU Lesser General Public 19 | * License along with this library; if not, write to the Free Software 20 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 21 | */ 22 | #include 23 | #include 24 | #include 25 | 26 | static void pspSOCInit(void) 27 | { 28 | pspX86MmioWriteU32(0xfffe000a3048, 0x0020ff00); 29 | pspX86MmioWriteU32(0xfffe000a30d0, 0x08fdff86); 30 | pspX86MmioWriteU8(0xfed81e77, 0x27); 31 | pspX86MmioWriteU32(0xfec20040, 0x0); 32 | pspX86MmioWriteU32(0xfffe000a3044, 0xc0); 33 | pspX86MmioWriteU32(0xfffe000a3048, 0x20ff07); 34 | pspX86MmioWriteU32(0xfffe000a3064, 0x1640); 35 | pspX86MmioWriteU32(0xfffe000a3000, 0xffffff00); 36 | pspX86MmioWriteU32(0xfffe000a30a0, 0xfec10002); 37 | pspX86MmioWriteU32(0xfed80300, 0xe3020b11); 38 | pspX86MmioWriteU8(0xfffdfc000072, 0x6); 39 | pspX86MmioWriteU8(0xfffdfc000072, 0x7); 40 | pspSmnWrU32(0x2dc58d0, 0x0c7c17cf); 41 | pspX86MmioWriteU32(0xfffe000a3044, 0xc0); 42 | pspX86MmioWriteU32(0xfffe000a3048, 0x20ff07); 43 | pspX86MmioWriteU32(0xfffe000a3064, 0x1640); 44 | } 45 | 46 | static void pspSuperIoInit_PrimeX370(void) 47 | { 48 | pspX86MmioWriteU8(0xfffdfc00002e, 0x87); 49 | pspX86MmioWriteU8(0xfffdfc00002e, 0x01); 50 | pspX86MmioWriteU8(0xfffdfc00002e, 0x55); 51 | pspX86MmioWriteU8(0xfffdfc00002e, 0x55); 52 | pspX86MmioWriteU8(0xfffdfc00002e, 0x07); 53 | pspX86MmioWriteU8(0xfffdfc00002f, 0x07); 54 | pspX86MmioWriteU8(0xfffdfc00002e, 0x24); 55 | pspX86MmioWriteU8(0xfffdfc00002f, 0x00); 56 | pspX86MmioWriteU8(0xfffdfc00002f, 0x10); 57 | pspX86MmioWriteU8(0xfffdfc00002e, 0x02); 58 | pspX86MmioWriteU8(0xfffdfc00002f, 0x02); 59 | pspX86MmioWriteU8(0xfffdfc00002e, 0x87); 60 | pspX86MmioWriteU8(0xfffdfc00002e, 0x01); 61 | pspX86MmioWriteU8(0xfffdfc00002e, 0x55); 62 | pspX86MmioWriteU8(0xfffdfc00002e, 0x55); 63 | pspX86MmioWriteU8(0xfffdfc00002e, 0x23); 64 | pspX86MmioWriteU8(0xfffdfc00002f, 0x40); 65 | pspX86MmioWriteU8(0xfffdfc00002f, 0x40); 66 | pspX86MmioWriteU8(0xfffdfc00002e, 0x07); 67 | pspX86MmioWriteU8(0xfffdfc00002f, 0x01); 68 | pspX86MmioWriteU8(0xfffdfc00002e, 0x61); 69 | pspX86MmioWriteU8(0xfffdfc00002f, 0xf8); 70 | pspX86MmioWriteU8(0xfffdfc00002e, 0x60); 71 | pspX86MmioWriteU8(0xfffdfc00002f, 0x03); 72 | pspX86MmioWriteU8(0xfffdfc00002e, 0x30); 73 | pspX86MmioWriteU8(0xfffdfc00002f, 0x01); 74 | pspX86MmioWriteU8(0xfffdfc00002e, 0x02); 75 | pspX86MmioWriteU8(0xfffdfc00002f, 0x02); 76 | } 77 | 78 | static void pspSuperIoInit_H11DSU_iN(void) 79 | { 80 | pspX86MmioWriteU8(0xfffdfc00002e, 0xa5); 81 | pspX86MmioWriteU8(0xfffdfc00002e, 0xa5); 82 | pspX86MmioWriteU8(0xfffdfc00002e, 0x7); 83 | pspX86MmioWriteU8(0xfffdfc00002f, 0x2); 84 | pspX86MmioWriteU8(0xfffdfc00002e, 0x61); 85 | pspX86MmioWriteU8(0xfffdfc00002f, 0xf8); 86 | pspX86MmioWriteU8(0xfffdfc00002e, 0x60); 87 | pspX86MmioWriteU8(0xfffdfc00002f, 0x3); 88 | pspX86MmioWriteU8(0xfffdfc00002e, 0x30); 89 | pspX86MmioWriteU8(0xfffdfc00002f, 0x1); 90 | pspX86MmioWriteU8(0xfffdfc00002e, 0xaa); 91 | } 92 | 93 | void pspPlatformInit(void) 94 | { 95 | pspSOCInit(); 96 | #if TARGET == TARGET_PRIME_X370 97 | pspSuperIoInit_PrimeX370(); 98 | #elif TARGET == TARGET_H11DSU_IN 99 | pspSuperIoInit_H11DSU_iN(); 100 | #else 101 | #error "Invalid target platform" 102 | #endif 103 | 104 | } 105 | -------------------------------------------------------------------------------- /Lib/src/smn-map.c: -------------------------------------------------------------------------------- 1 | /** @file SMN mapping driver. 2 | */ 3 | 4 | /* 5 | * Copyright (C) 2020 Alexander Eichner 6 | * Copyright (C) 2020 Robert Buhren 7 | * 8 | * This library is free software; you can redistribute it and/or 9 | * modify it under the terms of the GNU Lesser General Public 10 | * License as published by the Free Software Foundation; either 11 | * version 2.1 of the License, or (at your option) any later version. 12 | * 13 | * This library is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 16 | * Lesser General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU Lesser General Public 19 | * License along with this library; if not, write to the Free Software 20 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 21 | */ 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | 30 | /** SMN mapping bookeeping data. */ 31 | static PSPSMNMAPPING g_aSmnMapSlots[32]; 32 | static uint32_t g_u32SmnInitialized = 0; 33 | 34 | static void pspSmnMapInit(void) { 35 | memset(g_aSmnMapSlots, 0, sizeof(g_aSmnMapSlots)); 36 | g_u32SmnInitialized = 1; 37 | } 38 | 39 | int pspSmnMap(SMNADDR SmnAddr, void **ppv) 40 | { 41 | int rc = INF_SUCCESS; 42 | 43 | if (!g_u32SmnInitialized) 44 | pspSmnMapInit(); 45 | 46 | /* Split physical address into 1MB aligned base and offset. */ 47 | SMNADDR SmnAddrBase = (SmnAddr & ~(_1M - 1)); 48 | uint32_t offStart = SmnAddr - SmnAddrBase; 49 | 50 | PPSPSMNMAPPING pMapping = NULL; 51 | uint32_t idxSlot = 0; 52 | for (uint32_t i = 0; i < ELEMENTS(g_aSmnMapSlots); i++) 53 | { 54 | if ( ( g_aSmnMapSlots[i].SmnAddrBase == 0 55 | && g_aSmnMapSlots[i].cRefs == 0) 56 | || g_aSmnMapSlots[i].SmnAddrBase == SmnAddrBase) 57 | { 58 | pMapping = &g_aSmnMapSlots[i]; 59 | idxSlot = i; 60 | break; 61 | } 62 | } 63 | 64 | if (pMapping) 65 | { 66 | if (pMapping->SmnAddrBase == 0) 67 | { 68 | /* Set up the mapping. */ 69 | pMapping->SmnAddrBase = SmnAddrBase; 70 | 71 | /* Program base address. */ 72 | PSPADDR PspAddrSlotBase = 0x03220000 + (idxSlot / 2) * sizeof(uint32_t); 73 | uint32_t u32RegSmnMapCtrl = *(volatile uint32_t *)PspAddrSlotBase; 74 | if (idxSlot & 0x1) 75 | u32RegSmnMapCtrl |= ((SmnAddrBase >> 20) << 16); 76 | else 77 | u32RegSmnMapCtrl |= SmnAddrBase >> 20; 78 | *(volatile uint32_t *)PspAddrSlotBase = u32RegSmnMapCtrl; 79 | } 80 | 81 | pMapping->cRefs++; 82 | *ppv = (void *)(0x01000000 + idxSlot * _1M + offStart); 83 | } 84 | else 85 | rc = ERR_INVALID_STATE; 86 | 87 | return rc; 88 | } 89 | 90 | int pspSmnUnmapByPtr(void *pv) 91 | { 92 | int rc = INF_SUCCESS; 93 | 94 | if (!g_u32SmnInitialized) 95 | return ERR_INVALID_STATE; 96 | 97 | uintptr_t PspAddrMapBase = ((uintptr_t)pv) & ~(_1M - 1); 98 | PspAddrMapBase -= 0x01000000; 99 | 100 | uint32_t idxSlot = PspAddrMapBase / _1M; 101 | if ( idxSlot < ELEMENTS(g_aSmnMapSlots) 102 | && PspAddrMapBase % _1M == 0) 103 | { 104 | PPSPSMNMAPPING pMapping = &g_aSmnMapSlots[idxSlot]; 105 | 106 | if (pMapping->cRefs > 0) 107 | { 108 | pMapping->cRefs--; 109 | 110 | /* Clear out the mapping if there is no reference held. */ 111 | if (!pMapping->cRefs) 112 | { 113 | pMapping->SmnAddrBase = 0; 114 | 115 | PSPADDR PspAddrSlotBase = 0x03220000 + (idxSlot / 2) * sizeof(uint32_t); 116 | uint32_t u32RegSmnMapCtrl = *(volatile uint32_t *)PspAddrSlotBase; 117 | if (idxSlot & 0x1) 118 | u32RegSmnMapCtrl &= 0xffff; 119 | else 120 | u32RegSmnMapCtrl &= 0xffff0000; 121 | *(volatile uint32_t *)PspAddrSlotBase = u32RegSmnMapCtrl; 122 | } 123 | } 124 | else 125 | rc = ERR_INVALID_PARAMETER; 126 | } 127 | else 128 | rc = ERR_INVALID_PARAMETER; 129 | 130 | /*LogRel("pspStubSmnUnmapByPtr: pv=%p -> rc=%d\n", pv, rc);*/ 131 | return rc; 132 | } 133 | 134 | void pspSmnWrU32(SMNADDR SmnAddr, uint32_t u32Val) 135 | { 136 | void *pvMap = NULL; 137 | int rc = pspSmnMap(SmnAddr, &pvMap); 138 | if (!rc) 139 | { 140 | *(volatile uint32_t*) pvMap = u32Val; 141 | pspSmnUnmapByPtr(pvMap); 142 | } 143 | } 144 | -------------------------------------------------------------------------------- /Lib/src/string.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | size_t strlen(const char *pszStr) 4 | { 5 | size_t cch = 0; 6 | while (*pszStr++ != '\0') 7 | cch++; 8 | 9 | return cch; 10 | } 11 | 12 | void memset(void *pvDst, uint8_t ch, size_t cb) 13 | { 14 | if ( ((uintptr_t)pvDst & 3) 15 | || cb < sizeof(uint32_t)) 16 | { 17 | uint8_t *pb = (uint8_t *)pvDst; 18 | for (unsigned i = 0; i < cb; i++) 19 | *pb++ = ch; 20 | } 21 | else 22 | { 23 | /* A bit more optimized */ 24 | uint32_t *pu32Dst = (uint32_t *)pvDst; 25 | uint32_t dw = (ch << 24) | (ch << 16) | (ch << 8) | ch; 26 | 27 | while (cb >= sizeof(uint32_t)) 28 | { 29 | *pu32Dst++ = dw; 30 | cb -= sizeof(uint32_t); 31 | } 32 | 33 | uint8_t *pbDst = (uint8_t *)pu32Dst; 34 | switch (cb) 35 | { 36 | default: 37 | case 0: 38 | break; 39 | case 1: 40 | *pbDst = ch; 41 | break; 42 | case 2: 43 | *pbDst++ = ch; 44 | *pbDst = ch; 45 | break; 46 | case 3: 47 | *pbDst++ = ch; 48 | *pbDst++ = ch; 49 | *pbDst = ch; 50 | break; 51 | } 52 | } 53 | } 54 | 55 | void memcpy(void *pvDst, const void *pvSrc, size_t cb) 56 | { 57 | if ( cb < sizeof(uint32_t) 58 | || ((uintptr_t)pvDst & 3) 59 | || ((uintptr_t)pvSrc & 3)) 60 | { 61 | uint8_t *pbDst = (uint8_t *)pvDst; 62 | const uint8_t *pbSrc = (const uint8_t *)pvSrc; 63 | 64 | for (unsigned i = 0; i < cb; i++) 65 | *pbDst++ = *pbSrc++; 66 | } 67 | else 68 | { 69 | /* A bit more optimized */ 70 | uint32_t *pu32Dst = (uint32_t *)pvDst; 71 | const uint32_t *pu32Src = (const uint32_t *)pvSrc; 72 | 73 | while (cb >= sizeof(uint32_t)) 74 | { 75 | *pu32Dst++ = *pu32Src++; 76 | cb -= sizeof(uint32_t); 77 | } 78 | 79 | uint8_t *pbDst = (uint8_t *)pu32Dst; 80 | const uint8_t *pbSrc = (uint8_t *)pu32Src; 81 | switch (cb) 82 | { 83 | default: 84 | case 0: 85 | break; 86 | case 1: 87 | *pbDst = *pbSrc; 88 | break; 89 | case 2: 90 | *pbDst++ = *pbSrc++; 91 | *pbDst = *pbSrc; 92 | break; 93 | case 3: 94 | *pbDst++ = *pbSrc++; 95 | *pbDst++ = *pbSrc++; 96 | *pbDst = *pbSrc; 97 | break; 98 | } 99 | } 100 | } 101 | 102 | -------------------------------------------------------------------------------- /Lib/src/svc.S: -------------------------------------------------------------------------------- 1 | #include "../../include/psp-fw/svc_id.h" 2 | 3 | .section .text 4 | 5 | /* void svc_exit(unsigned int code) */ 6 | .globl svc_exit; 7 | svc_exit: 8 | svc #SVC_EXIT 9 | mov pc, lr 10 | .type svc_exit, %function; 11 | 12 | /* void svc_dbg_print(const char *pszStr) */ 13 | .globl svc_dbg_print; 14 | svc_dbg_print: 15 | svc #SVC_DBG_PRINT 16 | mov pc, lr 17 | .type svc_dbg_print, %function; 18 | 19 | /* void svc_get_dbg_key(char* sp_dst, char* dst, unsigned int length) */ 20 | .globl svc_get_dbg_key; 21 | svc_get_dbg_key: 22 | svc #SVC_GET_DBG_KEY 23 | mov pc, lr 24 | .type svc_get_dbg_key, %function; 25 | 26 | /* void svc_invalidate_mem(SVC_INV_MEM_OP enmOp, uint32_t fInsnMem, void *pvStart, uint32_t cbMem) */ 27 | .globl svc_invalidate_mem; 28 | svc_invalidate_mem: 29 | svc #SVC_CACHE_FLUSH 30 | mov pc, lr 31 | .type svc_invalidate_mem, %function; 32 | 33 | /* void *svc_get_state_buffer(size_t cbBuf) */ 34 | .globl svc_get_state_buffer; 35 | svc_get_state_buffer: 36 | svc #SVC_GET_STATE_BUFFER 37 | mov pc, lr 38 | .type svc_get_state_buffer, %function; 39 | 40 | /* uint32_t svc_x86_host_memory_copy_from(X86PADDR PhysX86AddrSrc, void *pvDst, size_t cbCopy) */ 41 | .globl svc_x86_host_memory_copy_from; 42 | svc_x86_host_memory_copy_from: 43 | svc #SVC_X86_HOST_MEMORY_COPY_FROM 44 | mov pc, lr 45 | .type svc_x86_host_memory_copy_from, %function; 46 | 47 | /* void *svc_x86_host_memory_map(X86PADDR PhysX86AddrMap, uint32_t enmMemType) */ 48 | .globl svc_x86_host_memory_map; 49 | svc_x86_host_memory_map: 50 | svc #SVC_X86_HOST_MEMORY_MAP 51 | mov pc, lr 52 | .type svc_x86_host_memory_map, %function; 53 | 54 | /* uint32_t svc_x86_host_memory_unmap(void *pvMapped) */ 55 | .globl svc_x86_host_memory_unmap; 56 | svc_x86_host_memory_unmap: 57 | svc #SVC_X86_HOST_MEMORY_UNMAP 58 | mov pc, lr 59 | .type svc_x86_host_memory_unmap, %function; 60 | 61 | /* uint32_t svc_query_two_64bit_values(uint64_t *pu64Val1, uint64_t *pu64Val2) */ 62 | .globl svc_query_two_64bit_values; 63 | svc_query_two_64bit_values: 64 | svc #SVC_QUERY_TWO_64BIT_VALS 65 | mov pc, lr 66 | .type svc_query_two_64bit_values, %function; 67 | 68 | /* uint16_t svc_x86_host_memory_copy_to_psp(PPSPX86MEMCOPYREQ pReq) */ 69 | .globl svc_x86_host_memory_copy_to_psp; 70 | svc_x86_host_memory_copy_to_psp: 71 | svc #SVC_X86_HOST_COPY_TO_PSP 72 | mov pc, lr 73 | .type svc_x86_host_memory_copy_to_psp, %function; 74 | 75 | /* uint16_t svc_x86_host_memory_copy_from_psp(PPSPX86MEMCOPYREQ pReq) */ 76 | .globl svc_x86_host_memory_copy_from_psp; 77 | svc_x86_host_memory_copy_from_psp: 78 | svc #SVC_X86_HOST_COPY_FROM_PSP 79 | mov pc, lr 80 | .type svc_x86_host_memory_copy_from_psp, %function; 81 | 82 | /* uint32_t svc_call_other_psp(uint32_t idCcx, void *pvReq, size_t cbReq) */ 83 | .globl svc_call_other_psp; 84 | svc_call_other_psp: 85 | svc #SVC_CALL_OTHER_PSP 86 | mov pc, lr 87 | .type svc_call_other_psp, %function; 88 | 89 | /* void * svc_smn_map_ex(uint32_t u32SmnAddr, uint32_t idCcxTgt) */ 90 | .globl svc_smn_map_ex; 91 | svc_smn_map_ex: 92 | svc #SVC_SMN_MAP_ADDR_EX 93 | mov pc, lr 94 | .type svc_smn_map_ex, %function; 95 | 96 | /* uint32_t svc_smn_unmap(void *pvUnmap) */ 97 | .globl svc_smn_unmap; 98 | svc_smn_unmap: 99 | svc #SVC_SMN_UNMAP_ADDR 100 | mov pc, lr 101 | .type svc_smn_unmap, %function; 102 | 103 | .globl svc_unknown_id_16; 104 | svc_unknown_id_16: 105 | svc #SVC_UNKNOWN_ID_16 106 | mov pc, lr 107 | .type svc_unknown_id_16, %function 108 | 109 | .globl svc_unknown_id_4b; 110 | svc_unknown_id_4b: 111 | svc #SVC_UNKNOWN_ID_4b 112 | mov pc, lr 113 | .type svc_unknown_id_4b, %function 114 | 115 | .globl svc_load_app; 116 | svc_load_app: 117 | svc #SVC_FFS_ENTRY_READ 118 | mov pc, lr 119 | .type svc_load_app, %function 120 | 121 | /* void *svc_injected_map_x86_host_memory_ex(X86PADDR PhysX86AddrMap, uint32_t enmType, uint32_t fFlags) */ 122 | .globl svc_injected_map_x86_host_memory_ex; 123 | svc_injected_map_x86_host_memory_ex: 124 | svc #SVC_INJECTED_MAP_X86_HOST_MEMORY_EX 125 | mov pc, lr 126 | .type svc_injected_map_x86_host_memory_ex, %function; 127 | 128 | /* void svc_log_char_buf(const char *pbBuf, size_t cchBuf) */ 129 | .globl svc_log_char_buf; 130 | svc_log_char_buf: 131 | svc #SVC_LOG_CHAR_BUF 132 | mov pc, lr 133 | .type svc_log_char_buf, %function; 134 | 135 | /* uint32_t svc_dbg_marker_1(void) */ 136 | .globl svc_dbg_marker_1; 137 | svc_dbg_marker_1: 138 | svc #SVC_INJECTED_DBG_MARKER_1 139 | mov pc, lr 140 | .type svc_dbg_marker_1, %function; 141 | 142 | /* uint32_t svc_dbg_marker_2(void) */ 143 | .globl svc_dbg_marker_2; 144 | svc_dbg_marker_2: 145 | svc #SVC_INJECTED_DBG_MARKER_2 146 | mov pc, lr 147 | .type svc_dbg_marker_2, %function; 148 | 149 | /* uint32_t svc_dbg_marker_3(void) */ 150 | .globl svc_dbg_marker_3; 151 | svc_dbg_marker_3: 152 | svc #SVC_INJECTED_DBG_MARKER_3 153 | mov pc, lr 154 | .type svc_dbg_marker_3, %function; 155 | 156 | /* uint32_t svc_dbg_marker_4(void) */ 157 | .globl svc_dbg_marker_4; 158 | svc_dbg_marker_4: 159 | svc #SVC_INJECTED_DBG_MARKER_4 160 | mov pc, lr 161 | .type svc_dbg_marker_4, %function; 162 | 163 | /* uint32_t svc_dbg_marker_5(void) */ 164 | .globl svc_dbg_marker_5; 165 | svc_dbg_marker_5: 166 | svc #SVC_INJECTED_DBG_MARKER_5 167 | mov pc, lr 168 | .type svc_dbg_marker_5, %function; 169 | 170 | /* uint32_t svc_template(uint32_t u32R0, uint32_t u32R1, uint32_t u32R2, uint32_t u32R3) */ 171 | .globl svc_template; 172 | svc_template: 173 | svc #SVC_CALL_INVALID 174 | mov pc, lr 175 | .type svc_template, %function; 176 | 177 | -------------------------------------------------------------------------------- /Lib/src/tm.c: -------------------------------------------------------------------------------- 1 | /** @file 2 | * TM - Timkeeping manager API. 3 | */ 4 | 5 | /* 6 | * Copyright (C) 2013 Alexander Eichner 7 | * 8 | * This library is free software; you can redistribute it and/or 9 | * modify it under the terms of the GNU Lesser General Public 10 | * License as published by the Free Software Foundation; either 11 | * version 2.1 of the License, or (at your option) any later version. 12 | * 13 | * This library is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 16 | * Lesser General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU Lesser General Public 19 | * License along with this library; if not, write to the Free Software 20 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 21 | */ 22 | 23 | #include 24 | #include 25 | #include 26 | 27 | /** 28 | * Runs the timer slots. 29 | * 30 | * @returns nothing. 31 | * @param pTm The timekeeping manager. 32 | */ 33 | static void tmRunSlots(PTM pTm) 34 | { 35 | uint32_t cMillies = TMGetMillies(pTm); 36 | 37 | for (unsigned i = 0; i < pTm->cTimerCallbacks; i++) 38 | { 39 | PTMCLBKSLOT pSlot = &pTm->aClbkSlots[i]; 40 | 41 | if ( pSlot->cMilliesNext != TM_TIMER_CALLBACK_DISABLED 42 | && pSlot->cMilliesNext <= cMillies) 43 | { 44 | /* Stop timer first, callee has to enable it again if required. */ 45 | pSlot->cMilliesNext = TM_TIMER_CALLBACK_DISABLED; 46 | pSlot->pfnTmClbk(pTm, pSlot, pSlot->pvUser); 47 | } 48 | } 49 | } 50 | 51 | int TMInit(PTM pTm) 52 | { 53 | pTm->cMicroSec = 0; 54 | pTm->cTimerCallbacks = 0; 55 | 56 | for (unsigned i = 0; i < TM_TIMER_CALLBACK_SLOT_COUNT; i++) 57 | { 58 | PTMCLBKSLOT pSlot = &pTm->aClbkSlots[i]; 59 | 60 | pSlot->idxSlot = i; 61 | pSlot->cMilliesNext = TM_TIMER_CALLBACK_DISABLED; 62 | pSlot->pfnTmClbk = NULL; 63 | pSlot->pvUser = NULL; 64 | } 65 | 66 | return INF_SUCCESS; 67 | } 68 | 69 | void TMTick(PTM pTm) 70 | { 71 | pTm->cMicroSec++; 72 | 73 | /* Check for expired timers. */ 74 | tmRunSlots(pTm); 75 | } 76 | 77 | void TMTickMultiple(PTM pTm, uint64_t cMicroSecs) 78 | { 79 | pTm->cMicroSec += cMicroSecs; 80 | 81 | /* Check for expired timers. */ 82 | tmRunSlots(pTm); 83 | } 84 | 85 | uint64_t TMGetMicros(PTM pTm) 86 | { 87 | if (!pTm) 88 | return 0; 89 | 90 | return pTm->cMicroSec; 91 | } 92 | 93 | uint32_t TMGetMillies(PTM pTm) 94 | { 95 | if (!pTm) 96 | return 0; 97 | 98 | return (uint32_t)(pTm->cMicroSec / 1000); 99 | } 100 | 101 | void TMDelayMillies(PTM pTm, uint32_t cMillies) 102 | { 103 | uint32_t msStart, msEnd; 104 | 105 | msStart = TMGetMillies(pTm); 106 | msEnd = msStart + cMillies; 107 | 108 | if (msStart < msEnd) 109 | { 110 | while ( (TMGetMillies(pTm) >= msStart) && (TMGetMillies(pTm) < msEnd)); 111 | } 112 | else 113 | { 114 | while ( (TMGetMillies(pTm) >= msStart) || (TMGetMillies(pTm) < msEnd)); 115 | } 116 | } 117 | 118 | void TMDelayMicros(PTM pTm, uint64_t cMicros) 119 | { 120 | uint64_t tsStart, tsEnd; 121 | 122 | tsStart = TMGetMicros(pTm); 123 | tsEnd = tsStart + cMicros; 124 | 125 | if (tsStart < tsEnd) 126 | { 127 | while ( (TMGetMicros(pTm) >= tsStart) && (TMGetMicros(pTm) < tsEnd)); 128 | } 129 | else 130 | { 131 | while ( (TMGetMicros(pTm) >= tsStart) || (TMGetMicros(pTm) < tsEnd)); 132 | } 133 | } 134 | 135 | int TMCallbackRegister(PTM pTm, PFNTMCLBK pfnTmClbk, void *pvUser, PTMCLBKSLOT *ppTmSlot) 136 | { 137 | if (pTm->cTimerCallbacks == TM_TIMER_CALLBACK_SLOT_COUNT) 138 | return ERR_TM_OUT_OF_SLOTS; 139 | 140 | PTMCLBKSLOT pSlot = &pTm->aClbkSlots[pTm->cTimerCallbacks]; 141 | 142 | pTm->cTimerCallbacks++; 143 | pSlot->pfnTmClbk = pfnTmClbk; 144 | pSlot->pvUser = pvUser; 145 | *ppTmSlot = pSlot; 146 | 147 | return INF_SUCCESS; 148 | } 149 | 150 | int TMCallbackDeregister(PTM pTm, PTMCLBKSLOT pTmSlot) 151 | { 152 | return ERR_NOT_IMPLEMENTED; 153 | } 154 | 155 | int TMCallbackSetExpirationAbsolute(PTM pTm, PTMCLBKSLOT pTmSlot, uint32_t cMillies) 156 | { 157 | pTmSlot->cMilliesNext = cMillies; 158 | return INF_SUCCESS; 159 | } 160 | 161 | int TMCallbackSetExpirationRelative(PTM pTm, PTMCLBKSLOT pTmSlot, uint32_t cMillies) 162 | { 163 | pTmSlot->cMilliesNext = TMGetMillies(pTm) + cMillies; 164 | return INF_SUCCESS; 165 | } 166 | 167 | int TMCallbackStop(PTM pTm, PTMCLBKSLOT pTmSlot) 168 | { 169 | pTmSlot->cMilliesNext = TM_TIMER_CALLBACK_DISABLED; 170 | return INF_SUCCESS; 171 | } 172 | 173 | -------------------------------------------------------------------------------- /Lib/src/uart.c: -------------------------------------------------------------------------------- 1 | /** @file 2 | * Basic x86 UART device driver. 3 | */ 4 | 5 | /* 6 | * Copyright (C) 2020 Alexander Eichner 7 | * 8 | * This library is free software; you can redistribute it and/or 9 | * modify it under the terms of the GNU Lesser General Public 10 | * License as published by the Free Software Foundation; either 11 | * version 2.1 of the License, or (at your option) any later version. 12 | * 13 | * This library is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 16 | * Lesser General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU Lesser General Public 19 | * License along with this library; if not, write to the Free Software 20 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 21 | */ 22 | 23 | #include 24 | 25 | #include 26 | #include 27 | 28 | 29 | /** 30 | * Sets the UART divisor. 31 | * 32 | * @returns Status code. 33 | * @param pUart The UART driver instance. 34 | * @param uDivisor The divisor to set. 35 | */ 36 | static int pspUartDivisorSet(PPSPUART pUart, uint32_t uDivisor) 37 | { 38 | uint8_t uDivLatchL = uDivisor & 0xff; 39 | uint8_t uDivLatchH = (uDivisor >> 8) & 0xff; 40 | 41 | /* Read LCR and set DLAB. */ 42 | uint8_t uLcr = 0; 43 | int rc = PSPIoDevRegRead(pUart->pIfDevIo, X86_UART_REG_LCR_OFF, &uLcr, sizeof(uLcr)); 44 | if (rc == INF_SUCCESS) 45 | { 46 | uLcr |= X86_UART_REG_LCR_DLAB; 47 | rc = PSPIoDevRegWrite(pUart->pIfDevIo, X86_UART_REG_LCR_OFF, &uLcr, sizeof(uLcr)); 48 | if (rc == INF_SUCCESS) 49 | { 50 | rc = PSPIoDevRegWrite(pUart->pIfDevIo, X86_UART_REG_DL_LSB_OFF, &uDivLatchL, sizeof(uDivLatchL)); 51 | if (rc == INF_SUCCESS) 52 | rc = PSPIoDevRegWrite(pUart->pIfDevIo, X86_UART_REG_DL_MSB_OFF, &uDivLatchH, sizeof(uDivLatchH)); 53 | 54 | /* Clear DLAB again. */ 55 | uLcr &= ~X86_UART_REG_LCR_DLAB; 56 | int rc2 = PSPIoDevRegWrite(pUart->pIfDevIo, X86_UART_REG_LCR_OFF, &uLcr, sizeof(uLcr)); 57 | if (rc == INF_SUCCESS) 58 | rc = rc2; 59 | } 60 | } 61 | 62 | return rc; 63 | } 64 | 65 | 66 | int PSPUartCreate(PPSPUART pUart, PCPSPIODEVIF pIfDevIo) 67 | { 68 | pUart->pIfDevIo = pIfDevIo; 69 | 70 | /* Bring the device into a known state. */ 71 | 72 | /* Disable all interrupts. */ 73 | uint8_t uTmp = 0; 74 | int rc = PSPIoDevRegWrite(pIfDevIo, X86_UART_REG_IER_OFF, &uTmp, sizeof(uTmp)); 75 | if (rc == INF_SUCCESS) 76 | { 77 | /* Disable FIFO. */ 78 | rc = PSPIoDevRegWrite(pIfDevIo, X86_UART_REG_FCR_OFF, &uTmp, sizeof(uTmp)); 79 | if (rc == INF_SUCCESS) 80 | { 81 | /* Set known line parameters. */ 82 | rc = PSPUartParamsSet(pUart, 115200, PSPUARTDATABITS_8BITS, 83 | PSPUARTPARITY_NONE, PSPUARTSTOPBITS_1BIT); 84 | } 85 | } 86 | 87 | return rc; 88 | } 89 | 90 | 91 | void PSPUartDestroy(PPSPUART pUart) 92 | { 93 | pUart->pIfDevIo = NULL; 94 | } 95 | 96 | 97 | int PSPUartParamsSet(PPSPUART pUart, uint32_t uBps, PSPUARTDATABITS enmDataBits, 98 | PSPUARTPARITY enmParity, PSPUARTSTOPBITS enmStopBits) 99 | { 100 | uint32_t uDivisor = 115200 / uBps; /* For PC compatible UARTs using a 1.8432 MHz crystal. */ 101 | uint8_t uLcr = 0; 102 | 103 | switch (enmDataBits) 104 | { 105 | case PSPUARTDATABITS_8BITS: 106 | X86_UART_REG_LCR_WLS_SET(uLcr, X86_UART_REG_LCR_WLS_8); 107 | break; 108 | default: 109 | return ERR_INVALID_PARAMETER; 110 | } 111 | 112 | switch (enmParity) 113 | { 114 | case PSPUARTPARITY_NONE: 115 | uLcr &= ~X86_UART_REG_LCR_PEN; 116 | break; 117 | default: 118 | return ERR_INVALID_PARAMETER; 119 | } 120 | 121 | switch (enmStopBits) 122 | { 123 | case PSPUARTSTOPBITS_1BIT: 124 | uLcr &= ~X86_UART_REG_LCR_STB; 125 | break; 126 | default: 127 | return ERR_INVALID_PARAMETER; 128 | } 129 | 130 | int rc = PSPIoDevRegWrite(pUart->pIfDevIo, X86_UART_REG_LCR_OFF, &uLcr, sizeof(uLcr)); 131 | if (!rc) 132 | rc = pspUartDivisorSet(pUart, uDivisor); 133 | 134 | return rc; 135 | } 136 | 137 | 138 | size_t PSPUartGetDataAvail(PPSPUART pUart) 139 | { 140 | size_t cbAvail = 0; 141 | uint8_t uLsr = 0; 142 | int rc = PSPIoDevRegRead(pUart->pIfDevIo, X86_UART_REG_LSR_OFF, &uLsr, sizeof(uLsr)); 143 | if ( rc == INF_SUCCESS 144 | && uLsr & X86_UART_REG_LSR_DR) 145 | cbAvail++; 146 | 147 | return cbAvail; 148 | } 149 | 150 | 151 | size_t PSPUartGetTxSpaceAvail(PPSPUART pUart) 152 | { 153 | size_t cbAvail = 0; 154 | uint8_t uLsr = 0; 155 | int rc = PSPIoDevRegRead(pUart->pIfDevIo, X86_UART_REG_LSR_OFF, &uLsr, sizeof(uLsr)); 156 | if ( rc == INF_SUCCESS 157 | && uLsr & X86_UART_REG_LSR_THRE) 158 | cbAvail++; 159 | 160 | return cbAvail; 161 | } 162 | 163 | 164 | int PSPUartRead(PPSPUART pUart, void *pvBuf, size_t cbRead, size_t *pcbRead) 165 | { 166 | size_t cbActuallyRead = 0; 167 | uint8_t *pbBuf = (uint8_t *)pvBuf; 168 | int rc = INF_SUCCESS; 169 | 170 | do 171 | { 172 | while (PSPUartGetDataAvail(pUart) == 0); /* Wait until there is something to read. */ 173 | 174 | size_t cbThisRead = 0; 175 | rc = PSPUartReadNB(pUart, pbBuf, cbRead, &cbThisRead); 176 | if (rc != INF_SUCCESS) 177 | break; 178 | 179 | pbBuf += cbThisRead; 180 | cbRead -= cbThisRead; 181 | cbActuallyRead += cbThisRead; 182 | } while ( cbRead 183 | && rc == INF_SUCCESS); 184 | 185 | if ( rc == INF_SUCCESS 186 | && pcbRead) 187 | *pcbRead = cbActuallyRead; 188 | 189 | return rc; 190 | } 191 | 192 | 193 | int PSPUartReadNB(PPSPUART pUart, void *pvBuf, size_t cbRead, size_t *pcbRead) 194 | { 195 | int rc = INF_SUCCESS; 196 | 197 | *pcbRead = 0; 198 | 199 | if (PSPUartGetDataAvail(pUart) > 0) 200 | { 201 | rc = PSPIoDevRegRead(pUart->pIfDevIo, X86_UART_REG_RBR_OFF, pvBuf, 1); 202 | *pcbRead = 1; 203 | } 204 | else 205 | rc = INF_TRY_AGAIN; 206 | 207 | return rc; 208 | } 209 | 210 | 211 | int PSPUartWrite(PPSPUART pUart, const void *pvBuf, size_t cbWrite, size_t *pcbWritten) 212 | { 213 | size_t cbWritten = 0; 214 | const uint8_t *pbBuf = (const uint8_t *)pvBuf; 215 | int rc = INF_SUCCESS; 216 | 217 | do 218 | { 219 | while (PSPUartGetTxSpaceAvail(pUart) == 0); /* Wait until there is room to write. */ 220 | 221 | size_t cbThisWritten = 0; 222 | rc = PSPUartWriteNB(pUart, pbBuf, cbWrite, &cbThisWritten); 223 | if (rc != INF_SUCCESS) 224 | break; 225 | 226 | pbBuf += cbThisWritten; 227 | cbWrite -= cbThisWritten; 228 | cbWritten += cbThisWritten; 229 | } while ( cbWrite 230 | && rc == INF_SUCCESS); 231 | 232 | if ( rc == INF_SUCCESS 233 | && pcbWritten) 234 | *pcbWritten = cbWritten; 235 | 236 | return rc; 237 | } 238 | 239 | 240 | int PSPUartWriteNB(PPSPUART pUart, const void *pvBuf, size_t cbWrite, size_t *pcbWritten) 241 | { 242 | int rc = INF_SUCCESS; 243 | 244 | *pcbWritten = 0; 245 | 246 | if (PSPUartGetTxSpaceAvail(pUart) > 0) 247 | { 248 | rc = PSPIoDevRegWrite(pUart->pIfDevIo, X86_UART_REG_THR_OFF, pvBuf, 1); 249 | *pcbWritten = 1; 250 | } 251 | else 252 | rc = INF_TRY_AGAIN; 253 | 254 | return rc; 255 | } 256 | 257 | -------------------------------------------------------------------------------- /Lib/src/x86-map.c: -------------------------------------------------------------------------------- 1 | /** @file x86 mapping driver. 2 | */ 3 | 4 | /* 5 | * Copyright (C) 2020 Alexander Eichner 6 | * Copyright (C) 2020 Robert Buhren 7 | * 8 | * This library is free software; you can redistribute it and/or 9 | * modify it under the terms of the GNU Lesser General Public 10 | * License as published by the Free Software Foundation; either 11 | * version 2.1 of the License, or (at your option) any later version. 12 | * 13 | * This library is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 16 | * Lesser General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU Lesser General Public 19 | * License along with this library; if not, write to the Free Software 20 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 21 | */ 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | 29 | /** x86 mapping bookkeeping data. */ 30 | static PSPX86MAPPING g_aX86MapSlots[15]; 31 | static uint32_t g_u32X86Initialized = 0; 32 | 33 | static void pspX86MapInit(void) 34 | { 35 | memset(g_aX86MapSlots, 0, sizeof(g_aX86MapSlots)); 36 | for (uint32_t i = 0; i < ELEMENTS(g_aX86MapSlots); i++) 37 | g_aX86MapSlots[i].PhysX86AddrBase = NIL_X86PADDR; 38 | g_u32X86Initialized = 1; 39 | } 40 | 41 | int pspX86PhysMap(X86PADDR PhysX86Addr, bool fMmio, void **ppv) 42 | { 43 | int rc = INF_SUCCESS; 44 | if (!g_u32X86Initialized) 45 | pspX86MapInit(); 46 | uint32_t uMemType = fMmio ? 0x6 : 0x4; 47 | 48 | /* Split physical address into 64MB aligned base and offset. */ 49 | X86PADDR PhysX86AddrBase = (PhysX86Addr & ~(_64M - 1)); 50 | uint32_t offStart = PhysX86Addr - PhysX86AddrBase; 51 | 52 | PPSPX86MAPPING pMapping = NULL; 53 | uint32_t idxSlot = 0; 54 | for (uint32_t i = fMmio ? 8 : 0; i < ELEMENTS(g_aX86MapSlots); i++) 55 | { 56 | if ( ( g_aX86MapSlots[i].PhysX86AddrBase == NIL_X86PADDR 57 | && g_aX86MapSlots[i].cRefs == 0) 58 | || ( g_aX86MapSlots[i].PhysX86AddrBase == PhysX86AddrBase 59 | && g_aX86MapSlots[i].uMemType == uMemType)) 60 | { 61 | pMapping = &g_aX86MapSlots[i]; 62 | idxSlot = i; 63 | break; 64 | } 65 | } 66 | 67 | if (pMapping) 68 | { 69 | if (pMapping->PhysX86AddrBase == NIL_X86PADDR) 70 | { 71 | /* Set up the mapping. */ 72 | pMapping->uMemType = uMemType; 73 | pMapping->PhysX86AddrBase = PhysX86AddrBase; 74 | 75 | /* Program base address. */ 76 | PSPADDR PspAddrSlotBase = 0x03230000 + idxSlot * 4 * sizeof(uint32_t); 77 | *(volatile uint32_t *)PspAddrSlotBase = ((PhysX86AddrBase >> 32) << 6) | ((PhysX86AddrBase >> 26) & 0x3f); 78 | *(volatile uint32_t *)(PspAddrSlotBase + 4) = 0x12; /* Unknown but fixed value. */ 79 | *(volatile uint32_t *)(PspAddrSlotBase + 8) = uMemType; 80 | *(volatile uint32_t *)(PspAddrSlotBase + 12) = uMemType; 81 | *(volatile uint32_t *)(0x032303e0 + idxSlot * sizeof(uint32_t)) = 0xffffffff; 82 | *(volatile uint32_t *)(0x032304d8 + idxSlot * sizeof(uint32_t)) = 0xc0000000; 83 | *(volatile uint32_t *)0x32305ec = 0x3333; 84 | } 85 | 86 | asm volatile("dsb #0xf\nisb #0xf\n": : :"memory"); 87 | pMapping->cRefs++; 88 | *ppv = (void *)(0x04000000 + idxSlot * _64M + offStart); 89 | } 90 | else 91 | rc = ERR_INVALID_STATE; 92 | 93 | return rc; 94 | } 95 | 96 | int pspX86PhysUnmapByPtr(void *pv) 97 | { 98 | int rc = INF_SUCCESS; 99 | if (!g_u32X86Initialized) 100 | return ERR_INVALID_STATE; 101 | uintptr_t PspAddrMapBase = ((uintptr_t)pv) & ~(_64M - 1); 102 | PspAddrMapBase -= 0x04000000; 103 | 104 | uint32_t idxSlot = PspAddrMapBase / _64M; 105 | if ( idxSlot < ELEMENTS(g_aX86MapSlots) 106 | && PspAddrMapBase % _64M == 0) 107 | { 108 | PPSPX86MAPPING pMapping = &g_aX86MapSlots[idxSlot]; 109 | 110 | asm volatile("dsb #0xf\nisb #0xf\n": : :"memory"); 111 | if (pMapping->cRefs > 0) 112 | { 113 | pMapping->cRefs--; 114 | 115 | /* Clear out the mapping if there is no reference held. */ 116 | if (!pMapping->cRefs) 117 | { 118 | pMapping->uMemType = 0; 119 | pMapping->PhysX86AddrBase = NIL_X86PADDR; 120 | 121 | PSPADDR PspAddrSlotBase = 0x03230000 + idxSlot * 4 * sizeof(uint32_t); 122 | *(volatile uint32_t *)PspAddrSlotBase = 0; 123 | *(volatile uint32_t *)(PspAddrSlotBase + 4) = 0; /* Unknown but fixed value. */ 124 | *(volatile uint32_t *)(PspAddrSlotBase + 8) = 0; 125 | *(volatile uint32_t *)(PspAddrSlotBase + 12) = 0; 126 | *(volatile uint32_t *)(0x032303e0 + idxSlot * sizeof(uint32_t)) = 0xffffffff; 127 | *(volatile uint32_t *)(0x032304d8 + idxSlot * sizeof(uint32_t)) = 0; 128 | } 129 | } 130 | else 131 | rc = ERR_INVALID_PARAMETER; 132 | } 133 | else 134 | rc = ERR_INVALID_PARAMETER; 135 | 136 | return rc; 137 | } 138 | 139 | void pspX86MmioWriteU32(X86PADDR PhysX86Addr, uint32_t u32Val) 140 | { 141 | volatile uint32_t *pu32 = NULL; 142 | int rc = pspX86PhysMap(PhysX86Addr, true /*fMmio*/, (void **)&pu32); 143 | if (STS_SUCCESS(rc)) 144 | { 145 | *pu32 = u32Val; 146 | pspX86PhysUnmapByPtr((void *)pu32); 147 | } 148 | } 149 | 150 | void pspX86MmioWriteU8(X86PADDR PhysX86Addr, uint8_t bVal) 151 | { 152 | volatile uint8_t *pb = NULL; 153 | int rc = pspX86PhysMap(PhysX86Addr, true /*fMmio*/, (void **)&pb); 154 | if (STS_SUCCESS(rc)) 155 | { 156 | *pb = bVal; 157 | pspX86PhysUnmapByPtr((void *)pb); 158 | } 159 | } 160 | -------------------------------------------------------------------------------- /Lib/src/x86mem.c: -------------------------------------------------------------------------------- 1 | /** @file 2 | * X86 host memory related APIs. 3 | */ 4 | 5 | /* 6 | * Copyright (C) 2019 Alexander Eichner 7 | * 8 | * This library is free software; you can redistribute it and/or 9 | * modify it under the terms of the GNU Lesser General Public 10 | * License as published by the Free Software Foundation; either 11 | * version 2.1 of the License, or (at your option) any later version. 12 | * 13 | * This library is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 16 | * Lesser General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU Lesser General Public 19 | * License along with this library; if not, write to the Free Software 20 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 21 | */ 22 | 23 | #include 24 | #include 25 | #include 26 | 27 | 28 | int psp_x86_memory_copy_from_host_fallback(X86PADDR PhysX86AddrSrc, void *pvDst, size_t cbCopy) 29 | { 30 | int rc = INF_SUCCESS; 31 | size_t cbLeft = cbCopy; 32 | uint8_t *pbDst = (uint8_t *)pvDst; 33 | PSPX86MEMCOPYREQ Req; 34 | 35 | while (cbLeft >= 4) 36 | { 37 | Req.PhysX86AddrSrc = PhysX86AddrSrc; 38 | Req.pvDst = pbDst; 39 | Req.cbCopy = 4; 40 | Req.enmMemType = PSP_X86_MEM_TYPE_UNKNOWN_4; 41 | 42 | rc = svc_x86_host_memory_copy_to_psp(&Req); 43 | if (rc != PSPSTATUS_SUCCESS) 44 | break; 45 | 46 | pbDst += 4; 47 | cbLeft -= 4; 48 | PhysX86AddrSrc += 4; 49 | } 50 | 51 | if ( rc == PSPSTATUS_SUCCESS 52 | && cbLeft) 53 | { 54 | while (cbLeft) 55 | { 56 | Req.PhysX86AddrSrc = PhysX86AddrSrc; 57 | Req.pvDst = pbDst; 58 | Req.cbCopy = 1; 59 | Req.enmMemType = PSP_X86_MEM_TYPE_UNKNOWN_4; 60 | 61 | rc = svc_x86_host_memory_copy_to_psp(&Req); 62 | if (rc != PSPSTATUS_SUCCESS) 63 | break; 64 | 65 | pbDst += 1; 66 | cbLeft -= 1; 67 | PhysX86AddrSrc += 1; 68 | } 69 | } 70 | 71 | return rc; 72 | } 73 | 74 | 75 | int psp_x86_mmio_read(X86PADDR PhysX86AddrSrc, void *pvDst, size_t cbRead) 76 | { 77 | PSPX86MEMCOPYREQ Req; 78 | Req.PhysX86AddrSrc = PhysX86AddrSrc; 79 | Req.pvDst = pvDst; 80 | Req.cbCopy = cbRead; 81 | Req.enmMemType = PSP_X86_MEM_TYPE_UNKNOWN_6; 82 | 83 | return svc_x86_host_memory_copy_to_psp(&Req); 84 | } 85 | 86 | 87 | int psp_x86_mmio_write(X86PADDR PhysX86AddrDst, const void *pvSrc, size_t cbWrite) 88 | { 89 | PSPX86MEMCOPYREQ Req; 90 | Req.PhysX86AddrSrc = PhysX86AddrDst; 91 | Req.pvDst = (void *)pvSrc; 92 | Req.cbCopy = cbWrite; 93 | Req.enmMemType = PSP_X86_MEM_TYPE_UNKNOWN_6; 94 | 95 | return svc_x86_host_memory_copy_from_psp(&Req); 96 | } 97 | 98 | -------------------------------------------------------------------------------- /PspSerialStub/Makefile: -------------------------------------------------------------------------------- 1 | CROSS_COMPILE=arm-none-eabi- 2 | CFLAGS=-O2 -DIN_PSP -g -I../include -I../Lib/include -std=gnu99 -fomit-frame-pointer -nostartfiles -nostdlib -ffreestanding -Wextra -Werror -march=armv7-a -mthumb 3 | VPATH=../Lib/src 4 | LIBGCC=$(shell $(CROSS_COMPILE)gcc -print-libgcc-file-name) 5 | LDFLAGS=$(LIBGCC) 6 | 7 | 8 | OBJS = main.o thumb-interwork.o utils.o string.o log.o tm.o uart.o checkpoint.o pdu-transp-uart.o pdu-transp-spi-flash.o pdu-transp-spi-em100.o 9 | 10 | all : psp-serial-stub.elf psp-serial-stub.raw 11 | 12 | clean: 13 | rm -f _svc-start.o $(OBJS) 14 | 15 | %.o: %.c 16 | $(CROSS_COMPILE)gcc $(CFLAGS) -c -o $@ $^ 17 | 18 | %.o: %.S 19 | $(CROSS_COMPILE)gcc $(CFLAGS) -c -o $@ $^ 20 | 21 | _svc-start.o: ../Lib/_svc-start.S 22 | $(CROSS_COMPILE)as -march=armv7ve -o $@ $^ 23 | 24 | main.o: main.c 25 | $(CROSS_COMPILE)gcc $(CFLAGS) -c -o $@ main.c 26 | 27 | psp-serial-stub.elf : ../build/svc-linker.ld _svc-start.o $(OBJS) 28 | $(CROSS_COMPILE)ld -Map=psp-serial-stub.map -T $^ -o $@ $(LDFLAGS) 29 | 30 | psp-serial-stub.raw: psp-serial-stub.elf 31 | $(CROSS_COMPILE)objcopy -O binary $^ $@ 32 | 33 | 34 | -------------------------------------------------------------------------------- /PspSerialStub/pdu-transp-spi-em100.c: -------------------------------------------------------------------------------- 1 | /** @file 2 | * PSP app - SPI PDU transport channel when the Dediprog EM100 is used. 3 | */ 4 | 5 | /* 6 | * Copyright (C) 2020 Alexander Eichner 7 | * 8 | * This library is free software; you can redistribute it and/or 9 | * modify it under the terms of the GNU Lesser General Public 10 | * License as published by the Free Software Foundation; either 11 | * version 2.1 of the License, or (at your option) any later version. 12 | * 13 | * This library is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 16 | * Lesser General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU Lesser General Public 19 | * License along with this library; if not, write to the Free Software 20 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 21 | */ 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | 28 | #include 29 | #include 30 | 31 | #include "pdu-transp.h" 32 | #include "psp-serial-stub-internal.h" 33 | 34 | 35 | #define PSP_SPI_MASTER_SMN_ADDR 0x02dc4000 36 | #define PSP_SPI_MASTER_ALT_CS 0x1d 37 | #define PSP_SPI_MASTER_SPEED_EN 0x20 38 | #define PSP_SPI_MASTER_SPEED_CFG 0x22 39 | #define PSP_SPI_MASTER_CMD_CODE 0x45 40 | #define PSP_SPI_MASTER_CMD_TRIG 0x47 41 | # define PSP_SPI_MASTER_CMD_TRIG_BIT BIT(7) 42 | #define PSP_SPI_MASTER_TX_CNT 0x48 43 | #define PSP_SPI_MASTER_RX_CNT 0x4b 44 | #define PSP_SPI_MASTER_STATUS 0x4c 45 | # define PSP_SPI_MASTER_STATUS_BSY BIT(31) 46 | #define PSP_SPI_FIFO_START 0x80 47 | 48 | 49 | #define PSP_SPI_MASTER_CHUNK_SZ 64 50 | /** Upload FIFO size of the Dediprog EM100 in bytes. */ 51 | #define EM100_UFIFO_SZ 512 52 | 53 | /** 54 | * SPI flash transport channel. 55 | */ 56 | typedef struct PSPPDUTRANSPINT 57 | { 58 | /** SMN mapping for the SPI master. */ 59 | volatile void *pvSmnMap; 60 | /** Amount of data available for reading. */ 61 | size_t cbAvail; 62 | /** The read chunk. */ 63 | uint8_t abChunk[PSP_SPI_MASTER_CHUNK_SZ]; 64 | /** Offset into the chunk buffer. */ 65 | uint8_t offChunk; 66 | /** Chip select register value read during initialization. */ 67 | uint8_t bRegCs; 68 | /** */ 69 | uint32_t fSpiBridgeDisable; 70 | } PSPPDUTRANSPINT; 71 | /** Pointer to the x86 UART PDU transport channel instance. */ 72 | typedef PSPPDUTRANSPINT *PPSPPDUTRANSPINT; 73 | 74 | 75 | static inline void pspStubSpiMasterWriteRegU8(PPSPPDUTRANSPINT pThis, uint32_t offReg, uint8_t bVal) 76 | { 77 | *((volatile uint8_t *)pThis->pvSmnMap + offReg) = bVal; 78 | } 79 | 80 | 81 | static inline uint8_t pspStubSpiMasterReadRegU8(PPSPPDUTRANSPINT pThis, uint32_t offReg) 82 | { 83 | return *((volatile uint8_t *)pThis->pvSmnMap + offReg); 84 | } 85 | 86 | 87 | static inline void pspStubSpiMasterWriteRegU16(PPSPPDUTRANSPINT pThis, uint32_t offReg, uint16_t u16Val) 88 | { 89 | *(volatile uint16_t *)((volatile uint8_t *)pThis->pvSmnMap + offReg) = u16Val; 90 | } 91 | 92 | 93 | static inline void pspStubSpiMasterWriteRegU32(PPSPPDUTRANSPINT pThis, uint32_t offReg, uint32_t u32Val) 94 | { 95 | *(volatile uint32_t *)((volatile uint8_t *)pThis->pvSmnMap + offReg) = u32Val; 96 | } 97 | 98 | 99 | static inline uint32_t pspStubSpiMasterReadRegU32(PPSPPDUTRANSPINT pThis, uint32_t offReg) 100 | { 101 | return *(volatile uint32_t *)((volatile uint8_t *)pThis->pvSmnMap + offReg); 102 | } 103 | 104 | 105 | /** 106 | * Executes a single SPI transaction on the SPI master. 107 | * 108 | * @returns Status code. 109 | * @param pThis The EM100 transport channel instance. 110 | * @param bCmd The command byte. 111 | * @param pbTx The data to transfer. 112 | * @param cbTx Number of bytes to transmit. 113 | * @param pbRx Where to store the received bytes. 114 | * @param cbRx Number of bytes to receive. 115 | */ 116 | static int pspStubSpiMasterXact(PPSPPDUTRANSPINT pThis, uint8_t bCmd, uint8_t *pbTx, size_t cbTx, 117 | uint8_t *pbRx, size_t cbRx) 118 | { 119 | pspStubSpiMasterWriteRegU8(pThis, PSP_SPI_MASTER_CMD_CODE, bCmd); 120 | pspStubSpiMasterWriteRegU8(pThis, PSP_SPI_MASTER_TX_CNT, (uint8_t)cbTx); 121 | pspStubSpiMasterWriteRegU8(pThis, PSP_SPI_MASTER_RX_CNT, (uint8_t)cbRx); 122 | 123 | for (uint32_t i = 0; i < cbTx; i++) 124 | pspStubSpiMasterWriteRegU8(pThis, PSP_SPI_FIFO_START + i, pbTx[i]); 125 | 126 | pspStubSpiMasterWriteRegU8(pThis, PSP_SPI_MASTER_CMD_TRIG, PSP_SPI_MASTER_CMD_TRIG_BIT); /* Issues the transaction */ 127 | 128 | /* Wait until the master is idling. */ 129 | while (pspStubSpiMasterReadRegU32(pThis, PSP_SPI_MASTER_STATUS) & PSP_SPI_MASTER_STATUS_BSY); 130 | 131 | for (uint32_t i = 0; i < cbRx; i++) 132 | pbRx[i + cbTx] = pspStubSpiMasterReadRegU8(pThis, PSP_SPI_FIFO_START + cbTx + i); 133 | 134 | return INF_SUCCESS; 135 | } 136 | 137 | 138 | /** 139 | * Reads a given register from the EM100. 140 | * 141 | * @returns Status code. 142 | * @param pThis The EM100 transport channel instance. 143 | * @param idxReg Register index. 144 | * @param bReg The value to write. 145 | */ 146 | static int pspStubEm100RegWrite(PPSPPDUTRANSPINT pThis, uint8_t idxReg, uint8_t bReg) 147 | { 148 | uint8_t abCmd[3] = { 0 }; 149 | abCmd[1] = 0xa0 | (idxReg & 0xf); 150 | abCmd[2] = bReg; 151 | 152 | return pspStubSpiMasterXact(pThis, 0x11, &abCmd[0], sizeof(abCmd), 153 | NULL /*pbRx*/, 0 /*cbRx*/); 154 | } 155 | 156 | 157 | /** 158 | * Reads a given register from the EM100. 159 | * 160 | * @returns Status code. 161 | * @param pThis The EM100 transport channel instance. 162 | * @param idxReg Register index. 163 | * @param pbReg Where to store the read value on success. 164 | */ 165 | static int pspStubEm100RegRead(PPSPPDUTRANSPINT pThis, uint8_t idxReg, uint8_t *pbReg) 166 | { 167 | uint8_t abCmd[2] = { 0 }; 168 | uint8_t abRecv[4] = { 0 }; 169 | abCmd[1] = 0xb0 | (idxReg & 0xf); 170 | 171 | int rc = pspStubSpiMasterXact(pThis, 0x11, &abCmd[0], sizeof(abCmd), 172 | &abRecv[0], sizeof(abRecv)); 173 | if (!rc) 174 | *pbReg = abRecv[3]; 175 | 176 | return rc; 177 | } 178 | 179 | 180 | /** 181 | * Queries the number of bytes used in the uFIFO. 182 | * 183 | * @returns Status code. 184 | * @param pThis The EM100 transport channel instance. 185 | * @param pcbUsed Where to store the number of bytes used on success. 186 | */ 187 | static int pspStubEm100UFifoQueryUsed(PPSPPDUTRANSPINT pThis, size_t *pcbUsed) 188 | { 189 | *pcbUsed = 0; 190 | 191 | /* Check number of bytes used by reading the master and uFIFO length register. */ 192 | uint8_t bMainReg = 0; 193 | int rc = pspStubEm100RegRead(pThis, 0, &bMainReg); 194 | if ( !rc 195 | && (bMainReg & BIT(5)) == 0) /* At least one valid byte in upload FIFO? */ 196 | { 197 | uint8_t bUFifoLength = 0; 198 | rc = pspStubEm100RegRead(pThis, 1, &bUFifoLength); 199 | if (!rc) 200 | { 201 | bMainReg >>= 1; /* Get to the 8th bit of the uFIFO length. */ 202 | *pcbUsed = (((uint16_t)bMainReg & 1) << 8) | bUFifoLength; 203 | } 204 | } 205 | 206 | return rc; 207 | } 208 | 209 | 210 | /** 211 | * Queries the number of bytes free in the uFIFO. 212 | * 213 | * @returns Status code. 214 | * @param pThis The EM100 transport channel instance. 215 | * @param pcbUsed Where to store the number of bytes free on success. 216 | */ 217 | static int pspStubEm100UFifoQueryFree(PPSPPDUTRANSPINT pThis, size_t *pcbFree) 218 | { 219 | size_t cbUsed = 0; 220 | int rc = pspStubEm100UFifoQueryUsed(pThis, &cbUsed); 221 | if (!rc) 222 | *pcbFree = EM100_UFIFO_SZ - cbUsed; 223 | 224 | return rc; 225 | } 226 | 227 | 228 | /** 229 | * Queries the number of bytes available in the dFIFO. 230 | * 231 | * @returns Status code. 232 | * @param pThis The EM100 transport channel instance. 233 | * @param pcbAvail Where to store the number of bytes available on success. 234 | */ 235 | static int pspStubEm100DFifoQueryAvail(PPSPPDUTRANSPINT pThis, size_t *pcbAvail) 236 | { 237 | *pcbAvail = 0; 238 | 239 | /* Check number of bytes available by reading the master and dFIFO length register. */ 240 | uint8_t bMainReg = 0; 241 | int rc = pspStubEm100RegRead(pThis, 0, &bMainReg); 242 | if ( !rc 243 | && (bMainReg & BIT(6)) == 0) /* At least one valid byte in download FIFO? */ 244 | { 245 | uint8_t bDFifoLength = 0; 246 | int rc = pspStubEm100RegRead(pThis, 2, &bDFifoLength); 247 | if (!rc) 248 | { 249 | bMainReg >>= 3; /* Get to the 8th bit of the dFIFO length. */ 250 | size_t cbAvail = (((uint16_t)bMainReg & 1) << 8) | bDFifoLength; 251 | *pcbAvail = cbAvail; 252 | } 253 | } 254 | 255 | return rc; 256 | } 257 | 258 | 259 | /** 260 | * Writes to the upload FIFO of the em100. 261 | * 262 | * @returns Status code. 263 | * @param pThis The EM100 transport channel instance. 264 | * @param pbBuf The data to write. 265 | * @param cbWrite Number of bytes to write. 266 | */ 267 | static int pspStubEm100UFifoWrite(PPSPPDUTRANSPINT pThis, const uint8_t *pbBuf, size_t cbWrite) 268 | { 269 | uint8_t abData[PSP_SPI_MASTER_CHUNK_SZ + 2 + 2]; 270 | 271 | if (cbWrite > PSP_SPI_MASTER_CHUNK_SZ) 272 | return ERR_INVALID_PARAMETER; 273 | 274 | abData[0] = 0x0; 275 | abData[1] = 0xc0; 276 | abData[2] = 0xef; 277 | abData[3] = (uint8_t)cbWrite; 278 | for (uint32_t i = 0; i < cbWrite; i++) 279 | abData[i + 4] = pbBuf[i]; 280 | 281 | return pspStubSpiMasterXact(pThis, 0x11, &abData[0], cbWrite + 4, 282 | NULL /*pbRx*/, 0 /*cbRx*/); 283 | } 284 | 285 | 286 | /** 287 | * Reads from the download FIFO of the em100. 288 | * 289 | * @returns Status code. 290 | * @param pThis The EM100 transport channel instance. 291 | * @param pbBuf Where to store the data read. 292 | * @param cbRead Number of bytes to read. 293 | */ 294 | static int pspStubEm100DFifoRead(PPSPPDUTRANSPINT pThis, uint8_t *pbBuf, size_t cbRead) 295 | { 296 | if (cbRead > PSP_SPI_MASTER_CHUNK_SZ) 297 | return ERR_INVALID_PARAMETER; 298 | 299 | uint8_t abCmd[3]; 300 | uint8_t abRecv[PSP_SPI_MASTER_CHUNK_SZ + sizeof(abCmd)]; 301 | abCmd[0] = 0x0; 302 | abCmd[1] = 0xd0; 303 | 304 | int rc = pspStubSpiMasterXact(pThis, 0x11, &abCmd[0], sizeof(abCmd), 305 | &abRecv[0], cbRead + sizeof(abCmd)); 306 | if (!rc) 307 | { 308 | for (uint32_t i = 0; i < cbRead; i++) 309 | pbBuf[i] = abRecv[i + sizeof(abCmd)]; 310 | } 311 | 312 | /* Wait for at least one free byte in the UFifo. */ 313 | for (;;) 314 | { 315 | size_t cbFree = 0; 316 | rc = pspStubEm100UFifoQueryFree(pThis, &cbFree); 317 | if ( rc 318 | || cbFree) 319 | break; 320 | 321 | pspSerialStubDelayUs(10); 322 | } 323 | 324 | if (!rc) 325 | { 326 | /* Notify the other end that we cleared the FIFO. */ 327 | abCmd[0] = 0x0; 328 | abCmd[1] = 0xc0; 329 | abCmd[2] = 0xdf; 330 | rc = pspStubSpiMasterXact(pThis, 0x11, &abCmd[0], sizeof(abCmd), 331 | NULL /*pbRx*/, 0 /*cbRx*/); 332 | } 333 | 334 | return rc; 335 | } 336 | 337 | 338 | /** 339 | * Fetch the next chunk of data from the dFIFO if available. 340 | * 341 | * @returns Status code. 342 | * @param pThis The EM100 transport channel instance. 343 | * 344 | * @note This is required here as the EM100 clears the dFIFO after each read no matter 345 | * how many bytes were transfered. So we have to cache chunks in case the caller 346 | * wants to read less data. 347 | */ 348 | static int pspStubEm100FetchChunk(PPSPPDUTRANSPINT pThis) 349 | { 350 | if (pThis->cbAvail) 351 | return INF_SUCCESS; 352 | 353 | /* 354 | * Wait a bit for the number of bytes available to stabilize 355 | * or we risk that we get an old number of bytes available and 356 | * read less than what is actually inside the dFIFO which is cleared 357 | * afterwards. 358 | */ 359 | size_t cbAvail = 0; 360 | int rc = INF_SUCCESS; 361 | for (;;) 362 | { 363 | pspSerialStubDelayUs(10); 364 | 365 | size_t cbThisAvail = 0; 366 | rc = pspStubEm100DFifoQueryAvail(pThis, &cbThisAvail); 367 | if ( rc 368 | || cbThisAvail == cbAvail 369 | || cbThisAvail == PSP_SPI_MASTER_CHUNK_SZ) 370 | { 371 | cbAvail = cbThisAvail; 372 | break; 373 | } 374 | 375 | cbAvail = cbThisAvail; 376 | } 377 | 378 | /* We should never have more than chunk size here. */ 379 | if ( !rc 380 | && cbAvail) 381 | { 382 | rc = pspStubEm100DFifoRead(pThis, &pThis->abChunk[0], cbAvail); 383 | if (!rc) 384 | { 385 | pThis->cbAvail = cbAvail; 386 | pThis->offChunk = 0; 387 | } 388 | } 389 | 390 | return rc; 391 | } 392 | 393 | 394 | static int pspStubEm100TranspWrite(PSPPDUTRANSP hPduTransp, const void *pvBuf, size_t cbWrite, size_t *pcbWritten) 395 | { 396 | PPSPPDUTRANSPINT pThis = hPduTransp; 397 | 398 | uint8_t *pbBuf = (uint8_t *)pvBuf; 399 | int rc = INF_SUCCESS; 400 | while ( cbWrite 401 | && rc == INF_SUCCESS) 402 | { 403 | size_t cbFree = 0; 404 | rc = pspStubEm100UFifoQueryFree(pThis, &cbFree); 405 | if (!rc) 406 | { 407 | if (cbFree >= 2 * (PSP_SPI_MASTER_CHUNK_SZ + 2)) 408 | { 409 | size_t cbThisWrite = MIN(cbWrite, PSP_SPI_MASTER_CHUNK_SZ - 2); 410 | cbThisWrite = MIN(cbThisWrite, cbFree); 411 | 412 | rc = pspStubEm100UFifoWrite(pThis, pbBuf, cbThisWrite); 413 | if (!rc) 414 | { 415 | pbBuf += cbThisWrite; 416 | cbWrite -= cbThisWrite; 417 | } 418 | } 419 | #if 0 420 | else 421 | pspSerialStubDelayMs(1); /* Wait for a moment to let the host empty the uFIFO. */ 422 | #endif 423 | } 424 | } 425 | 426 | return INF_SUCCESS; 427 | } 428 | 429 | 430 | static int pspStubEm100TranspRead(PSPPDUTRANSP hPduTransp, void *pvBuf, size_t cbRead, size_t *pcbRead) 431 | { 432 | PPSPPDUTRANSPINT pThis = hPduTransp; 433 | 434 | uint8_t *pbBuf = (uint8_t *)pvBuf; 435 | size_t cbReadLeft = cbRead; 436 | int rc = INF_SUCCESS; 437 | while ( cbReadLeft 438 | && rc == INF_SUCCESS) 439 | { 440 | /* fetch a new chunk if we're out of data. */ 441 | while ( !pThis->cbAvail 442 | && rc == INF_SUCCESS) 443 | rc = pspStubEm100FetchChunk(pThis); 444 | 445 | size_t cbThisRead = MIN(cbReadLeft, pThis->cbAvail); 446 | memcpy(pbBuf, &pThis->abChunk[pThis->offChunk], cbThisRead); 447 | pbBuf += cbThisRead; 448 | cbReadLeft -= cbThisRead; 449 | pThis->cbAvail -= cbThisRead; 450 | pThis->offChunk += cbThisRead; 451 | } 452 | 453 | return rc; 454 | } 455 | 456 | 457 | static size_t pspStubEm100TranspPeek(PSPPDUTRANSP hPduTransp) 458 | { 459 | PPSPPDUTRANSPINT pThis = hPduTransp; 460 | 461 | if (pThis->cbAvail) 462 | return pThis->cbAvail; 463 | 464 | size_t cbAvail = 0; 465 | pspStubEm100DFifoQueryAvail(pThis, &cbAvail); 466 | return cbAvail; 467 | } 468 | 469 | 470 | static int pspStubEm100TranspEnd(PSPPDUTRANSP hPduTransp) 471 | { 472 | /* Nothing to do. */ 473 | return INF_SUCCESS; 474 | } 475 | 476 | 477 | static int pspStubEm100TranspBegin(PSPPDUTRANSP hPduTransp) 478 | { 479 | #if 0 480 | PPSPPDUTRANSPINT pThis = hPduTransp; 481 | 482 | pspStubSpiMasterWriteRegU16(pThis, PSP_SPI_MASTER_SPEED_CFG, 0x1111); 483 | pspStubSpiMasterWriteRegU8(pThis, PSP_SPI_MASTER_ALT_CS, pThis->bRegCs); 484 | uint32_t u32RegCntrl0 = pspStubSpiMasterReadRegU32(pThis, 0); 485 | pspStubSpiMasterWriteRegU32(pThis, 0, (u32RegCntrl0 & ~BIT(27)) | pThis->fSpiBridgeDisable); 486 | #endif 487 | return INF_SUCCESS; 488 | } 489 | 490 | 491 | static void pspStubEm100TranspTerm(PSPPDUTRANSP hPduTransp) 492 | { 493 | PPSPPDUTRANSPINT pThis = hPduTransp; 494 | pspSerialStubSmnUnmapByPtr((void *)pThis->pvSmnMap); 495 | } 496 | 497 | 498 | static int pspStubEm100TranspInit(void *pvMem, size_t cbMem, PPSPPDUTRANSP phPduTransp) 499 | { 500 | if (cbMem < sizeof(PSPPDUTRANSPINT)) 501 | return ERR_INVALID_PARAMETER; 502 | 503 | PPSPPDUTRANSPINT pThis = (PPSPPDUTRANSPINT)pvMem; 504 | int rc = pspSerialStubSmnMap(PSP_SPI_MASTER_SMN_ADDR, (void **)&pThis->pvSmnMap); 505 | if (!rc) 506 | { 507 | #if 1 /** @todo Doesn't has any effect. */ 508 | pspStubSpiMasterWriteRegU8(pThis, PSP_SPI_MASTER_SPEED_EN, 1); 509 | pspStubSpiMasterWriteRegU16(pThis, PSP_SPI_MASTER_SPEED_CFG, 0x1111); /* Switches everything to 800kHz mode. */ 510 | #endif 511 | 512 | while (pspStubSpiMasterReadRegU32(pThis, PSP_SPI_MASTER_STATUS) & PSP_SPI_MASTER_STATUS_BSY); 513 | pThis->bRegCs = pspStubSpiMasterReadRegU8(pThis, PSP_SPI_MASTER_ALT_CS); 514 | pThis->fSpiBridgeDisable = pspStubSpiMasterReadRegU32(pThis, 0) & BIT(27); 515 | 516 | /* Check for the EM100 identifier. */ 517 | uint8_t bId = 0; 518 | rc = pspStubEm100RegRead(pThis, 3, &bId); 519 | if (!rc) 520 | { 521 | if (bId == 0xaa) 522 | { 523 | pThis->cbAvail = 0; 524 | pThis->offChunk = 0; 525 | *phPduTransp = pThis; 526 | return INF_SUCCESS; 527 | } 528 | else 529 | rc = -1; 530 | } 531 | 532 | pspSerialStubSmnUnmapByPtr((void *)pThis->pvSmnMap); 533 | } 534 | 535 | return rc; 536 | } 537 | 538 | 539 | const PSPPDUTRANSPIF g_SpiFlashTranspEm100 = 540 | { 541 | /** cbState */ 542 | sizeof(PSPPDUTRANSPINT), 543 | /** pfnInit */ 544 | pspStubEm100TranspInit, 545 | /** pfnTerm */ 546 | pspStubEm100TranspTerm, 547 | /** pfnBegin */ 548 | pspStubEm100TranspBegin, 549 | /** pfnEnd */ 550 | pspStubEm100TranspEnd, 551 | /** pfnPeek */ 552 | pspStubEm100TranspPeek, 553 | /** pfnRead */ 554 | pspStubEm100TranspRead, 555 | /** pfnWrite */ 556 | pspStubEm100TranspWrite 557 | }; 558 | 559 | -------------------------------------------------------------------------------- /PspSerialStub/pdu-transp-spi-flash.c: -------------------------------------------------------------------------------- 1 | /** @file 2 | * PSP app - SPI flash PDU transport channel. 3 | */ 4 | 5 | /* 6 | * Copyright (C) 2020 Alexander Eichner 7 | * 8 | * This library is free software; you can redistribute it and/or 9 | * modify it under the terms of the GNU Lesser General Public 10 | * License as published by the Free Software Foundation; either 11 | * version 2.1 of the License, or (at your option) any later version. 12 | * 13 | * This library is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 16 | * Lesser General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU Lesser General Public 19 | * License along with this library; if not, write to the Free Software 20 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 21 | */ 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | 28 | #include 29 | #include 30 | 31 | #include "pdu-transp.h" 32 | #include "psp-serial-stub-internal.h" 33 | 34 | 35 | #define PSP_SPI_FLASH_SMN_ADDR 0x0a000000 36 | 37 | #define PSP_SPI_FLASH_LOCK_WAIT 50 38 | 39 | /** Where in the flash the message channel is located. */ 40 | #define SPI_MSG_CHAN_HDR_OFF 0xaab000 41 | #define SPI_MSG_CHAN_AVAIL_OFF 0xaaa000 42 | #define SPI_MSG_CHAN_AVAIL_F_OFF 0xaac000 43 | #define SPI_MSG_CHAN_STS_OFF 0xaad000 44 | #define SPI_FLASH_LOCK_OFF 0xaa0000 45 | #define SPI_FLASH_LOCK_UNLOCK_REQ_MAGIC 0x19570528 /* (Frank Schaetzing) */ 46 | #define SPI_FLASH_LOCK_UNLOCKED_MAGIC 0x18280208 /* (Jules Verne) */ 47 | #define SPI_FLASH_LOCK_LOCK_REQ_MAGIC 0x19380110 /* (Donald E Knuth) */ 48 | #define SPI_FLASH_LOCK_LOCKED_MAGIC 0x18990223 /* (Erich Kaestner) */ 49 | 50 | #define SPI_MSG_CHAN_AVAIL_MAGIC 0x19640522 /* (Dan Brown) */ 51 | 52 | /** 53 | * SPI flash transport channel. 54 | */ 55 | typedef struct PSPPDUTRANSPINT 56 | { 57 | /** Number of times the SPI flash was locked. */ 58 | uint32_t cSpiFlashLock; 59 | /** Last accessed offset for reading (top optimize the cache wiping). */ 60 | uint32_t offReadLast; 61 | /** Number of bytes available for reading. */ 62 | size_t cbReadAvail; 63 | } PSPPDUTRANSPINT; 64 | /** Pointer to the x86 UART PDU transport channel instance. */ 65 | typedef PSPPDUTRANSPINT *PPSPPDUTRANSPINT; 66 | 67 | 68 | static size_t pspStubSpiFlashTranspPeek(PSPPDUTRANSP hPduTransp); 69 | 70 | 71 | /** 72 | * Wipe the read cache of the SPI flash. 73 | * 74 | * @returns nothing. 75 | * @param pThis SPI flash transport instance data. 76 | */ 77 | static void pspStubSpiFlashWipeCache(PPSPPDUTRANSPINT pThis) 78 | { 79 | /* Map the SMN region. */ 80 | void *pvMap; 81 | int rc = pspSerialStubSmnMap(PSP_SPI_FLASH_SMN_ADDR, &pvMap); 82 | if (!rc) 83 | { 84 | /* Make sure we don't read cached data by issuing a read to a non accecssed region. */ 85 | uint32_t uIgnored = *(volatile uint32_t *)pvMap; 86 | pspSerialStubSmnUnmapByPtr(pvMap); 87 | } 88 | } 89 | 90 | 91 | /** 92 | * Reads the given amount of data from the SPI flash. 93 | * 94 | * @returns Nothing. 95 | * @param pThis SPI flash transport instance data. 96 | * @param off Start offset to read from. 97 | * @param pvBuf Where to store the read data. 98 | * @param cbRead How many bytes to read. 99 | */ 100 | static void pspStubSpiFlashRead(PPSPPDUTRANSPINT pThis, uint32_t off, void *pvBuf, size_t cbRead) 101 | { 102 | if ( pThis->offReadLast == 0xffff0000 103 | || ( off >= pThis->offReadLast 104 | && off < pThis->offReadLast + 256 /* cache size */)) 105 | pspStubSpiFlashWipeCache(pThis); 106 | 107 | /* Map the SMN region. */ 108 | void *pvMap; 109 | int rc = pspSerialStubSmnMap(PSP_SPI_FLASH_SMN_ADDR + off, &pvMap); 110 | if (!rc) 111 | { 112 | memcpy(pvBuf, pvMap, cbRead); 113 | pspSerialStubSmnUnmapByPtr(pvMap); 114 | pThis->offReadLast = off; 115 | } 116 | } 117 | 118 | 119 | /** 120 | * Writes the given amount of data to the SPI flash. 121 | * 122 | * @returns Nothing. 123 | * @param pThis SPI flash transport instance data. 124 | * @param off Start offset to write to. 125 | * @param pvBuf The data to write. 126 | * @param cbWrite How many bytes to write. 127 | */ 128 | static void pspStubSpiFlashWrite(PPSPPDUTRANSPINT pThis, uint32_t off, const void *pvBuf, size_t cbWrite) 129 | { 130 | /* Map the SMN region. */ 131 | void *pvMap; 132 | int rc = pspSerialStubSmnMap(PSP_SPI_FLASH_SMN_ADDR + off, &pvMap); 133 | if (!rc) 134 | { 135 | volatile uint8_t *pbDst = (volatile uint8_t *)pvMap; 136 | const uint8_t *pbSrc = (const uint8_t *)pvBuf; 137 | 138 | while (cbWrite >= sizeof(uint32_t)) 139 | { 140 | *(volatile uint32_t *)pbDst = *(uint32_t *)pbSrc; 141 | pbDst += sizeof(uint32_t); 142 | pbSrc += sizeof(uint32_t); 143 | cbWrite -= sizeof(uint32_t); 144 | } 145 | 146 | if (cbWrite) 147 | memcpy((uint8_t *)pbDst, pbSrc, cbWrite); 148 | pspSerialStubSmnUnmapByPtr(pvMap); 149 | } 150 | } 151 | 152 | 153 | /** 154 | * Write status code to the respective port. 155 | * 156 | * @returns nothing. 157 | * @param uSts Status code to write. 158 | */ 159 | static inline void pspStubSpiFlashStsWr(uint32_t uSts) 160 | { 161 | void *pvMap; 162 | int rc = pspSerialStubSmnMap(PSP_SPI_FLASH_SMN_ADDR + SPI_MSG_CHAN_STS_OFF, &pvMap); 163 | if (!rc) 164 | { 165 | *(volatile uint32_t *)pvMap = uSts; 166 | uint32_t uIgnored = *((volatile uint32_t *)pvMap + 1); 167 | pspSerialStubSmnUnmapByPtr(pvMap); 168 | } 169 | } 170 | 171 | 172 | /** 173 | * Lock the SPI flash for access. 174 | * 175 | * @returns nothing. 176 | * @param pThis SPI flash transport instance data. 177 | */ 178 | static void pspStubSpiFlashLock(PPSPPDUTRANSPINT pThis) 179 | { 180 | if (!pThis->cSpiFlashLock) 181 | { 182 | /* Write the lock request until we see the magic value for the locked case. */ 183 | uint32_t u32Read = 0; 184 | 185 | uint32_t u32Write = SPI_FLASH_LOCK_LOCK_REQ_MAGIC; 186 | pspStubSpiFlashWrite(pThis, SPI_FLASH_LOCK_OFF, &u32Write, sizeof(u32Write)); 187 | pspStubSpiFlashRead(pThis, 0, &u32Write, sizeof(u32Write)); /* Dummy */ 188 | 189 | #if 1 190 | uint32_t cRounds = 0; 191 | #endif 192 | do 193 | { 194 | pspSerialStubDelayMs(PSP_SPI_FLASH_LOCK_WAIT); /* Wait a moment for the emulator process the request. */ 195 | pspStubSpiFlashRead(pThis, SPI_FLASH_LOCK_OFF, &u32Read, sizeof(u32Read)); 196 | 197 | #if 1 /* Debug code for a hang where the locked magic is never read after a lock request. */ 198 | cRounds++; 199 | if (cRounds >= 10) 200 | { 201 | pspStubSpiFlashStsWr(SPI_FLASH_LOCK_LOCK_REQ_MAGIC); 202 | pspStubSpiFlashWipeCache(pThis); 203 | cRounds = 0; 204 | } 205 | #endif 206 | } 207 | while (u32Read != SPI_FLASH_LOCK_LOCKED_MAGIC); 208 | } 209 | 210 | pThis->cSpiFlashLock++; 211 | } 212 | 213 | 214 | /** 215 | * Unlock the SPI flash for access. 216 | * 217 | * @returns nothing. 218 | * @param pThis SPI flash transport instance data. 219 | */ 220 | static void pspStubSpiFlashUnlock(PPSPPDUTRANSPINT pThis) 221 | { 222 | pThis->cSpiFlashLock--; 223 | if (!pThis->cSpiFlashLock) 224 | { 225 | /* Write the unlock request and wait till we see the magic value for the unlocked case. */ 226 | uint32_t u32Read = 0; 227 | 228 | uint32_t u32Write = SPI_FLASH_LOCK_UNLOCK_REQ_MAGIC; 229 | pspStubSpiFlashWrite(pThis, SPI_FLASH_LOCK_OFF, &u32Write, sizeof(u32Write)); 230 | pspStubSpiFlashRead(pThis, 0, &u32Write, sizeof(u32Write)); /* Dummy */ 231 | 232 | #if 1 233 | uint32_t cRounds = 0; 234 | #endif 235 | do 236 | { 237 | pspSerialStubDelayMs(PSP_SPI_FLASH_LOCK_WAIT); /* Wait a moment for the emulator process the request. */ 238 | pspStubSpiFlashRead(pThis, SPI_FLASH_LOCK_OFF, &u32Read, sizeof(u32Read)); 239 | 240 | #if 1 /* Debug code for a hang where the unlocked magic is never read after a unlock request. */ 241 | cRounds++; 242 | if (cRounds >= 10) 243 | { 244 | pspStubSpiFlashStsWr(SPI_FLASH_LOCK_UNLOCK_REQ_MAGIC); 245 | pspStubSpiFlashWipeCache(pThis); 246 | cRounds = 0; 247 | } 248 | #endif 249 | } 250 | while (u32Read != SPI_FLASH_LOCK_UNLOCKED_MAGIC); 251 | } 252 | } 253 | 254 | 255 | static int pspStubSpiFlashTranspWrite(PSPPDUTRANSP hPduTransp, const void *pvBuf, size_t cbWrite, size_t *pcbWritten) 256 | { 257 | PPSPPDUTRANSPINT pThis = hPduTransp; 258 | 259 | pspStubSpiFlashLock(pThis); 260 | size_t cbWriteLeft = cbWrite; 261 | uint8_t *pbBuf = (uint8_t *)pvBuf; 262 | 263 | while (cbWriteLeft) 264 | { 265 | size_t cbThisWrite = MIN(256, cbWriteLeft); 266 | 267 | pspStubSpiFlashWrite(pThis, SPI_MSG_CHAN_HDR_OFF, pbBuf, cbThisWrite); 268 | pbBuf += cbThisWrite; 269 | cbWriteLeft -= cbThisWrite; 270 | } 271 | pspStubSpiFlashUnlock(pThis); 272 | 273 | return INF_SUCCESS; 274 | } 275 | 276 | 277 | static int pspStubSpiFlashTranspRead(PSPPDUTRANSP hPduTransp, void *pvBuf, size_t cbRead, size_t *pcbRead) 278 | { 279 | PPSPPDUTRANSPINT pThis = hPduTransp; 280 | 281 | size_t cbReadLeft = cbRead; 282 | uint8_t *pbBuf = (uint8_t *)pvBuf; 283 | 284 | while (cbReadLeft) 285 | { 286 | pspStubSpiFlashLock(pThis); 287 | 288 | /* Simple case, read the number of bytes available and get them. */ 289 | size_t cbThisRead = MIN(pspStubSpiFlashTranspPeek(pThis), cbReadLeft); 290 | if (cbThisRead) 291 | { 292 | pspStubSpiFlashRead(pThis, SPI_MSG_CHAN_HDR_OFF, pbBuf, cbThisRead); 293 | pbBuf += cbThisRead; 294 | cbReadLeft -= cbThisRead; 295 | pspStubSpiFlashWrite(pThis, SPI_MSG_CHAN_AVAIL_OFF, &cbThisRead, sizeof(cbThisRead)); 296 | pspStubSpiFlashRead(pThis, 0, &cbThisRead, sizeof(cbThisRead)); /* Dummy */ 297 | } 298 | 299 | #if 0 300 | pThis->cbReadAvail -= cbThisRead; 301 | /* Update the amount of data we can read here under the lock if we've read everything. */ 302 | if (!pThis->cbReadAvail) 303 | pThis->cbReadAvail = pspStubSpiFlashTranspPeek(pThis); 304 | #endif 305 | pspStubSpiFlashUnlock(pThis); 306 | } 307 | 308 | return INF_SUCCESS; 309 | } 310 | 311 | 312 | static size_t pspStubSpiFlashTranspPeek(PSPPDUTRANSP hPduTransp) 313 | { 314 | PPSPPDUTRANSPINT pThis = hPduTransp; 315 | 316 | #if 0 317 | /* Don't bother with checking if there is still something left. */ 318 | if (pThis->cbReadAvail) 319 | return pThis->cbReadAvail; 320 | #endif 321 | 322 | uint32_t u32Avail = 0; 323 | uint32_t u32ReadAvailMagic = 0; 324 | pspStubSpiFlashRead(pThis, SPI_MSG_CHAN_AVAIL_F_OFF, &u32ReadAvailMagic, sizeof(u32ReadAvailMagic)); 325 | if (u32ReadAvailMagic == SPI_MSG_CHAN_AVAIL_MAGIC) 326 | { 327 | /* 328 | * The magic indicates something is available for reading, now do the locking and get the actual 329 | * number of bytes available. 330 | */ 331 | pspStubSpiFlashLock(pThis); 332 | pspStubSpiFlashRead(pThis, SPI_MSG_CHAN_AVAIL_OFF, &u32Avail, sizeof(u32Avail)); 333 | pspStubSpiFlashUnlock(pThis); 334 | pThis->cbReadAvail = u32Avail; 335 | } 336 | 337 | return u32Avail; 338 | } 339 | 340 | 341 | static int pspStubSpiFlashTranspEnd(PSPPDUTRANSP hPduTransp) 342 | { 343 | PPSPPDUTRANSPINT pThis = hPduTransp; 344 | pspStubSpiFlashUnlock(pThis); 345 | return INF_SUCCESS; 346 | } 347 | 348 | 349 | static int pspStubSpiFlashTranspBegin(PSPPDUTRANSP hPduTransp) 350 | { 351 | PPSPPDUTRANSPINT pThis = hPduTransp; 352 | pspStubSpiFlashLock(pThis); 353 | return INF_SUCCESS; 354 | } 355 | 356 | 357 | static void pspStubSpiFlashTranspTerm(PSPPDUTRANSP hPduTransp) 358 | { 359 | /* Nothing to do. */ 360 | } 361 | 362 | 363 | static int pspStubSpiFlashTranspInit(void *pvMem, size_t cbMem, PPSPPDUTRANSP phPduTransp) 364 | { 365 | if (cbMem < sizeof(PSPPDUTRANSPINT)) 366 | return ERR_INVALID_PARAMETER; 367 | 368 | PPSPPDUTRANSPINT pThis = (PPSPPDUTRANSPINT)pvMem; 369 | 370 | pThis->cSpiFlashLock = 0; 371 | pThis->offReadLast = 0xffff0000; /* Invalid, this will always wipe the cache. */ 372 | pThis->cbReadAvail = 0; 373 | 374 | uint32_t u32Magic; 375 | do 376 | { 377 | pspStubSpiFlashRead(pThis, 0, &u32Magic, sizeof(u32Magic)); /* Read some dummy first, to flush the SPI read cache. */ 378 | pspStubSpiFlashRead(pThis, SPI_FLASH_LOCK_OFF, &u32Magic, sizeof(u32Magic)); 379 | } 380 | while (u32Magic != SPI_FLASH_LOCK_UNLOCKED_MAGIC); 381 | 382 | *phPduTransp = pThis; 383 | return INF_SUCCESS; 384 | } 385 | 386 | 387 | const PSPPDUTRANSPIF g_SpiFlashTransp = 388 | { 389 | /** cbState */ 390 | sizeof(PSPPDUTRANSPINT), 391 | /** pfnInit */ 392 | pspStubSpiFlashTranspInit, 393 | /** pfnTerm */ 394 | pspStubSpiFlashTranspTerm, 395 | /** pfnBegin */ 396 | pspStubSpiFlashTranspBegin, 397 | /** pfnEnd */ 398 | pspStubSpiFlashTranspEnd, 399 | /** pfnPeek */ 400 | pspStubSpiFlashTranspPeek, 401 | /** pfnRead */ 402 | pspStubSpiFlashTranspRead, 403 | /** pfnWrite */ 404 | pspStubSpiFlashTranspWrite 405 | }; 406 | 407 | -------------------------------------------------------------------------------- /PspSerialStub/pdu-transp-uart.c: -------------------------------------------------------------------------------- 1 | /** @file 2 | * PSP app - UART PDU transport channel. 3 | */ 4 | 5 | /* 6 | * Copyright (C) 2020 Alexander Eichner 7 | * 8 | * This library is free software; you can redistribute it and/or 9 | * modify it under the terms of the GNU Lesser General Public 10 | * License as published by the Free Software Foundation; either 11 | * version 2.1 of the License, or (at your option) any later version. 12 | * 13 | * This library is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 16 | * Lesser General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU Lesser General Public 19 | * License along with this library; if not, write to the Free Software 20 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 21 | */ 22 | #include 23 | #include 24 | #include 25 | #include 26 | 27 | #include 28 | #include 29 | 30 | #include "pdu-transp.h" 31 | #include "psp-serial-stub-internal.h" 32 | 33 | 34 | /** 35 | * x86 UART device I/O interface. 36 | */ 37 | typedef struct PSPPDUTRANSPINT 38 | { 39 | /** Device I/O interface. */ 40 | PSPIODEVIF IfIoDev; 41 | /** The physical x86 address where the UART is mapped. */ 42 | X86PADDR PhysX86UartBase; 43 | /** The MMIO mapping of the UART. */ 44 | volatile void *pvUart; 45 | /** UART device instance. */ 46 | PSPUART Uart; 47 | } PSPPDUTRANSPINT; 48 | /** Pointer to the x86 UART PDU transport channel instance. */ 49 | typedef PSPPDUTRANSPINT *PPSPPDUTRANSPINT; 50 | 51 | 52 | /** 53 | * x86 UART register read callback. 54 | */ 55 | static int pspStubX86UartRegRead(PCPSPIODEVIF pIfIoDev, uint32_t offReg, void *pvBuf, size_t cbRead) 56 | { 57 | PPSPPDUTRANSPINT pThis = (PPSPPDUTRANSPINT)pIfIoDev; 58 | 59 | /* UART supports only 1 byte wide register accesses. */ 60 | if (cbRead != 1) return ERR_INVALID_STATE; 61 | 62 | *(uint8_t *)pvBuf = *(volatile uint8_t *)((uintptr_t)pThis->pvUart + offReg); 63 | return INF_SUCCESS; 64 | } 65 | 66 | 67 | /** 68 | * x86 UART register write callback. 69 | */ 70 | static int pspStubX86UartRegWrite(PCPSPIODEVIF pIfIoDev, uint32_t offReg, const void *pvBuf, size_t cbWrite) 71 | { 72 | PPSPPDUTRANSPINT pThis = (PPSPPDUTRANSPINT)pIfIoDev; 73 | 74 | /* UART supports only 1 byte wide register accesses. */ 75 | if (cbWrite != 1) return ERR_INVALID_STATE; 76 | 77 | *(volatile uint8_t *)((uintptr_t)pThis->pvUart + offReg) = *(uint8_t *)pvBuf; 78 | return INF_SUCCESS; 79 | } 80 | 81 | 82 | static int pspStubUartTranspWrite(PSPPDUTRANSP hPduTransp, const void *pvBuf, size_t cbWrite, size_t *pcbWritten) 83 | { 84 | PPSPPDUTRANSPINT pThis = hPduTransp; 85 | 86 | return PSPUartWrite(&pThis->Uart, pvBuf, cbWrite, pcbWritten); 87 | } 88 | 89 | 90 | static int pspStubUartTranspRead(PSPPDUTRANSP hPduTransp, void *pvBuf, size_t cbRead, size_t *pcbRead) 91 | { 92 | PPSPPDUTRANSPINT pThis = hPduTransp; 93 | 94 | return PSPUartRead(&pThis->Uart, pvBuf, cbRead, pcbRead); 95 | } 96 | 97 | 98 | static size_t pspStubUartTranspPeek(PSPPDUTRANSP hPduTransp) 99 | { 100 | PPSPPDUTRANSPINT pThis = hPduTransp; 101 | 102 | return PSPUartGetDataAvail(&pThis->Uart); 103 | } 104 | 105 | 106 | static int pspStubUartTranspEnd(PSPPDUTRANSP hPduTransp) 107 | { 108 | /* Nothing to do. */ 109 | return INF_SUCCESS; 110 | } 111 | 112 | 113 | static int pspStubUartTranspBegin(PSPPDUTRANSP hPduTransp) 114 | { 115 | /* Nothing to do. */ 116 | return INF_SUCCESS; 117 | } 118 | 119 | 120 | static void pspStubUartTranspTerm(PSPPDUTRANSP hPduTransp) 121 | { 122 | /* Nothing to do. */ 123 | } 124 | 125 | 126 | static int pspStubUartTranspInit(void *pvMem, size_t cbMem, PPSPPDUTRANSP phPduTransp) 127 | { 128 | if (cbMem < sizeof(PSPPDUTRANSPINT)) 129 | return ERR_INVALID_PARAMETER; 130 | 131 | PPSPPDUTRANSPINT pThis = (PPSPPDUTRANSPINT)pvMem; 132 | 133 | pThis->PhysX86UartBase = 0xfffdfc0003f8; 134 | pThis->pvUart = NULL; 135 | pThis->IfIoDev.pfnRegRead = pspStubX86UartRegRead; 136 | pThis->IfIoDev.pfnRegWrite = pspStubX86UartRegWrite; 137 | 138 | int rc = pspSerialStubX86PhysMap(pThis->PhysX86UartBase, true /*fMmio*/, (void **)&pThis->pvUart); 139 | if (!rc) 140 | { 141 | rc = PSPUartCreate(&pThis->Uart, &pThis->IfIoDev); 142 | if (!rc) 143 | { 144 | rc = PSPUartParamsSet(&pThis->Uart, 115200, PSPUARTDATABITS_8BITS, PSPUARTPARITY_NONE, PSPUARTSTOPBITS_1BIT); 145 | if (!rc) 146 | *phPduTransp = pThis; 147 | } 148 | } 149 | 150 | return rc; 151 | } 152 | 153 | 154 | const PSPPDUTRANSPIF g_UartTransp = 155 | { 156 | /** cbState */ 157 | sizeof(PSPPDUTRANSPINT), 158 | /** pfnInit */ 159 | pspStubUartTranspInit, 160 | /** pfnTerm */ 161 | pspStubUartTranspTerm, 162 | /** pfnBegin */ 163 | pspStubUartTranspBegin, 164 | /** pfnEnd */ 165 | pspStubUartTranspEnd, 166 | /** pfnPeek */ 167 | pspStubUartTranspPeek, 168 | /** pfnRead */ 169 | pspStubUartTranspRead, 170 | /** pfnWrite */ 171 | pspStubUartTranspWrite 172 | }; 173 | 174 | -------------------------------------------------------------------------------- /PspSerialStub/pdu-transp.h: -------------------------------------------------------------------------------- 1 | /** @file 2 | * PSP internal interfaces - PDU transport channel callback table. 3 | */ 4 | 5 | /* 6 | * Copyright (C) 2020 Alexander Eichner 7 | * 8 | * Permission is hereby granted, free of charge, to any person obtaining a copy 9 | * of this software and associated documentation files (the "Software"), to deal 10 | * in the Software without restriction, including without limitation the rights 11 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | * copies of the Software, and to permit persons to whom the Software is 13 | * furnished to do so, subject to the following conditions: 14 | * 15 | * The above copyright notice and this permission notice shall be included in all 16 | * copies or substantial portions of the Software. 17 | * 18 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 24 | * SOFTWARE. 25 | */ 26 | #ifndef __include_pdu_transp_h 27 | #define __include_pdu_transp_h 28 | 29 | #if defined(IN_PSP) 30 | # include 31 | #else 32 | # error "Invalid environment" 33 | #endif 34 | 35 | /** PDU transport channel instance handle. */ 36 | typedef struct PSPPDUTRANSPINT *PSPPDUTRANSP; 37 | /** Pointer to a PDU transport channel instance handle. */ 38 | typedef PSPPDUTRANSP *PPSPPDUTRANSP; 39 | 40 | 41 | /** Pointer to a PDU transport channel interface. */ 42 | typedef struct PSPPDUTRANSPIF *PPSPPDUTRANSPIF; 43 | /** Pointer to a const PDU transport channel interface. */ 44 | typedef const struct PSPPDUTRANSPIF *PCPSPPDUTRANSPIF; 45 | 46 | 47 | /** PDU transport channel interface. */ 48 | typedef struct PSPPDUTRANSPIF 49 | { 50 | /** Number if bytes of private state required. */ 51 | size_t cbState; 52 | 53 | /** 54 | * Initialize the transport channel. 55 | * 56 | * @returns Status code. 57 | * @param pvMem The memory available for the PDU transport channel instance. 58 | * @param cbMem Number of bytes available. 59 | * @param phPduTransp Where to store the handle on success. 60 | */ 61 | int (*pfnInit) (void *pvMem, size_t cbMem, PPSPPDUTRANSP phPduTransp); 62 | 63 | /** 64 | * Terminate the transport channel. 65 | * 66 | * @returns nothing. 67 | * @param hPduTransp PDU transport channel instance handle. 68 | */ 69 | void (*pfnTerm) (PSPPDUTRANSP hPduTransp); 70 | 71 | /** 72 | * Marks the begin of a channel access. 73 | * 74 | * @returns Status code. 75 | * @param hPduTransp PDU transport channel instance handle. 76 | */ 77 | int (*pfnBegin) (PSPPDUTRANSP hPduTransp); 78 | 79 | /** 80 | * Marks the end of a channel access. 81 | * 82 | * @returns Status code. 83 | * @param hPduTransp PDU transport channel instance handle. 84 | */ 85 | int (*pfnEnd) (PSPPDUTRANSP hPduTransp); 86 | 87 | /** 88 | * Return the amount of bytes available for reading. 89 | * 90 | * @returns Number of bytes available for reading. 91 | * @param hPduTransp PDU transport channel instance handle. 92 | */ 93 | size_t (*pfnPeek) (PSPPDUTRANSP hPduTransp); 94 | 95 | /** 96 | * Data read callback. 97 | * 98 | * @returns Status code. 99 | * @param hPduTransp PDU transport channel instance handle. 100 | * @param pvBuf Where to store the read data. 101 | * @param cbRead How much to read. 102 | * @param pcbRead Where to store the number of bytes read upon success, optional. 103 | */ 104 | int (*pfnRead) (PSPPDUTRANSP hPduTransp, void *pvBuf, size_t cbRead, size_t *pcbRead); 105 | 106 | /** 107 | * Data write callback. 108 | * 109 | * @returns Status code. 110 | * @param hPduTransp PDU transport channel instance handle. 111 | * @param pvBuf The data to write. 112 | * @param cbWrite How much to write. 113 | * @param pcbWritten Where to store the number of bytes written upon success, optional. 114 | */ 115 | int (*pfnWrite) (PSPPDUTRANSP hPduTransp, const void *pvBuf, size_t cbWrite, size_t *pcbWritten); 116 | 117 | } PSPPDUTRANSPIF; 118 | 119 | 120 | #endif /* !__include_pdu_transp_h */ 121 | 122 | -------------------------------------------------------------------------------- /PspSerialStub/psp-serial-stub-internal.h: -------------------------------------------------------------------------------- 1 | /** @file 2 | * PSP internal interfaces - PDU transport channel callback table. 3 | */ 4 | 5 | /* 6 | * Copyright (C) 2020 Alexander Eichner 7 | * 8 | * Permission is hereby granted, free of charge, to any person obtaining a copy 9 | * of this software and associated documentation files (the "Software"), to deal 10 | * in the Software without restriction, including without limitation the rights 11 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | * copies of the Software, and to permit persons to whom the Software is 13 | * furnished to do so, subject to the following conditions: 14 | * 15 | * The above copyright notice and this permission notice shall be included in all 16 | * copies or substantial portions of the Software. 17 | * 18 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 24 | * SOFTWARE. 25 | */ 26 | #ifndef __include_psp_serial_stub_internal_h 27 | #define __include_psp_serial_stub_internal_h 28 | 29 | #if defined(IN_PSP) 30 | # include 31 | #else 32 | # error "Invalid environment" 33 | #endif 34 | 35 | /** 36 | * Maps the given x86 physical address into the PSP address space. 37 | * 38 | * @returns Status code. 39 | * @param PhysX86Addr The x86 physical address to map. 40 | * @param fMmio Flag whether this a MMIO address. 41 | * @param ppv Where to store the pointer to the mapping on success. 42 | */ 43 | int pspSerialStubX86PhysMap(X86PADDR PhysX86Addr, bool fMmio, void **ppv); 44 | 45 | 46 | /** 47 | * Unmaps a previously mapped x86 physical address. 48 | * 49 | * @returns Status code. 50 | * @param pv Pointer to the mapping as returned by a successful call to pspStubX86PhysMap(). 51 | */ 52 | int pspSerialStubX86PhysUnmapByPtr(void *pv); 53 | 54 | 55 | /** 56 | * Unmaps a previously mapped SMN address. 57 | * 58 | * @returns Status code. 59 | * @param pv Pointer to the mapping as returned by a successful call to pspStubSmnMap(). 60 | */ 61 | int pspSerialStubSmnMap(SMNADDR SmnAddr, void **ppv); 62 | 63 | 64 | /** 65 | * Maps the given SMN address into the PSP address space. 66 | * 67 | * @returns Status code. 68 | * @param SmnAddr The SMN address to map. 69 | * @param ppv Where to store the pointer to the mapping on success. 70 | */ 71 | int pspSerialStubSmnUnmapByPtr(void *pv); 72 | 73 | 74 | /** 75 | * Wait the given number of milli seconds. 76 | * 77 | * @returns nothing. 78 | * @param cMillies Number of milli seconds to wait. 79 | */ 80 | void pspSerialStubDelayMs(uint32_t cMillies); 81 | 82 | 83 | /** 84 | * Wait the given number of microseconds. 85 | * 86 | * @returns nothing. 87 | * @param cMicros Number of microseconds to wait. 88 | */ 89 | void pspSerialStubDelayUs(uint64_t cMicros); 90 | 91 | #endif /* !__include_psp_serial_stub_internal_h */ 92 | 93 | -------------------------------------------------------------------------------- /PspSerialStub/thumb-interwork.S: -------------------------------------------------------------------------------- 1 | /** @file 2 | * PSP serial stub - Thumb interworking code. 3 | */ 4 | 5 | /* 6 | * Copyright (C) 2020 Alexander Eichner 7 | * 8 | * This library is free software; you can redistribute it and/or 9 | * modify it under the terms of the GNU Lesser General Public 10 | * License as published by the Free Software Foundation; either 11 | * version 2.1 of the License, or (at your option) any later version. 12 | * 13 | * This library is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 16 | * Lesser General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU Lesser General Public 19 | * License along with this library; if not, write to the Free Software 20 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 21 | */ 22 | 23 | /** 24 | * This is ugly AF but in order to support ARM and thumb code modules there 25 | * doesn't seem to be a better way as gcc will always emit a ""ldr pc, ..." which 26 | * will not return the previous instruction set state. 27 | */ 28 | 29 | /** 30 | * Macro generating a trampoline for functions with up to 4 arguments not requiring 31 | * repositioning some arguments on the stack. 32 | * 33 | * @param a_Name Name of the function generate the trampoline for. 34 | */ 35 | .macro FN_INTERWORK_1_2_3_4_ARG a_Name 36 | .globl \a_Name\()Asm 37 | \a_Name\()Asm: 38 | push {lr} 39 | blx \a_Name 40 | pop {lr} 41 | bx lr 42 | .type \a_Name\()Asm, %function; 43 | .endm 44 | 45 | 46 | /** 47 | * Macro generating a trampoline for functions with up 5 arguments which requires 48 | * repositioning one argument on the stack. 49 | * 50 | * @param a_Name Name of the function generate the trampoline for. 51 | */ 52 | .macro FN_INTERWORK_5_ARG a_Name 53 | .globl \a_Name\()Asm 54 | \a_Name\()Asm: 55 | push {lr} 56 | ldr lr, [sp, #4] /* Rearrange the last argument on the stack as the lr push has changed the layout. */ 57 | push {lr} 58 | blx \a_Name 59 | pop {lr} 60 | pop {lr} 61 | bx lr 62 | .type \a_Name\()Asm, %function; 63 | .endm 64 | 65 | /* External references to methods we are creating tramponlines for. */ 66 | .extern pspStubCmIfInBufPeek 67 | .extern pspStubCmIfInBufPoll 68 | .extern pspStubCmIfInBufRead 69 | .extern pspStubCmIfOutBufWrite 70 | .extern pspStubCmIfDelayMs 71 | .extern pspStubCmIfTsGetMilli 72 | 73 | /* Generates the trampolines */ 74 | FN_INTERWORK_1_2_3_4_ARG pspStubCmIfInBufPeek 75 | FN_INTERWORK_1_2_3_4_ARG pspStubCmIfInBufPoll 76 | FN_INTERWORK_5_ARG pspStubCmIfInBufRead 77 | FN_INTERWORK_5_ARG pspStubCmIfOutBufWrite 78 | FN_INTERWORK_1_2_3_4_ARG pspStubCmIfDelayMs 79 | FN_INTERWORK_1_2_3_4_ARG pspStubCmIfTsGetMilli 80 | 81 | -------------------------------------------------------------------------------- /PspSerialStub/utils.S: -------------------------------------------------------------------------------- 1 | /** @file 2 | * PSP serial stub - Utility assembly routines. 3 | */ 4 | 5 | /* 6 | * Copyright (C) 2020 Alexander Eichner 7 | * 8 | * This library is free software; you can redistribute it and/or 9 | * modify it under the terms of the GNU Lesser General Public 10 | * License as published by the Free Software Foundation; either 11 | * version 2.1 of the License, or (at your option) any later version. 12 | * 13 | * This library is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 16 | * Lesser General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU Lesser General Public 19 | * License along with this library; if not, write to the Free Software 20 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 21 | */ 22 | 23 | /** 24 | * Writes to a co processor register 25 | * 26 | * @returns nothing. 27 | * @param r0 The value to write. 28 | */ 29 | .globl pspSerialStubCoProcWriteAsm 30 | pspSerialStubCoProcWriteAsm: 31 | mcr p15, 0, r0, cr0, cr0, 0 /* This will get overwritten with the appropriate arguments. */ 32 | bx lr 33 | .type pspSerialStubCoProcWriteAsm, %function; 34 | 35 | 36 | /** 37 | * Reads from a co processor register 38 | * 39 | * @returns The value read. 40 | */ 41 | .globl pspSerialStubCoProcReadAsm 42 | pspSerialStubCoProcReadAsm: 43 | mrc p15, 0, r0, cr0, cr0, 0 /* This will get overwritten with the appropriate arguments. */ 44 | bx lr 45 | .type pspSerialStubCoProcReadAsm, %function; 46 | 47 | 48 | /** 49 | * Branches to a given address using the given register set. 50 | * 51 | * @returns The value read. 52 | */ 53 | .globl pspStubBranchToAsm 54 | pspStubBranchToAsm: 55 | cpsid i /* Disable interrupts. */ 56 | mov lr, r0 57 | mov r12, r1 58 | ldmia r12!, {r0-r11} 59 | ldr r12, [r12] 60 | bx lr /* This branches to the destination, bye bye world it was really nice here... */ 61 | .type pspStubBranchToAsm, %function; 62 | 63 | 64 | -------------------------------------------------------------------------------- /PspStub/Makefile: -------------------------------------------------------------------------------- 1 | CROSS_COMPILE=arm-none-eabi- 2 | CFLAGS=-O2 -g -DIN_PSP -I../include -I../Lib/include -std=gnu99 -fomit-frame-pointer -nostartfiles -ffreestanding -Wextra -Werror 3 | VPATH=../Lib/src 4 | 5 | OBJS = main.o string.o svc.o log.o tm.o x86mem.o 6 | 7 | all : psp-stub.elf psp-stub.raw 8 | 9 | clean: 10 | rm -f _start.o $(OBJS) 11 | 12 | %.o: %.c 13 | $(CROSS_COMPILE)gcc $(CFLAGS) -c -o $@ $^ 14 | 15 | %.o: %.S 16 | $(CROSS_COMPILE)gcc $(CFLAGS) -c -o $@ $^ 17 | 18 | _start.o: ../Lib/_start.S 19 | $(CROSS_COMPILE)as -march=armv7-a -mcpu=cortex-a8 -o $@ $^ 20 | 21 | main.o: main.c 22 | $(CROSS_COMPILE)gcc $(CFLAGS) -c -o $@ main.c 23 | 24 | psp-stub.elf : ../build/linker.ld _start.o $(OBJS) 25 | $(CROSS_COMPILE)ld -T $^ -o $@ 26 | 27 | psp-stub.raw: psp-stub.elf 28 | $(CROSS_COMPILE)objcopy -O binary $^ $@ 29 | 30 | 31 | -------------------------------------------------------------------------------- /PspStub/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #include 11 | #include 12 | 13 | typedef struct PSPSTUBSTATE 14 | { 15 | /** The CPU ID of the PSP. */ 16 | uint32_t uCpuId; 17 | /** Flag whether a binary is loaded. */ 18 | uint8_t fBinLoaded; 19 | /** Flag whether the binary we loaded is run for the first time. */ 20 | uint8_t fFirstRun; 21 | /** Padding. */ 22 | uint8_t abPadding0[2]; 23 | /** State of the binary we loaded. */ 24 | uint8_t abBinState[2048]; 25 | /** The binary data itself we loaded. */ 26 | uint8_t abBinary[2048]; 27 | /** The logger instance to use. */ 28 | LOGGER Logger; 29 | /** Helper structure. */ 30 | BINLDRHLP Hlp; 31 | } PSPSTUBSTATE; 32 | /** Pointer to the binary loader state. */ 33 | typedef PSPSTUBSTATE *PPSPSTUBSTATE; 34 | 35 | typedef int32_t FNPSPREQHANDLER(PPSPSTUBSTATE pBinLdrState, PPSPSTUBREQHDR pReqHdr); 36 | typedef FNPSPREQHANDLER *PFNPSPREQHANDLER; 37 | 38 | typedef struct PSPSTUBREQHANDLER 39 | { 40 | /** Size of the request structure in bytes. */ 41 | uint32_t cbReq; 42 | /** The handler to call. */ 43 | PFNPSPREQHANDLER pfnReq; 44 | } PSPSTUBREQHANDLER; 45 | typedef const PSPSTUBREQHANDLER *PCPSPSTUBREQHANDLER; 46 | 47 | /** The global binary loader state. */ 48 | static PSPSTUBSTATE g_StubState; 49 | /** Our scratch buffer for temporary memory. */ 50 | static uint8_t g_abScratch[16 * 1024]; 51 | 52 | static void pspstubLoggerFlush(void *pvUser, uint8_t *pbBuf, size_t cbBuf) 53 | { 54 | (void)pvUser; 55 | svc_log_char_buf(pbBuf, cbBuf); 56 | } 57 | 58 | static void psp_stub_log(const char *pszFmt, ...) 59 | { 60 | va_list hArgs; 61 | va_start(hArgs, pszFmt); 62 | 63 | LOGLoggerV(&g_StubState.Logger, pszFmt, hArgs); 64 | 65 | va_end(hArgs); 66 | } 67 | 68 | static int bin_ldr_ctx_load_or_init(PPSPSTUBSTATE pCtx, uint32_t idCcd, uint32_t cCcds, uint8_t fFirstRun) 69 | { 70 | if (!fFirstRun) 71 | { 72 | void *pvLoad = svc_get_state_buffer(sizeof(*pCtx)); 73 | if (pvLoad != NULL) 74 | { 75 | memcpy(pCtx, pvLoad, sizeof(*pCtx)); 76 | LOGLoggerSetDefaultInstance(&pCtx->Logger); 77 | LogRel("Stub called, loading state\n"); 78 | } 79 | } 80 | else 81 | { 82 | pCtx->uCpuId = idCcd; 83 | pCtx->fBinLoaded = 0; 84 | pCtx->fFirstRun = 1; 85 | pCtx->Hlp.idCcd = idCcd; 86 | pCtx->Hlp.cCcds = cCcds; 87 | pCtx->Hlp.pfnLog = psp_stub_log; 88 | LOGLoggerInit(&pCtx->Logger, pspstubLoggerFlush, pCtx, 89 | "PspStub", NULL, 0); 90 | LOGLoggerSetDefaultInstance(&pCtx->Logger); 91 | LogRel("Stub called for the first time\n"); 92 | } 93 | 94 | return PSPSTATUS_SUCCESS; 95 | } 96 | 97 | static void bin_ldr_ctx_save(PPSPSTUBSTATE pCtx) 98 | { 99 | void *pvSave = svc_get_state_buffer(sizeof(*pCtx)); 100 | if (pvSave != NULL) 101 | memcpy(pvSave, pCtx, sizeof(*pCtx)); 102 | } 103 | 104 | static int bin_ldr_read_from_x86(X86PADDR PhysX86Addr, void *pvDst, size_t cbDst) 105 | { 106 | int rc = PSPSTATUS_SUCCESS; 107 | 108 | void *pvX86Map = svc_x86_host_memory_map(PhysX86Addr, 4); 109 | if (pvX86Map != NULL) 110 | { 111 | memcpy(pvDst, pvX86Map, cbDst); 112 | int rcPsp = svc_x86_host_memory_unmap(pvX86Map); 113 | if (rcPsp != PSPSTATUS_SUCCESS) 114 | LogRel("Unmapping x86 memory failed with %d\n", rc); 115 | } 116 | else 117 | { 118 | LogRel("Mapping x86 memory failed\n"); 119 | rc = ERR_INVALID_STATE; 120 | } 121 | 122 | return rc; 123 | } 124 | 125 | static int bin_ldr_write_to_x86(X86PADDR PhysX86Addr, void *pvSrc, size_t cbCopy) 126 | { 127 | int rc = PSPSTATUS_SUCCESS; 128 | 129 | void *pvX86Map = svc_x86_host_memory_map(PhysX86Addr, 4); 130 | if (pvX86Map != NULL) 131 | { 132 | memcpy(pvX86Map, pvSrc, cbCopy); 133 | int rcPsp = svc_x86_host_memory_unmap(pvX86Map); 134 | if (rcPsp != PSPSTATUS_SUCCESS) 135 | LogRel("Unmapping x86 memory failed with %d\n", rc); 136 | } 137 | else 138 | { 139 | LogRel("Mapping x86 memory failed\n"); 140 | rc = ERR_INVALID_STATE; 141 | } 142 | 143 | return rc; 144 | } 145 | 146 | 147 | static int32_t pspstubReqLoadBin(PPSPSTUBSTATE pBinLdrState, PPSPSTUBREQHDR pReqHdr) 148 | { 149 | PPSPSTUBREQLOADBIN pReq = (PPSPSTUBREQLOADBIN)pReqHdr; 150 | int32_t rc = INF_SUCCESS; 151 | 152 | if (pReq->cbBinary <= sizeof(pBinLdrState->abBinary)) 153 | { 154 | LogRel("Loading binary from %#X (%u bytes)\n", pReq->PhysX86AddrLoad, pReq->cbBinary); 155 | rc = bin_ldr_read_from_x86(pReq->PhysX86AddrLoad, (uint8_t *)&pBinLdrState->abBinary[0], 156 | pReq->cbBinary); 157 | if (rc == PSPSTATUS_SUCCESS) 158 | { 159 | pBinLdrState->fFirstRun = 1; 160 | pBinLdrState->fBinLoaded = 1; 161 | LogRel("Loaded binary successfully\n"); 162 | return INF_SUCCESS; 163 | } 164 | else 165 | LogRel("Loading binary failed\n"); 166 | } 167 | else 168 | { 169 | LogRel("Binary exceeds internal buffer size\n"); 170 | rc = ERR_BUFFER_OVERFLOW; 171 | } 172 | 173 | return rc; 174 | } 175 | 176 | 177 | static int32_t pspstubReqExecBin(PPSPSTUBSTATE pBinLdrState, PPSPSTUBREQHDR pReqHdr) 178 | { 179 | PPSPSTUBREQEXECBIN pReq = (PPSPSTUBREQEXECBIN)pReqHdr; 180 | 181 | int32_t rc = INF_SUCCESS; 182 | 183 | LogRel("Calling loaded binary\n"); 184 | 185 | memcpy((void *)(uintptr_t)BIN_LOADER_LOAD_ADDR, &g_StubState.abBinary[0], sizeof(g_StubState.abBinary)); 186 | ((PFNBINLOADENTRY)BIN_LOADER_LOAD_ADDR)(&g_StubState.abBinState[0], &pBinLdrState->Hlp, pReq->PhysX8AddrExec, 0, pBinLdrState->fFirstRun); 187 | pBinLdrState->fFirstRun = 0; 188 | 189 | return rc; 190 | } 191 | 192 | 193 | static int32_t pspstubReqSmnRwWorker(PPSPSTUBSTATE pBinLdrState, PPSPSTUBREQHDR pReqHdr, uint8_t fWrite) 194 | { 195 | PPSPSTUBREQSMNRW pReq = (PPSPSTUBREQSMNRW)pReqHdr; 196 | int32_t rc = INF_SUCCESS; 197 | 198 | void *pvSmn = svc_smn_map_ex(pReq->u32Addr, pReq->idCcdTgt); 199 | if (pvSmn != NULL) 200 | { 201 | if (fWrite) 202 | { 203 | switch (pReq->cbVal) 204 | { 205 | case 1: 206 | *(volatile uint8_t *)pvSmn = (uint8_t)pReq->u64Val; 207 | break; 208 | case 2: 209 | *(volatile uint16_t *)pvSmn = (uint16_t)pReq->u64Val; 210 | break; 211 | case 4: 212 | *(volatile uint32_t *)pvSmn = (uint32_t)pReq->u64Val; 213 | break; 214 | case 8: 215 | *(volatile uint64_t *)pvSmn = (uint64_t)pReq->u64Val; 216 | break; 217 | default: 218 | LogRel("Invalid write size %u\n", pReq->cbVal); 219 | rc = ERR_INVALID_PARAMETER; 220 | } 221 | } 222 | else 223 | { 224 | switch (pReq->cbVal) 225 | { 226 | case 1: 227 | pReq->u64Val = (uint64_t)*(volatile uint8_t *)pvSmn; 228 | break; 229 | case 2: 230 | pReq->u64Val = (uint64_t)*(volatile uint16_t *)pvSmn; 231 | break; 232 | case 4: 233 | pReq->u64Val = (uint64_t)*(volatile uint32_t *)pvSmn; 234 | break; 235 | case 8: 236 | pReq->u64Val = *(volatile uint64_t *)pvSmn; 237 | break; 238 | default: 239 | LogRel("Invalid read size %u\n", pReq->cbVal); 240 | rc = ERR_INVALID_PARAMETER; 241 | } 242 | } 243 | 244 | svc_smn_unmap(pvSmn); 245 | } 246 | else 247 | { 248 | LogRel("Mapping SMN address %#x on CCD %u failed\n", pReq->u32Addr, pReq->idCcdTgt); 249 | rc = ERR_INVALID_STATE; 250 | } 251 | 252 | return rc; 253 | } 254 | 255 | static int32_t pspstubReqSmnRead(PPSPSTUBSTATE pBinLdrState, PPSPSTUBREQHDR pReqHdr) 256 | { 257 | return pspstubReqSmnRwWorker(pBinLdrState, pReqHdr, 0 /*fWrite*/); 258 | } 259 | 260 | 261 | static int32_t pspstubReqSmnWrite(PPSPSTUBSTATE pBinLdrState, PPSPSTUBREQHDR pReqHdr) 262 | { 263 | return pspstubReqSmnRwWorker(pBinLdrState, pReqHdr, 1 /*fWrite*/); 264 | } 265 | 266 | 267 | static int32_t pspstubReqPspRwWorker(PPSPSTUBSTATE pBinLdrState, PPSPSTUBREQHDR pReqHdr, uint8_t fWrite) 268 | { 269 | PCPSPSTUBREQPSPRW pReq = (PCPSPSTUBREQPSPRW)pReqHdr; 270 | void *pvAddrPsp = (void *)pReq->u32Addr; 271 | int32_t rc = PSPSTATUS_SUCCESS; 272 | 273 | void *pvX86Map = svc_x86_host_memory_map(pReq->PhysX86Addr, 4); 274 | if (pvX86Map != NULL) 275 | { 276 | if (fWrite) 277 | memcpy(pvAddrPsp, pvX86Map, pReq->cbCopy); 278 | else 279 | memcpy(pvX86Map, pvAddrPsp, pReq->cbCopy); 280 | int rcPsp = svc_x86_host_memory_unmap(pvX86Map); 281 | if (rcPsp != PSPSTATUS_SUCCESS) 282 | { 283 | LogRel("Unmapping x86 memory failed with %d\n", rc); 284 | rc = ERR_INVALID_STATE; 285 | } 286 | } 287 | else 288 | { 289 | LogRel("Mapping x86 memory failed\n"); 290 | rc = ERR_INVALID_STATE; 291 | } 292 | 293 | return rc; 294 | } 295 | 296 | static int32_t pspstubReqPspRead(PPSPSTUBSTATE pBinLdrState, PPSPSTUBREQHDR pReqHdr) 297 | { 298 | return pspstubReqPspRwWorker(pBinLdrState, pReqHdr, 0 /*fWrite*/); 299 | } 300 | 301 | 302 | static int32_t pspstubReqPspWrite(PPSPSTUBSTATE pBinLdrState, PPSPSTUBREQHDR pReqHdr) 303 | { 304 | return pspstubReqPspRwWorker(pBinLdrState, pReqHdr, 1 /*fWrite*/); 305 | } 306 | 307 | 308 | static int32_t pspstubReqSvcCall(PPSPSTUBSTATE pBinLdrState, PPSPSTUBREQHDR pReqHdr) 309 | { 310 | PPSPSTUBREQCALLSVC pReq = (PPSPSTUBREQCALLSVC)pReqHdr; 311 | 312 | /* Modify the svc template to call the requested syscall. */ 313 | volatile uint8_t *pbSyscall = (volatile uint8_t *)svc_template; 314 | *pbSyscall++ = (uint8_t)(pReq->idxSyscall & 0xff); 315 | *pbSyscall++ = (uint8_t)(pReq->idxSyscall >> 8)& 0xff; 316 | *pbSyscall++ = (uint8_t)(pReq->idxSyscall >> 16)& 0xff; 317 | *pbSyscall = 0xef; /* svc */ 318 | 319 | #if 0 320 | uint32_t *pu32Syscall = (uint32_t *)svc_template; 321 | 322 | for (uint32_t i = 0; i < 4; i++) 323 | LogRel("BinLoader#%u: SVC[%u]: %#x\n", pBinLdrState->uCpuId, i, pu32Syscall[i]); 324 | #endif 325 | 326 | /* Clean instruction cache. */ 327 | svc_invalidate_mem(SVC_INV_MEM_OP_CLEAN_AND_INVALIDATE, 1 /*fInsnMem*/, (void *)svc_template, sizeof(uint64_t)); 328 | pReq->u32R0Return = svc_template(pReq->u32R0, pReq->u32R1, pReq->u32R2, pReq->u32R3); 329 | 330 | return INF_SUCCESS; 331 | } 332 | 333 | 334 | static int32_t pspstubReqQueryInfo(PPSPSTUBSTATE pBinLdrState, PPSPSTUBREQHDR pReqHdr) 335 | { 336 | PPSPSTUBREQQUERYINFO pReq = (PPSPSTUBREQQUERYINFO)pReqHdr; 337 | 338 | pReq->u32PspScratchAddr = (uint32_t)(uintptr_t)&g_abScratch[0]; 339 | pReq->cbScratch = sizeof(g_abScratch); 340 | 341 | return INF_SUCCESS; 342 | } 343 | 344 | 345 | /** Request handlers. */ 346 | static const PSPSTUBREQHANDLER g_aReqHandlers[] = 347 | { 348 | { sizeof(PSPSTUBREQLOADBIN), pspstubReqLoadBin }, 349 | { sizeof(PSPSTUBREQEXECBIN), pspstubReqExecBin }, 350 | { sizeof(PSPSTUBREQSMNRW), pspstubReqSmnRead }, 351 | { sizeof(PSPSTUBREQSMNRW), pspstubReqSmnWrite }, 352 | { sizeof(PSPSTUBREQPSPRW), pspstubReqPspRead }, 353 | { sizeof(PSPSTUBREQPSPRW), pspstubReqPspWrite }, 354 | { sizeof(PSPSTUBREQCALLSVC), pspstubReqSvcCall }, 355 | { sizeof(PSPSTUBREQQUERYINFO), pspstubReqQueryInfo } 356 | }; 357 | 358 | 359 | typedef struct BINLDRSLVREQ 360 | { 361 | uint32_t idCmd; 362 | X86PADDR PhysX86AddrReqBuf; 363 | } BINLDRSLVREQ; 364 | typedef BINLDRSLVREQ *PBINLDRSLVREQ; 365 | 366 | uint32_t main(uint32_t idCcd, uint32_t cCcds, PSEVCMDBUF pCmdBuf, uint8_t fFirstRun) 367 | { 368 | if (bin_ldr_ctx_load_or_init(&g_StubState, idCcd, cCcds, fFirstRun) != PSPSTATUS_SUCCESS) 369 | return 1; 370 | 371 | g_StubState.Hlp.pvCmdBuf = (void *)pCmdBuf; 372 | 373 | if (idCcd == 0) 374 | { 375 | uint32_t idCmd = (pCmdBuf->idCmd >> 16) & 0xff; 376 | X86PADDR PhysX86AddrReqBuf = (X86PADDR)pCmdBuf->PhysX86CmdBufHigh << 32 | pCmdBuf->PhysX86CmdBufLow; 377 | 378 | if (idCmd >= PSP_STUB_REQ_FIRST && idCmd <= PSP_STUB_REQ_LAST) 379 | { 380 | PCPSPSTUBREQHANDLER pHandler = &g_aReqHandlers[idCmd - PSP_STUB_REQ_FIRST]; 381 | PSPSTUBREQ BinLoaderReq; 382 | 383 | LogRel("Loading request buffer from %#X (%u bytes)\n", PhysX86AddrReqBuf, pHandler->cbReq); 384 | int rc = bin_ldr_read_from_x86(PhysX86AddrReqBuf, &BinLoaderReq, pHandler->cbReq); 385 | if (rc == PSPSTATUS_SUCCESS) 386 | { 387 | /* Check whether the request is designated for us or one of the slaves. */ 388 | if (BinLoaderReq.Hdr.idCcd == 0) 389 | { 390 | /* Execute handler and pass return value back. */ 391 | int32_t rcReq = pHandler->pfnReq(&g_StubState, &BinLoaderReq.Hdr); 392 | BinLoaderReq.Hdr.i32Sts = rcReq; 393 | rc = bin_ldr_write_to_x86(PhysX86AddrReqBuf, &BinLoaderReq, pHandler->cbReq); 394 | if (rc != PSPSTATUS_SUCCESS) 395 | LogRel("writing request buffer back failed with %d\n", rc); 396 | } 397 | else 398 | { 399 | BINLDRSLVREQ SlvReq; 400 | 401 | LogRel("Poking slave CCD %u\n", BinLoaderReq.Hdr.idCcd); 402 | SlvReq.idCmd = idCmd; 403 | SlvReq.PhysX86AddrReqBuf = PhysX86AddrReqBuf; 404 | uint32_t rcPsp = svc_call_other_psp(BinLoaderReq.Hdr.idCcd, &SlvReq, sizeof(SlvReq)); 405 | LogRel("Poking slave returned %u\n", rcPsp); 406 | } 407 | } 408 | else 409 | LogRel("Reading request buffer failed with %d\n", rc); 410 | } 411 | else 412 | LogRel("Ignoring command %#x probably designated for original SEV APP\n", idCmd); 413 | } 414 | else 415 | { 416 | PBINLDRSLVREQ pSlvReq = (PBINLDRSLVREQ)pCmdBuf; 417 | 418 | LogRel("Got kicked by master\n"); 419 | PCPSPSTUBREQHANDLER pHandler = &g_aReqHandlers[pSlvReq->idCmd - PSP_STUB_REQ_FIRST]; 420 | PSPSTUBREQ BinLoaderReq; 421 | 422 | LogRel("Loading request buffer from %#X (%u bytes)\n", pSlvReq->PhysX86AddrReqBuf, pHandler->cbReq); 423 | int rc = bin_ldr_read_from_x86(pSlvReq->PhysX86AddrReqBuf, &BinLoaderReq, pHandler->cbReq); 424 | if (rc == PSPSTATUS_SUCCESS) 425 | { 426 | /* Execute handler and pass return value back. */ 427 | int32_t rcReq = pHandler->pfnReq(&g_StubState, &BinLoaderReq.Hdr); 428 | BinLoaderReq.Hdr.i32Sts = rcReq; 429 | rc = bin_ldr_write_to_x86(pSlvReq->PhysX86AddrReqBuf, &BinLoaderReq, pHandler->cbReq); 430 | if (rc != PSPSTATUS_SUCCESS) 431 | LogRel("writing request buffer back failed with %d\n", rc); 432 | } 433 | else 434 | LogRel("Reading request buffer failed with %d\n", rc); 435 | } 436 | 437 | bin_ldr_ctx_save(&g_StubState); 438 | return 0; 439 | } 440 | -------------------------------------------------------------------------------- /PspUartHelloWorld/Makefile: -------------------------------------------------------------------------------- 1 | CROSS_COMPILE=arm-none-eabi- 2 | CFLAGS=-Os -DIN_PSP -g -I../include -I../Lib/include -std=gnu99 -fomit-frame-pointer -nostartfiles -nostdlib -ffreestanding -Wextra -Werror -march=armv7-a -marm 3 | VPATH=../Lib/src 4 | LIBGCC=$(shell $(CROSS_COMPILE)gcc -print-libgcc-file-name) 5 | LDFLAGS=$(LIBGCC) 6 | 7 | ifeq ($(TARGET), PRIME-X370) 8 | CFLAGS += -DTARGET=1 9 | else ifeq ($(TARGET), H11DSU-IN) 10 | CFLAGS += -DTARGET=2 11 | endif 12 | 13 | OBJS = main.o misc.o string.o uart.o x86-map.o smn-map.o platform.o 14 | 15 | all : hello_world.elf hello_world.raw 16 | 17 | clean: 18 | rm -f _svc-start.o $(OBJS) hello_world.raw hello_world.map hello_world.elf 19 | 20 | %.o: %.c 21 | $(CROSS_COMPILE)gcc $(CFLAGS) -c -o $@ $^ 22 | 23 | %.o: %.S 24 | $(CROSS_COMPILE)gcc $(CFLAGS) -c -o $@ $^ 25 | 26 | _svc-start.o: ../Lib/_svc-start.S 27 | $(CROSS_COMPILE)as -march=armv7ve -o $@ $^ 28 | 29 | main.o: main.c 30 | $(CROSS_COMPILE)gcc $(CFLAGS) -c -o $@ main.c 31 | 32 | hello_world.elf : ../build/svc-linker.ld _svc-start.o $(OBJS) 33 | $(CROSS_COMPILE)ld -Map=hello_world.map -T $^ -o $@ $(LDFLAGS) 34 | 35 | hello_world.raw: hello_world.elf 36 | $(CROSS_COMPILE)objcopy -O binary $^ $@ 37 | 38 | -------------------------------------------------------------------------------- /PspUartHelloWorld/main.c: -------------------------------------------------------------------------------- 1 | /** @file PSP Hello World. 2 | */ 3 | 4 | /* 5 | * Copyright (C) 2020 Alexander Eichner 6 | * Copyright (C) 2020 Robert Buhren 7 | * 8 | * This library is free software; you can redistribute it and/or 9 | * modify it under the terms of the GNU Lesser General Public 10 | * License as published by the Free Software Foundation; either 11 | * version 2.1 of the License, or (at your option) any later version. 12 | * 13 | * This library is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 16 | * Lesser General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU Lesser General Public 19 | * License along with this library; if not, write to the Free Software 20 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 21 | */ 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | 34 | /** 35 | * x86 UART device I/O interface. 36 | */ 37 | typedef struct PSPPDUTRANSPINT 38 | { 39 | /** Device I/O interface. */ 40 | PSPIODEVIF IfIoDev; 41 | /** The MMIO mapping of the UART. */ 42 | volatile void *pvUart; 43 | } PSPPDUTRANSPINT; 44 | 45 | /** Pointer to the x86 UART PDU transport channel instance. */ 46 | typedef PSPPDUTRANSPINT *PPSPPDUTRANSPINT; 47 | 48 | /** 49 | * x86 UART register read callback. 50 | */ 51 | static int pspUartRegRead(PCPSPIODEVIF pIfIoDev, uint32_t offReg, void *pvBuf, size_t cbRead) 52 | { 53 | PPSPPDUTRANSPINT pThis = (PPSPPDUTRANSPINT)pIfIoDev; 54 | 55 | /* UART supports only 1 byte wide register accesses. */ 56 | if (cbRead != 1) return ERR_INVALID_STATE; 57 | 58 | *(uint8_t *)pvBuf = *(volatile uint8_t *)((uintptr_t)pThis->pvUart + offReg); 59 | return INF_SUCCESS; 60 | } 61 | 62 | /** 63 | * x86 UART register write callback. 64 | */ 65 | static int pspUartRegWrite(PCPSPIODEVIF pIfIoDev, uint32_t offReg, const void *pvBuf, size_t cbWrite) 66 | { 67 | PPSPPDUTRANSPINT pThis = (PPSPPDUTRANSPINT)pIfIoDev; 68 | 69 | /* UART supports only 1 byte wide register accesses. */ 70 | if (cbWrite != 1) return ERR_INVALID_STATE; 71 | 72 | *(volatile uint8_t *)((uintptr_t)pThis->pvUart + offReg) = *(uint8_t *)pvBuf; 73 | return INF_SUCCESS; 74 | } 75 | 76 | void ExcpUndefInsn(PPSPIRQREGFRAME pRegFrame) { 77 | (void)pRegFrame; 78 | /* For now, just stall the execution */ 79 | do {} while(1); 80 | } 81 | 82 | void ExcpSwi(void) { 83 | /* For now, just stall the execution */ 84 | do {} while(1); 85 | } 86 | 87 | void ExcpPrefAbrt(PPSPIRQREGFRAME pRegFrame) { 88 | (void)pRegFrame; 89 | /* For now, just stall the execution */ 90 | do {} while(1); 91 | } 92 | 93 | void ExcpDataAbrt(PPSPIRQREGFRAME pRegFrame) { 94 | (void)pRegFrame; 95 | /* For now, just stall the execution */ 96 | do {} while(1); 97 | } 98 | 99 | void ExcpIrq(PPSPIRQREGFRAME pRegFrame) { 100 | (void)pRegFrame; 101 | /* For now, just stall the execution */ 102 | do {} while(1); 103 | } 104 | 105 | void ExcpFiq(void) { 106 | /* For now, just stall the execution */ 107 | do {} while(1); 108 | } 109 | 110 | int main(void) 111 | { 112 | PSPUART uart; 113 | PSPPDUTRANSPINT ptrans; 114 | ptrans.IfIoDev.pfnRegWrite = pspUartRegWrite; 115 | ptrans.IfIoDev.pfnRegRead = pspUartRegRead; 116 | ptrans.pvUart = NULL; 117 | 118 | /* Disable IRQs */ 119 | pspIrqDisable(); 120 | 121 | /* Don't do anything if this is not the master PSP. */ 122 | /* @todo Figure out why this is required to get the UART working. */ 123 | if (pspGetPhysDieId() != 0) 124 | { 125 | for (;;); 126 | } 127 | 128 | /* Basic initialization of the SOC and the SuperIO. */ 129 | pspPlatformInit(); 130 | 131 | /* Map the memory-mapped UART ioports into the PSP address space */ 132 | pspX86PhysMap(0xfffdfc0003f8, true, (void**)&ptrans.pvUart); 133 | 134 | /* Create the UART object and initialize the UART */ 135 | PSPUartCreate(&uart, &(ptrans.IfIoDev)); 136 | PSPUartParamsSet(&uart, 115200, PSPUARTDATABITS_8BITS, PSPUARTPARITY_NONE, PSPUARTSTOPBITS_1BIT); 137 | 138 | /* Write "Hello World!" to the uart */ 139 | PSPUartWrite(&uart, "Hello World!\n", sizeof("Hello World!\n"), NULL); 140 | 141 | for(;;); 142 | } 143 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # psp-apps 2 | Custom PSP app framework 3 | -------------------------------------------------------------------------------- /StubCodeModules/HelloWorld/Makefile: -------------------------------------------------------------------------------- 1 | CROSS_COMPILE=arm-none-eabi- 2 | CFLAGS=-O2 -DIN_PSP -g -I../../include -I../../Lib/include -std=gnu99 -fomit-frame-pointer -nostartfiles -ffreestanding -Wextra -Werror -march=armv7ve -mthumb -mthumb-interwork 3 | VPATH=../Lib/src 4 | 5 | OBJS = main.o 6 | 7 | all : cm-hello-world.elf cm-hello-world.raw 8 | 9 | clean: 10 | rm -f $(OBJS) cm-hello-world.elf cm-hello-world.raw 11 | 12 | %.o: %.c 13 | $(CROSS_COMPILE)gcc $(CFLAGS) -c -o $@ $^ 14 | 15 | %.o: %.S 16 | $(CROSS_COMPILE)gcc $(CFLAGS) -c -o $@ $^ 17 | 18 | _cm-start.o: ../../Lib/_cm-start.S 19 | $(CROSS_COMPILE)as -march=armv7ve -o $@ $^ 20 | 21 | cm-hello-world.elf : ../../build/cm-linker.ld _cm-start.o $(OBJS) 22 | $(CROSS_COMPILE)ld -Map=cm-hello-world.map -T $^ -o $@ 23 | 24 | cm-hello-world.raw: cm-hello-world.elf 25 | $(CROSS_COMPILE)objcopy -O binary $^ $@ 26 | 27 | 28 | -------------------------------------------------------------------------------- /StubCodeModules/HelloWorld/main.c: -------------------------------------------------------------------------------- 1 | /** @file 2 | * PSP code module - Hello World. 3 | */ 4 | 5 | /* 6 | * Copyright (C) 2020 Alexander Eichner 7 | * 8 | * This library is free software; you can redistribute it and/or 9 | * modify it under the terms of the GNU Lesser General Public 10 | * License as published by the Free Software Foundation; either 11 | * version 2.1 of the License, or (at your option) any later version. 12 | * 13 | * This library is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 16 | * Lesser General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU Lesser General Public 19 | * License along with this library; if not, write to the Free Software 20 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 21 | */ 22 | #include 23 | #include 24 | 25 | #include 26 | 27 | uint32_t main(PCCMIF pCmIf, uint32_t u32Arg0, uint32_t u32Arg1, uint32_t u32Arg2, uint32_t u32Arg3) 28 | { 29 | return pCmIf->pfnOutBufWrite(pCmIf, 0 /*idOutBuf*/, "Hello World!\n", sizeof("Hello World!\n") - 1, NULL /*pcbWritten*/); 30 | } 31 | -------------------------------------------------------------------------------- /Tools/psp-log-dump.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | import csv; 3 | import sys; 4 | import os; 5 | import struct; 6 | 7 | from enum import Enum; 8 | 9 | g_PspMarker1 = 0xd00f; 10 | g_PspMarker2 = 0xf00d; 11 | g_PspMarker3 = 0xfeed; 12 | g_PspMarker4 = 0xfade; 13 | g_DbgLogMarker = 0xdead; 14 | 15 | class PspState(Enum): 16 | DETECTING_1 = 1 17 | DETECTING_2 = 2 18 | DETECTING_3 = 3 19 | IDLE = 2 # Waiting for a debug marker 20 | DBG_LOG = 3 # Dumping a debug log 21 | 22 | class Psp(object): 23 | """ 24 | The class representing a single PSP. 25 | """ 26 | 27 | def __init__(self, idPsp, idDbgMarker): 28 | self.idPsp = idPsp; 29 | self.idDbgMarker = idDbgMarker; 30 | self.enmState = PspState.DETECTING_1; 31 | self.sLog = ''; 32 | 33 | def getId(self): 34 | return self.idPsp; 35 | 36 | def getState(self): 37 | return self.enmState; 38 | 39 | def setState(self, enmState): 40 | self.enmState = enmState; 41 | 42 | def appendToLog(self, sAppend): 43 | self.sLog += sAppend; 44 | 45 | class PspLogExtractor(object): 46 | """ 47 | The main class handling log extraction from CSV exported logic traces. 48 | """ 49 | 50 | def __init__(self): 51 | self.sToolName = None; 52 | self.sInput = None; 53 | self.fInputCsv = True; 54 | self.sOutputLog = None; 55 | self.dPspDetected = { }; # The dictionary containing the detected PSPs keyed by ID 56 | 57 | def showUsage(self): 58 | """ 59 | Prints the usage of the tool to stdout. 60 | """ 61 | print('%s Options:' % (self.sToolName,)); 62 | print(' --input-csv '); 63 | print(' The path to the logic trace in CSV format'); 64 | print(' --input-binary '); 65 | print(' The path to the logic trace in raw binary format'); 66 | print(' --output '); 67 | print(' Where to store the extracted log'); 68 | 69 | def parseOption(self, asArgs, iArg): 70 | """ 71 | Parses a single option at the given index. 72 | """ 73 | if asArgs[iArg] == '--input-csv': 74 | iArg += 1; 75 | if iArg >= len(asArgs): raise Exception('Invalid option', '--input-csv takes a file path'); 76 | self.sInput = asArgs[iArg]; 77 | self.fInputCsv = True; 78 | elif asArgs[iArg] == '--input-binary': 79 | iArg += 1; 80 | if iArg >= len(asArgs): raise Exception('Invalid option', '--input-binary takes a file path'); 81 | self.sInput = asArgs[iArg]; 82 | self.fInputCsv = False; 83 | elif asArgs[iArg] == '--output': 84 | iArg += 1; 85 | if iArg >= len(asArgs): raise Exception('Invalid option', '--output takes a file path'); 86 | self.sOutputLog = asArgs[iArg]; 87 | else: 88 | self.showUsage(); 89 | raise Exception('Invalid option', 'Option "%s" is unknown' % (asArgs[iArg],)); 90 | 91 | return iArg + 1; 92 | 93 | def main(self, asArgs = None): 94 | """ 95 | Main entry point doing the argument parsing and doing the work. 96 | """ 97 | 98 | self.sToolName = asArgs[0]; 99 | iArg = 1; 100 | try: 101 | while iArg < len(asArgs): 102 | iNext = self.parseOption(asArgs, iArg); 103 | if iNext == iArg: 104 | self.showUsage(); 105 | raise Exception('Invalid option', 'Option "%s" is unknown' % (asArgs[iArg],)); 106 | iArg = iNext; 107 | except Exception as oXcpt: 108 | print(oXcpt); 109 | sys.exit(1); 110 | 111 | # Check that all required options present. 112 | if self.sInput is None\ 113 | or self.sOutputLog is None: 114 | print('A required option is missing'); 115 | self.showUsage(); 116 | sys.exit(1); 117 | 118 | if self.fInputCsv: 119 | # Load the CSV 120 | oInputCsv = open(self.sInput); 121 | oCsvRdr = csv.reader(oInputCsv, delimiter=','); 122 | 123 | # Extract the MOSI lines and convert to byte array 124 | # @todo Improve and don't require to create a big chunk of memory. 125 | sRes = ' '.join(sLine[2].strip()[2:] for sLine in oCsvRdr); 126 | abBytes = bytearray.fromhex(sRes[3:]); 127 | 128 | oInputCsv.close(); 129 | else: 130 | oInputBin = open(self.sInput, 'rb'); 131 | abBytes = bytearray(oInputBin.read()); 132 | oInputBin.close(); 133 | 134 | oLogOut = open(self.sOutputLog + '.raw', "wb"); 135 | oLogOut.write(abBytes); 136 | oLogOut.close(); 137 | 138 | # Traverse bytes and look for a debug marker. 139 | idxBytes = 0; 140 | while idxBytes < len(abBytes): 141 | if idxBytes + 4 >= len(abBytes): 142 | break; 143 | 144 | uMarker, uPspId = struct.unpack('> 8) != 0: 207 | oPsp.appendToLog(str(chr((uMarker >> 8) & 0xff))); 208 | idxBytes += 4; 209 | else: 210 | idxBytes += 1; 211 | 212 | if idxBytes % (1024 * 1024) == 0: 213 | print('Processed %s out of %s bytes' % (idxBytes, len(abBytes))); 214 | 215 | oLogOut = open(self.sOutputLog, "w"); 216 | 217 | for oPsp in self.dPspDetected.values(): 218 | oLogOut.write('\n\n\n'); 219 | oLogOut.write('Log of PSP %s: \n' % (oPsp.getId(), )); 220 | oLogOut.write(oPsp.sLog); 221 | oLogOut.close(); 222 | 223 | sys.exit(0); 224 | 225 | 226 | if __name__ == '__main__': 227 | sys.exit(PspLogExtractor().main(sys.argv)); 228 | -------------------------------------------------------------------------------- /build/cm-linker.ld: -------------------------------------------------------------------------------- 1 | MEMORY 2 | { 3 | RAM : ORIGIN = 0x10000, LENGTH = 0x2f000 /* Code module area from 0x10000 right to the start of the boot ROM servie page */ 4 | } 5 | 6 | 7 | SECTIONS 8 | { 9 | . = 0x10000; 10 | 11 | .text ALIGN(0x10): 12 | { 13 | *(.text); 14 | *(.text*); 15 | } > RAM 16 | 17 | .rodata ALIGN(0x10): 18 | { 19 | *(.rodata) 20 | *(.rodata*) 21 | } > RAM 22 | 23 | .data ALIGN(0x10): 24 | { 25 | *(.data) 26 | *(.data*) 27 | } > RAM 28 | 29 | .bss ALIGN(0x10): 30 | { 31 | BSS_START = .; 32 | *(.bss) 33 | *(.bss*) 34 | BSS_END = .; 35 | } > RAM 36 | } 37 | 38 | -------------------------------------------------------------------------------- /build/linker.ld: -------------------------------------------------------------------------------- 1 | 2 | SECTIONS 3 | { 4 | . = 0x15100; 5 | .text ALIGN(0x10): { *(.text) } 6 | .data ALIGN(0x10) : { *(.data) } 7 | BSS_START = .; 8 | .bss ALIGN(0x10) : { *(.bss) } 9 | BSS_END = .; 10 | 11 | SCRATCH_STACK_BASE = .; 12 | . += 0x2000; 13 | SCRATCH_STACK_TOP = .; 14 | } 15 | -------------------------------------------------------------------------------- /build/linker_binload.ld: -------------------------------------------------------------------------------- 1 | 2 | SECTIONS 3 | { 4 | . = 0x1d000; 5 | .text ALIGN(0x10): { *(.text) } 6 | .data ALIGN(0x10) : { *(.data) } 7 | .bss ALIGN(0x10) : { *(.bss) } 8 | } 9 | -------------------------------------------------------------------------------- /build/linker_zen2.ld: -------------------------------------------------------------------------------- 1 | 2 | SECTIONS 3 | { 4 | . = 0x1b100; 5 | .text ALIGN(0x10): { *(.text) } 6 | .data ALIGN(0x10) : { *(.data) } 7 | BSS_START = .; 8 | .bss ALIGN(0x10) : { *(.bss) } 9 | BSS_END = .; 10 | 11 | SCRATCH_STACK_BASE = .; 12 | . += 0x2000; 13 | SCRATCH_STACK_TOP = .; 14 | } 15 | -------------------------------------------------------------------------------- /build/svc-linker.ld: -------------------------------------------------------------------------------- 1 | MEMORY 2 | { 3 | RAM : ORIGIN = 0x0, LENGTH = 64K 4 | } 5 | 6 | 7 | SECTIONS 8 | { 9 | . = 0x100; 10 | 11 | .text ALIGN(0x10): 12 | { 13 | *(.text); 14 | *(.text*); 15 | } > RAM 16 | 17 | .rodata ALIGN(0x10): 18 | { 19 | *(.rodata) 20 | *(.rodata*) 21 | } > RAM 22 | 23 | .data ALIGN(0x10): 24 | { 25 | *(.data) 26 | *(.data*) 27 | } > RAM 28 | 29 | .bss ALIGN(0x10): 30 | { 31 | BSS_START = .; 32 | *(.bss) 33 | *(.bss*) 34 | BSS_END = .; 35 | } > RAM 36 | 37 | .stack ALIGN(0x10): 38 | { 39 | SCRATCH_STACK_BASE_SVC = .; 40 | . += 0x2000; 41 | SCRATCH_STACK_TOP_SVC = .; 42 | 43 | SCRATCH_STACK_BASE_UNDEF = .; 44 | . += 0x200; 45 | SCRATCH_STACK_TOP_UNDEF = .; 46 | 47 | SCRATCH_STACK_BASE_ABORT = .; 48 | . += 0x200; 49 | SCRATCH_STACK_TOP_ABORT = .; 50 | 51 | SCRATCH_STACK_BASE_IRQ = .; 52 | . += 0x200; 53 | SCRATCH_STACK_TOP_IRQ = .; 54 | 55 | SCRATCH_STACK_BASE_FIQ = .; 56 | . += 0x200; 57 | SCRATCH_STACK_TOP_FIQ = .; 58 | } > RAM 59 | 60 | _ram_end = ORIGIN(RAM) + LENGTH(RAM); 61 | } 62 | 63 | --------------------------------------------------------------------------------