├── .gitignore ├── .gitmodules ├── CMakeLists.txt ├── LICENSE ├── README.md ├── include ├── os │ ├── file.h │ ├── lock.h │ ├── tcp.h │ ├── thread.h │ └── time.h ├── psp-brsp.h ├── psp-ccd.h ├── psp-cfg.h ├── psp-core.h ├── psp-cov.h ├── psp-dbg-hlp.h ├── psp-dbg.h ├── psp-dev.h ├── psp-devs.h ├── psp-disasm.h ├── psp-flash.h ├── psp-iolog-replay.h ├── psp-iolog.h ├── psp-iom.h ├── psp-irq.h ├── psp-profile.h ├── psp-proxy.h ├── psp-svc.h ├── psp-trace.h └── psp-x86-ice.h ├── obsolete └── psp_emu.c ├── os ├── file.c └── posix │ ├── lock.c │ ├── tcp.c │ ├── thread.c │ └── time.c ├── profiles ├── amd-cpu-ryzen5-5600x.h ├── amd-cpu-ryzen7-1800x.h ├── amd-cpu-zen-synthetic.h ├── amd-psp-zen-2.h ├── amd-psp-zen-3.h ├── amd-psp-zen-plus.h ├── amd-psp-zen.h └── proxy-blocked-range-std.h ├── psp-brsp.c ├── psp-ccd.c ├── psp-cfg.c ├── psp-core.c ├── psp-cov.c ├── psp-dbg-hlp.c ├── psp-dbg.c ├── psp-dev-acpi.c ├── psp-dev-ccp-v5.c ├── psp-dev-flash.c ├── psp-dev-fuse.c ├── psp-dev-gpio.c ├── psp-dev-iomux.c ├── psp-dev-lpc.c ├── psp-dev-mmio-unknown.c ├── psp-dev-mp2.c ├── psp-dev-rtc.c ├── psp-dev-smn-unknown.c ├── psp-dev-smu.c ├── psp-dev-status.c ├── psp-dev-timer.c ├── psp-dev-version.c ├── psp-dev-x86-mem.c ├── psp-dev-x86-uart.c ├── psp-dev-x86-unknown.c ├── psp-dev.c ├── psp-disasm.c ├── psp-emu.c ├── psp-flash.c ├── psp-iolog-replay.c ├── psp-iolog-tool.c ├── psp-iolog.c ├── psp-iom.c ├── psp-irq.c ├── psp-profile.c ├── psp-proxy.c ├── psp-svc.c ├── psp-trace.c └── psp-x86-ice.c /.gitignore: -------------------------------------------------------------------------------- 1 | .clangd 2 | CMakeCache.txt 3 | Makefile 4 | CMakeFiles 5 | PSPEmu 6 | psp-iolog-tool 7 | cmake_install.cmake 8 | compile_commands.json 9 | 10 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "psp-includes"] 2 | path = psp-includes 3 | url = https://github.com/PSPReverse/psp-includes 4 | [submodule "capstone"] 5 | path = capstone 6 | url = https://github.com/aquynh/capstone 7 | [submodule "libgdbstub"] 8 | path = libgdbstub 9 | url = https://github.com/AlexanderEichner/libgdbstub 10 | [submodule "unicorn"] 11 | path = unicorn 12 | url = https://github.com/PSPReverse/unicorn.git 13 | branch = mmio 14 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.9) 2 | 3 | project(PSPEmu VERSION 0.0.0 DESCRIPTION "PSP emulator") 4 | 5 | set(CMAKE_THREAD_PREFER_PTHREAD On) 6 | set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DIN_PSP_EMULATOR") 7 | set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize=address") 8 | find_package (Threads) 9 | find_package(PkgConfig) 10 | find_package(ZLIB REQUIRED) 11 | find_library(m REQUIRED) 12 | 13 | pkg_check_modules(PC_LIBPSPPROXY REQUIRED IMPORTED_TARGET libpspproxy) 14 | pkg_check_modules(PC_OPENSSL REQUIRED IMPORTED_TARGET openssl) 15 | 16 | add_executable(PSPEmu 17 | psp-emu.c 18 | psp-brsp.c 19 | psp-core.c 20 | psp-ccd.c 21 | psp-cfg.c 22 | psp-disasm.c 23 | psp-dbg.c 24 | psp-dbg-hlp.c 25 | psp-svc.c 26 | psp-flash.c 27 | psp-iom.c 28 | psp-iolog.c 29 | psp-iolog-replay.c 30 | psp-irq.c 31 | psp-trace.c 32 | psp-cov.c 33 | psp-proxy.c 34 | psp-profile.c 35 | psp-dev.c 36 | psp-dev-ccp-v5.c 37 | psp-dev-timer.c 38 | psp-dev-fuse.c 39 | psp-dev-flash.c 40 | psp-dev-smu.c 41 | psp-dev-mp2.c 42 | psp-dev-status.c 43 | psp-dev-acpi.c 44 | psp-dev-gpio.c 45 | psp-dev-iomux.c 46 | psp-dev-rtc.c 47 | psp-dev-lpc.c 48 | psp-dev-version.c 49 | psp-dev-x86-uart.c 50 | psp-dev-x86-mem.c 51 | psp-dev-mmio-unknown.c 52 | psp-dev-smn-unknown.c 53 | psp-dev-x86-unknown.c 54 | psp-x86-ice.c 55 | 56 | # OS abstraction APIs goes here 57 | os/file.c 58 | os/posix/time.c 59 | os/posix/lock.c 60 | os/posix/thread.c 61 | os/posix/tcp.c) 62 | 63 | target_include_directories(PSPEmu PUBLIC 64 | "${PROJECT_SOURCE_DIR}/include" 65 | "${PROJECT_SOURCE_DIR}/psp-includes" 66 | "${PROJECT_SOURCE_DIR}/unicorn/include" 67 | "${PROJECT_SOURCE_DIR}/capstone/include" 68 | "${PROJECT_SOURCE_DIR}/libgdbstub" 69 | "${LIBPSPPROXY_INCLUDE_DIRS}" 70 | "${ZLIB_INCLUDE_DIRS}" 71 | ) 72 | 73 | target_link_libraries(PSPEmu PkgConfig::PC_LIBPSPPROXY) 74 | target_link_libraries(PSPEmu PkgConfig::PC_OPENSSL) 75 | target_link_libraries(PSPEmu ${ZLIB_LIBRARIES}) 76 | target_link_libraries(PSPEmu ${CMAKE_SOURCE_DIR}/unicorn/libunicorn.a) 77 | target_link_libraries(PSPEmu ${CMAKE_SOURCE_DIR}/capstone/libcapstone.a) 78 | target_link_libraries(PSPEmu ${CMAKE_SOURCE_DIR}/libgdbstub/libgdbstub.a) 79 | target_link_libraries(PSPEmu m) 80 | target_link_libraries(PSPEmu ${CMAKE_THREAD_LIBS_INIT}) 81 | 82 | add_executable (psp-iolog-tool 83 | psp-iolog-tool.c 84 | psp-iolog.c) 85 | target_include_directories(psp-iolog-tool PUBLIC 86 | "${PROJECT_SOURCE_DIR}/include" 87 | "${PROJECT_SOURCE_DIR}/psp-includes" 88 | ) 89 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # PSPEmu - Emulator for AMDs (Platform) Secure Processor 2 | 3 | ## Description 4 | 5 | This is an emulator for AMDs (Platform) Secure Processor or PSP with the goal to understand 6 | AMDs prorietary AGESA code running on the PSP by watching execution of the involved code modules. 7 | The PSP is the first processor to run on an AMD CPU after power is applied and is responsible for bootstrapping 8 | the whole system. It loads firmware for other micro controllers inside the CPU like the SMU for instance 9 | and initializes the memory controllers so DRAM is fully initialized when the first instruction starts executing 10 | on the x86 cores. The PSP also acts as the systems trust anchor by doing signature verification for loaded code 11 | including the UEFI firmware running on the x86 cores and implementing a firmware TPM on some models. 12 | On EPYC the PSP is responsible for key management and programming the encryption keys for the AES engines inside 13 | the memory controllers for AMDs Secure Encrypted Virtualization (SEV) feature. 14 | 15 | ## Target audience 16 | 17 | The emulator is targeted at firmware engineers who want to gain a deeper understanding about the PSP and the interaction 18 | with the UEFI firmware. Because of the security aspect it is interesting to security researchers as well. 19 | 20 | ## Features 21 | 22 | The following features are currently implemented in the emulator: 23 | 24 | - [x] Execute on-chip, off-chip bootloaders and the secure OS in a virtual environment 25 | - [x] Supports Zen, Zen+ and Zen2 (partial) based bootloaders 26 | - [x] Logging of hardware accesses, syscalls, etc. 27 | - [x] GDB stub interface with full support for breakpoints, watchpoints, stepping, etc. 28 | - [x] Create coverage traces compatible with the DrCov format 29 | - [x] Proxy mode allows accessing real hardware by running a small stub on a real PSP using code from the [psp-apps](https://github.com/PSPReverse/psp-apps) repository. 30 | 31 | ## Building 32 | 33 | ### Requirements 34 | 35 | A fairly recent Linux host with openssl, zlib and the respective development packages installed is required. 36 | 37 | ### Actual building 38 | 39 | Building the whole thing is a bit icky right now, patches certainly welcome! 40 | 41 | First [libpspproxy](https://github.com/PSPReverse/libpspproxy) needs to be installed. 42 | 43 | Then PSPEmu itself can be built by cloning the repository and issuing the following commands: 44 | ``` 45 | git clone --recurse-submodules https://github.com/PSPReverse/PSPEmu.git 46 | cd PSPEmu 47 | cd capstone && make && cd .. 48 | cd libgdbstub && cmake . && make && cd.. 49 | cd unicorn && sh make.sh && cd .. 50 | cmake . && make 51 | ``` 52 | 53 | ## Usage 54 | 55 | ### Fully emulated setup 56 | 57 | For first steps no access to AMD hardware is required, only a firmware image from a Mainboard 58 | vendor which can be downloaded from the vendors websites. In this example the off chip BL is 59 | executed in the emulator by using a fully emulated setup based on the first generation Zen architecture. 60 | ``` 61 | ./PSPEmu \ 62 | --emulation-mode sys \ # Sets the emulation mode to start at the off chip BL stage 63 | --cpu-profile ryzen7-1800x \ # Selects a Ryzen 7 1800X for emulation (automatically selects PSP profile) 64 | --flash-rom \ # The flash image to use for the emulated flash device 65 | --timer-real-time \ # Emulated timers tick in host real time 66 | --trace-log ./log \ # Destination for the log 67 | --intercept-svc-6 \ # Intercept and log svc 6 debug log syscalls 68 | --trace-svcs # Log all syscalls being made from usermode 69 | ``` 70 | 71 | ### Understanding the log 72 | 73 | Running `PSPEmu` with `--trace-log` will create a log which has the following layout: 74 | ``` 75 | 00000000 WARNING MMIO 0x000028ac[0x0000289b][ SVC, S, M, I,NF,0x00014000] DEV WRITE 0x3006000 4 0x00000001 76 | ``` 77 | 78 | The first column is monotonically increasing event ID, it is useful when filtering the log after the run to see how far certain events are apart. This is followed by the event severity 79 | which ranges from debug messages to fatal errors which will make the run fail or continue with undefined behavior. The following severities can occur: 80 | 81 | Severity | Description 82 | ------------ | ------------- 83 | DEBUG | Debug messages usually only useful when working on `PSPEmu` itself 84 | INFO | Informational messages like accesses to devices, syscalls being made, etc. 85 | WARNING | Warnings that something is not emulated correctly or at all. This will usually be shown for accesses to MMIO/SMN/X86 regions which are not backed by an emulated device. 86 | ERROR | Error messages where the error could be conveyed to the firmware so it can respond correctly, like errors in the CCP. 87 | FATAL_ERROR | Errors which can not be conveyed to the firmware in a meaningful way so the emulation result will be undefined because the firmware continues with a bogus state. 88 | 89 | After the severity comes the event origin i.e. which component of the emulator triggered the event. The most important origins are MMIO/SMN/X86 accesses or messages made from the proxy component 90 | or the syscall tracing. 91 | 92 | The fourth column is the PC value of the instruction causing the event, followed by the value of the LR register in square brackets. Next comes a brief state about the emulated ARM core when 93 | the event happened: 94 | 95 | Values | Description 96 | ------------ | ------------- 97 | SVC,USR,FIQ,IRQ,ABRT,UNDEF,MON,SYS | CPU mode 98 | S,NS | Secure/Non-secure World 99 | M,NM | MMU active/inactive 100 | I,NI | Interrupts enabled/masked 101 | F,NF | Fast interrupts enabled/masked 102 | addr | TTBR0 content for the page table root 103 | 104 | The following content is dependent on the type of event. The example shows a device write event to an unassigned region at address `0x3006000` which is 4 bytes in size and the value `0x00000001` 105 | 106 | ### Enabling the GDB stub 107 | 108 | `PSPEmu` offers the ability to debug the firmware using a standard GDB which has support for ARM. This requires adding `--dbg ` to the command line. The GDB stub will listen on the given port 109 | which one can connect to using GDBs `target remote localhost:` command. When connected you can set breakpoints and watchpoints, inspect and manipulate registers and memory and step through the 110 | executed code. `PSPEmu` offers specialized commands through GDBs `monitor` command. `monitor help` will print all available commands. 111 | 112 | ### Proxy mode 113 | 114 | TODO 115 | 116 | -------------------------------------------------------------------------------- /include/os/file.h: -------------------------------------------------------------------------------- 1 | /** @file 2 | * PSP Emulator - OS abstraction for file accesses. 3 | */ 4 | 5 | /* 6 | * Copyright (C) 2020 Alexander Eichner 7 | * 8 | * This program is free software: you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License as published by 10 | * the Free Software Foundation, version 3. 11 | * 12 | * This program is distributed in the hope that it will be useful, but 13 | * WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 | * General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with this program. If not, see . 19 | */ 20 | #ifndef INCLUDED_os_file_h 21 | #define INCLUDED_os_file_h 22 | 23 | #include 24 | 25 | /** 26 | * Loads the everything from the given file into the process memory space and returning an appropriate memory buffer (mmap'ed for example). 27 | * 28 | * @returns Status code. 29 | * @param pszFilename The filename to laod the flash content from. 30 | * @param ppv Where to store the pointer to the flash content on success. 31 | * @param pcb Where to store the size of the flash region on success. 32 | */ 33 | int OSFileLoadAll(const char *pszFilename, void **ppv, size_t *pcb); 34 | 35 | /** 36 | * Frees the file loaded with OSFileLoadAll(). 37 | * 38 | * @returns Status code. 39 | * @param pv Pointer to the start of the file as returned by OSFileLoadAll(). 40 | * @param cb Size of the file as returned by OSFileLoadAll(). 41 | */ 42 | int OSFileLoadAllFree(void *pv, size_t cb); 43 | 44 | #endif /* !INCLUDED_os_file_h */ 45 | -------------------------------------------------------------------------------- /include/os/lock.h: -------------------------------------------------------------------------------- 1 | /** @file 2 | * PSP Emulator - OS abstraction for semaphores, mutexes, etc. 3 | */ 4 | 5 | /* 6 | * Copyright (C) 2020 Alexander Eichner 7 | * 8 | * This program is free software: you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License as published by 10 | * the Free Software Foundation, version 3. 11 | * 12 | * This program is distributed in the hope that it will be useful, but 13 | * WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 | * General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with this program. If not, see . 19 | */ 20 | #ifndef INCLUDED_os_lock_h 21 | #define INCLUDED_os_lock_h 22 | 23 | #include 24 | 25 | /** Opaque lock handle. */ 26 | typedef struct OSLOCKINT *OSLOCK; 27 | /** Pointer to a lock handle. */ 28 | typedef OSLOCK *POSLOCK; 29 | 30 | 31 | /** 32 | * Creates a default lock. 33 | * 34 | * @returns Status code. 35 | * @param phLock Where to store the handle to the lock on success. 36 | */ 37 | int OSLockCreate(POSLOCK phLock); 38 | 39 | 40 | /** 41 | * Destroys the given lock. 42 | * 43 | * @returns Status code. 44 | * @param hLock The lock to destroy. 45 | */ 46 | int OSLockDestroy(OSLOCK hLock); 47 | 48 | 49 | /** 50 | * Acquires the given lock, waiting for it to become free if already acquired. 51 | * 52 | * @returns Status code. 53 | * @param hLock The lock to acquire. 54 | */ 55 | int OSLockAcquire(OSLOCK hLock); 56 | 57 | 58 | /** 59 | * Releases a previously acquired lock. 60 | * 61 | * @returns Status code. 62 | * @param hLock The lock to release. 63 | */ 64 | int OSLockRelease(OSLOCK hLock); 65 | 66 | #endif /* !INCLUDED_os_lock_h */ 67 | -------------------------------------------------------------------------------- /include/os/tcp.h: -------------------------------------------------------------------------------- 1 | /** @file 2 | * PSP Emulator - OS abstraction for TCP server/client connections. 3 | */ 4 | 5 | /* 6 | * Copyright (C) 2020 Alexander Eichner 7 | * 8 | * This program is free software: you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License as published by 10 | * the Free Software Foundation, version 3. 11 | * 12 | * This program is distributed in the hope that it will be useful, but 13 | * WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 | * General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with this program. If not, see . 19 | */ 20 | #ifndef INCLUDED_os_tcp_h 21 | #define INCLUDED_os_tcp_h 22 | 23 | #include 24 | 25 | /** Opaque TCP connection handle. */ 26 | typedef struct OSTCPCONINT *OSTCPCON; 27 | /** Pointer to a TCP connection handle. */ 28 | typedef OSTCPCON *POSTCPCON; 29 | 30 | 31 | /** Opaque TCP server handle. */ 32 | typedef struct OSTCPSRVINT *OSTCPSRV; 33 | /** Pointer to a TCP server handle. */ 34 | typedef OSTCPSRV *POSTCPSRV; 35 | 36 | 37 | /** Wait until data can be read from the connection. */ 38 | #define OSTCP_POLL_F_READ BIT(0) 39 | /** Wait until data can be written to the connection. */ 40 | #define OSTCP_POLL_F_WRITE BIT(1) 41 | /** Wait until an error occurred. */ 42 | #define OSTCP_POLL_F_ERROR BIT(2) 43 | 44 | 45 | /** 46 | * Tries to connect to the given remote server and returns a TCP client connection. 47 | * 48 | * @returns Status code. 49 | * @param phThread Where to store the handle to the thread on success. 50 | * @param pfnMain The handler to call on the created thread. 51 | * @param pvUser Opaque user data to pass to the thread handler. 52 | */ 53 | int OSTcpClientConnect(POSTCPCON phTcpCon, const char *pszHostname, uint16_t uPort); 54 | 55 | 56 | /** 57 | * Close the given TCP connection. 58 | * 59 | * @returns Status code. 60 | * @param hTcpCon The TCP connection to close. 61 | * @param fShutdown Flag whether to do an orderly shutdown of the connection. 62 | */ 63 | int OSTcpConnectionClose(OSTCPCON hTcpCon, bool fShutdown); 64 | 65 | 66 | /** 67 | * Enabled or disable send coalescing aka. Nagles algorithm. 68 | * 69 | * @returns Status code. 70 | * @param hTcpCon The TCP connection to configure. 71 | * @param fEnable Flag whether to enable or disable send coalescing. 72 | */ 73 | int OSTcpConnectionSendCoalescingSet(OSTCPCON hTcpCon, bool fEnable); 74 | 75 | 76 | /** 77 | * Tries to read the given number of bytes from the given client connection. 78 | * 79 | * @returns Status code. 80 | * @param hTcpCon The TCP connection. 81 | * @param pvBuf Where to store the read data. 82 | * @param cbRead How much to read. 83 | * @param pcbRead Where to store the actual number of bytes read, optional. 84 | * If NULL the call will block until either the given number of bytes 85 | * where read or an error occured. 86 | */ 87 | int OSTcpConnectionRead(OSTCPCON hTcpCon, void *pvBuf, size_t cbRead, size_t *pcbRead); 88 | 89 | 90 | /** 91 | * Tries to write the given number of bytes to the given client connection. 92 | * 93 | * @returns Status code. 94 | * @param hTcpCon The TCP connection. 95 | * @param pvBuf The data to write. 96 | * @param cbWrite How much to write. 97 | * @param pcbWritten Where to store the actual number of bytes written, optional. 98 | * If NULL the call will block until either the given number of bytes 99 | * where written or an error occured. 100 | */ 101 | int OSTcpConnectionWrite(OSTCPCON hTcpCon, const void *pvBuf, size_t cbWrite, size_t *pcbWritten); 102 | 103 | 104 | /** 105 | * Polls the given TCP connection until one of the given events occurs. 106 | * 107 | * @returns Status code. 108 | * @param hTcpCon The TCP connection. 109 | * @param fEvt Combination of events to wait for, see OSTCP_POLL_F_XXX. 110 | * @param pfEvtsRecv Where to store the mask of events received upon success. 111 | * @param cMsWait How many milliseconds to wait, UINT32_MAX for indefinite wait. 112 | */ 113 | int OSTcpConnectionPoll(OSTCPCON hTcpCon, uint32_t fEvt, uint32_t *pfEvtsRecv, uint32_t cMsWait); 114 | 115 | 116 | /** 117 | * Peeks for the amount of data available for immediate reading. 118 | * 119 | * @returns Status code. 120 | * @param hTcpCon The TCP connection. 121 | * @param pcbRead Where to store the amount of bytes available for reading. 122 | */ 123 | int OSTcpConnectionPeek(OSTCPCON hTcpCon, size_t *pcbRead); 124 | 125 | 126 | /** 127 | * Creates a TCP server instance listening on the given port. 128 | * 129 | * @returns Status code. 130 | * @param phTcpSrv Where to store the handle to the TCP server instance on success. 131 | * @param uPort The port to listen on. 132 | */ 133 | int OSTcpServerCreate(POSTCPSRV phTcpSrv, uint16_t uPort); 134 | 135 | 136 | /** 137 | * Destroys the given TCP server handle. 138 | * 139 | * @returns Status code. 140 | * @param hTcpSrv The TCP server handle to destroy. 141 | */ 142 | int OSTcpServerDestroy(OSTCPSRV hTcpSrv); 143 | 144 | 145 | /** 146 | * Waits for a new connection on the given TCP server instance. 147 | * 148 | * @returns Status code. 149 | * @param hTcpSrv The TCP server instance to wait on. 150 | * @param phTcpCon Where to store the handle to the new connection upon success. 151 | * @param cMsWait How many milliseconds to wait before timing out. 152 | */ 153 | int OSTcpServerConnectionWaitFor(OSTCPSRV hTcpSrv, POSTCPCON phTcpCon, uint32_t cMsWait); 154 | 155 | #endif /* !INCLUDED_os_tcp_h */ 156 | -------------------------------------------------------------------------------- /include/os/thread.h: -------------------------------------------------------------------------------- 1 | /** @file 2 | * PSP Emulator - OS abstraction for threads. 3 | */ 4 | 5 | /* 6 | * Copyright (C) 2020 Alexander Eichner 7 | * 8 | * This program is free software: you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License as published by 10 | * the Free Software Foundation, version 3. 11 | * 12 | * This program is distributed in the hope that it will be useful, but 13 | * WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 | * General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with this program. If not, see . 19 | */ 20 | #ifndef INCLUDED_os_thread_h 21 | #define INCLUDED_os_thread_h 22 | 23 | #include 24 | 25 | /** Opaque thread handle. */ 26 | typedef struct OSTHREADINT *OSTHREAD; 27 | /** Pointer to a thread handle. */ 28 | typedef OSTHREAD *POSTHREAD; 29 | 30 | 31 | /** 32 | * The main thread handler. 33 | * 34 | * @returns Status code. 35 | * @param hThread The thread handle this method is called from. 36 | * @param pvUser Opaque user data passed during thread creation. 37 | */ 38 | typedef int (FNOSTHREADMAIN)(OSTHREAD hThread, void *pvUser); 39 | /** Thread handler pointer. */ 40 | typedef FNOSTHREADMAIN *PFNOSTHREADMAIN; 41 | 42 | 43 | /** 44 | * Creates a thread with default parameters for the running host. 45 | * 46 | * @returns Status code. 47 | * @param phThread Where to store the handle to the thread on success. 48 | * @param pfnMain The handler to call on the created thread. 49 | * @param pvUser Opaque user data to pass to the thread handler. 50 | */ 51 | int OSThreadCreate(POSTHREAD phThread, PFNOSTHREADMAIN pfnMain, void *pvUser); 52 | 53 | 54 | /** 55 | * Destroys the given thread handle. 56 | * 57 | * @returns Status code. 58 | * @param hThread The thread handle to destroy (the thread handler must have returned already). 59 | * @param prcThread Where to store the thread return status upon success, optional. 60 | */ 61 | int OSThreadDestroy(OSTHREAD hThread, int *prcThread); 62 | 63 | 64 | #endif /* !INCLUDED_os_thread_h */ 65 | -------------------------------------------------------------------------------- /include/os/time.h: -------------------------------------------------------------------------------- 1 | /** @file 2 | * PSP Emulator - OS abstraction for timing related APIs. 3 | */ 4 | 5 | /* 6 | * Copyright (C) 2020 Alexander Eichner 7 | * 8 | * This program is free software: you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License as published by 10 | * the Free Software Foundation, version 3. 11 | * 12 | * This program is distributed in the hope that it will be useful, but 13 | * WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 | * General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with this program. If not, see . 19 | */ 20 | #ifndef INCLUDED_os_time_h 21 | #define INCLUDED_os_time_h 22 | 23 | #include 24 | 25 | 26 | /** 27 | * Returns monotonically increasing nano second precision timestamp from an arbitrary starting point in time. 28 | * 29 | * @returns Nano second precision timestamp. 30 | */ 31 | uint64_t OSTimeTsGetNano(void); 32 | 33 | #endif /* !INCLUDED_os_time_h */ 34 | -------------------------------------------------------------------------------- /include/psp-brsp.h: -------------------------------------------------------------------------------- 1 | /** @file 2 | * PSP Emulator - API for manipulating the Boot ROM Service Page. 3 | */ 4 | 5 | /* 6 | * Copyright (C) 2020 Alexander Eichner 7 | * 8 | * This program is free software: you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License as published by 10 | * the Free Software Foundation, version 3. 11 | * 12 | * This program is distributed in the hope that it will be useful, but 13 | * WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 | * General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with this program. If not, see . 19 | */ 20 | #ifndef INCLUDED_psp_brsp_h 21 | #define INCLUDED_psp_brsp_h 22 | 23 | #include 24 | 25 | #include 26 | 27 | #include 28 | 29 | 30 | /** 31 | * Generates a boot ROM service page from the given emulator config. 32 | * 33 | * @returns Status code. 34 | * @param pBrsp The Boot ROM Service Page to initialize. 35 | * @param pCfg The emulator config to generate from. 36 | * @param idCcd The CCD ID to generate for. 37 | * @param idSocket The socket ID to generate for. 38 | */ 39 | int PSPBrspGenerate(PPSPROMSVCPG pBrsp, PCPSPEMUCFG pCfg, uint32_t idCcd, uint32_t idSocket); 40 | 41 | 42 | /** 43 | * Dumps the given BRSP to stdout. 44 | * 45 | * @returns Status code. 46 | * @param pBrsp The Boot ROM Service Page to dump. 47 | */ 48 | int PSPBrspDump(PPSPROMSVCPG pBrsp); 49 | 50 | #endif /* !INCLUDED_psp_brsp_h */ 51 | -------------------------------------------------------------------------------- /include/psp-ccd.h: -------------------------------------------------------------------------------- 1 | /** @file 2 | * PSP Emulator - API for a single PSP contained in a CCD along with the peripherals 3 | */ 4 | 5 | /* 6 | * Copyright (C) 2020 Alexander Eichner 7 | * 8 | * This program is free software: you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License as published by 10 | * the Free Software Foundation, version 3. 11 | * 12 | * This program is distributed in the hope that it will be useful, but 13 | * WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 | * General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with this program. If not, see . 19 | */ 20 | #ifndef __psp_ccd_h 21 | #define __psp_ccd_h 22 | 23 | #include 24 | #include 25 | 26 | #include 27 | 28 | #include 29 | #include 30 | #include 31 | 32 | 33 | /** Opaque PSP CCD handle. */ 34 | typedef struct PSPCCDINT *PSPCCD; 35 | /** Pointer to a PSP CCD core handle. */ 36 | typedef PSPCCD *PPSPCCD; 37 | 38 | 39 | /** 40 | * Creates a new emulated CCD containing a single PSP and all the peripherals. 41 | * 42 | * @returns Status code. 43 | * @param phCcd Where to store the handle to the CCD on success. 44 | * @param idSocket Socket ID where the CCD is located. 45 | * @param idCcd ID of the emulated CCD. 46 | * @param pCfg Global config for the system. 47 | */ 48 | int PSPEmuCcdCreate(PPSPCCD phCcd, uint32_t idSocket, uint32_t idCcd, PCPSPEMUCFG pCfg); 49 | 50 | 51 | /** 52 | * Destroys a given CCD. 53 | * 54 | * @returns nothing. 55 | * @param hCcd The CCD handle to destroy. 56 | */ 57 | void PSPEmuCcdDestroy(PSPCCD hCcd); 58 | 59 | 60 | /** 61 | * Queries the emulation core handle from the given CCD. 62 | * 63 | * @returns Status code. 64 | * @param hCcd The CCD handle. 65 | * @param phPspCore Where to store the handle to the PSP core on success. 66 | */ 67 | int PSPEmuCcdQueryCore(PSPCCD hCcd, PPSPCORE phPspCore); 68 | 69 | 70 | /** 71 | * Queries the I/O manager handle from the given CCD. 72 | * 73 | * @returns Status code. 74 | * @param hCcd The CCD handle. 75 | * @param phIoMgr Where to store the handle to the I/O manager on success. 76 | */ 77 | int PSPEmuCcdQueryIoMgr(PSPCCD hCcd, PPSPIOM phIoMgr); 78 | 79 | 80 | /** 81 | * Resets the given CCD instance to the initial state right after creation, including all device states. 82 | * 83 | * @returns Status code. 84 | * @param hCcd The CCD handle. 85 | */ 86 | int PSPEmuCcdReset(PSPCCD hCcd); 87 | 88 | 89 | /** 90 | * Let the given CCD instance run. 91 | * 92 | * @returns Status code. 93 | * @param hCcd The CCD handle. 94 | */ 95 | int PSPEmuCcdRun(PSPCCD hCcd); 96 | 97 | #endif /* !__psp_ccd_h */ 98 | -------------------------------------------------------------------------------- /include/psp-cov.h: -------------------------------------------------------------------------------- 1 | /** @file 2 | * PSP Emulator - Coverage tracing API. 3 | */ 4 | 5 | /* 6 | * Copyright (C) 2020 Alexander Eichner 7 | * 8 | * This program is free software: you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License as published by 10 | * the Free Software Foundation, version 3. 11 | * 12 | * This program is distributed in the hope that it will be useful, but 13 | * WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 | * General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with this program. If not, see . 19 | */ 20 | #ifndef __psp_cov_h 21 | #define __psp_cov_h 22 | 23 | #include 24 | #include 25 | 26 | #include 27 | 28 | #include 29 | #include 30 | #include 31 | 32 | 33 | /** Opaque PSP coverage tracer handle. */ 34 | typedef struct PSPCOVINT *PSPCOV; 35 | /** Pointer to a PSP coverage tracer handle. */ 36 | typedef PSPCOV *PPSPCOV; 37 | 38 | 39 | /** 40 | * Creates a new coverage tracer instance. 41 | * 42 | * @returns Status code. 43 | * @param phCov Where to store the coverage tracer handle on success. 44 | * @param hPspCore PSP core handle to create the coverage trace for. 45 | * @param PspAddrBegin Where to start collecting coverage information. 46 | * @param PspAddrEnd Where to stop collecting coverage information, inclusive. 47 | */ 48 | int PSPEmuCovCreate(PPSPCOV phCov, PSPCORE hPspCore, PSPADDR PspAddrBegin, PSPADDR PspAddrEnd); 49 | 50 | /** 51 | * Destroys a given coverage tracer handle. 52 | * 53 | * @returns nothing. 54 | * @param hCov The coverage tracer handle to destroy. 55 | */ 56 | void PSPEmuCovDestroy(PSPCOV hCov); 57 | 58 | 59 | /** 60 | * Resets the state of the given coverage tracer to a clean one. 61 | * 62 | * @returns nothing. 63 | * @param hCov The coverage tracer handle. 64 | */ 65 | void PSPEmuCovReset(PSPCOV hCov); 66 | 67 | 68 | /** 69 | * Dumps the currently collected coverage information to the given file. 70 | * 71 | * @returns Status code. 72 | * @param hCov The coverage tracer handle. 73 | * @param pszFilename Filename to dump the information to. 74 | * 75 | * @note The file format is supposed to be compatible with DynamoRIOs drcov format. 76 | */ 77 | int PSPEmuCovDumpToFile(PSPCOV hCov, const char *pszFilename); 78 | 79 | #endif /* __psp_cov_h */ 80 | -------------------------------------------------------------------------------- /include/psp-dbg-hlp.h: -------------------------------------------------------------------------------- 1 | /** @file 2 | * PSP Emulator - Debug helper API. 3 | */ 4 | 5 | /* 6 | * Copyright (C) 2020 Alexander Eichner 7 | * 8 | * This program is free software: you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License as published by 10 | * the Free Software Foundation, version 3. 11 | * 12 | * This program is distributed in the hope that it will be useful, but 13 | * WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 | * General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with this program. If not, see . 19 | */ 20 | #ifndef INCLUDED_psp_dbg_hlp_h 21 | #define INCLUDED_psp_dbg_hlp_h 22 | 23 | #include 24 | #include 25 | 26 | 27 | /** Opaque PSP Debug helper handle. */ 28 | typedef struct PSPDBGHLPINT *PSPDBGHLP; 29 | /** Pointer to a PSP Debug helper handle. */ 30 | typedef PSPDBGHLP *PPSPDBGHLP; 31 | 32 | 33 | /** Forward decleration of a const debugger output helper structure. */ 34 | typedef const struct PSPDBGOUTHLP *PCPSPDBGOUTHLP; 35 | 36 | /** 37 | * Debugger output helper callback table. 38 | */ 39 | typedef struct PSPDBGOUTHLP 40 | { 41 | 42 | /** 43 | * Print formatted string. 44 | * 45 | * @returns Status code. 46 | * @param pHlp Pointer to this structure. 47 | * @param pszFmt The format string. 48 | * @param ... Variable number of arguments depending on the format string. 49 | */ 50 | int (*pfnPrintf) (PCPSPDBGOUTHLP pHlp, const char *pszFmt, ...); 51 | 52 | } PSPDBGOUTHLP; 53 | 54 | 55 | /** 56 | * Custom command descriptor. 57 | */ 58 | typedef struct DBGHLPCMD 59 | { 60 | /** Command name. */ 61 | const char *pszCmd; 62 | /** Command description, optional. */ 63 | const char *pszDesc; 64 | 65 | /** 66 | * Command callback. 67 | * 68 | * @returns Status code. 69 | * @param hDbgHlp The debug helper handle this command was registered invoked from. 70 | * @param pHlp Pointer to output formatting helpers. 71 | * @param pszArgs Command arguments. 72 | * @param pvUser Opaque user data passed during stub context creation. 73 | */ 74 | int (*pfnCmd) (PSPDBGHLP hDbgHlp, PCPSPDBGOUTHLP pHlp, const char *pszArgs, void *pvUser); 75 | } DBGHLPCMD; 76 | /** Pointer to a custom command descriptor. */ 77 | typedef DBGHLPCMD *PDBGHLPCMD; 78 | /** Pointer to a const custom command descriptor. */ 79 | typedef const DBGHLPCMD *PCDBGHLPCMD; 80 | 81 | 82 | /** 83 | * Creates a new debug helper module. 84 | * 85 | * @returns Status code. 86 | * @param phDbgHlp Where to store the debug helper handle on success. 87 | */ 88 | int PSPEmuDbgHlpCreate(PPSPDBGHLP phDbgHlp); 89 | 90 | 91 | /** 92 | * Retains a reference to the given debug helper module. 93 | * 94 | * @returns New reference count. 95 | * @param hDbgHlp The debug helper module handle. 96 | */ 97 | uint32_t PSPEmuDbgHlpRetain(PSPDBGHLP hDbgHlp); 98 | 99 | 100 | /** 101 | * Releases a reference to the given debug helper module. 102 | * 103 | * @returns New reference count - 0 if the debug helper module was destroyed. 104 | * @param hDbgHlp The debug helper module handle. 105 | */ 106 | uint32_t PSPEmuDbgHlpRelease(PSPDBGHLP hDbgHlp); 107 | 108 | 109 | /** 110 | * Registers a the given set of commands with the debug helper module. 111 | * 112 | * @returns Status code. 113 | * @param hDbgHlp The debug helper module handle - if NULL the call returns success without doing anything 114 | * (to avoid if mazes if there is no debug helper existing). 115 | * @param paCmds Array of command descriptors to register. 116 | * @param cCmds Number of commands in the array. 117 | * @param pvUser Opaque user data passed to the registered commands on invocation. 118 | */ 119 | int PSPEmuDbgHlpCmdRegister(PSPDBGHLP hDbgHlp, PCDBGHLPCMD paCmds, uint32_t cCmds, void *pvUser); 120 | 121 | 122 | /** 123 | * Deregisters a the given set of commands from the debug helper module. 124 | * 125 | * @returns Status code. 126 | * @param hDbgHlp The debug helper module handle. 127 | * @param paCmds Array of command descriptors to to deregister. 128 | */ 129 | int PSPEmuDbgHlpCmdDeregister(PSPDBGHLP hDbgHlp, PCDBGHLPCMD paCmds); 130 | 131 | 132 | /** 133 | * Calls the given command with the given set of arguments. 134 | * 135 | * @returns Status code. 136 | * @param hDbgHlp The debug helper module handle. 137 | * @param pszCmd The command to call. 138 | * @param pszArgs Arguments given as a single string. 139 | * @param pOutHlp The output helper to use. 140 | */ 141 | int PSPEmuDbgHlpCmdExec(PSPDBGHLP hDbgHlp, const char *pszCmd, const char *pszArgs, PCPSPDBGOUTHLP pOutHlp); 142 | 143 | 144 | /** 145 | * Returns the number of commands registered with the given debug helper module. 146 | * 147 | * @returns Number of commands. 148 | * @param hDbgHlp The debug helper module handle. 149 | */ 150 | uint32_t PSPEmuDbgHlpCmdGetCount(PSPDBGHLP hDbgHlp); 151 | 152 | 153 | /** 154 | * Queries the descriptors of the registered commands for the given debug helper module. 155 | * 156 | * @returns Status code. 157 | * @param hDbgHlp The debug helper module handle. 158 | * @param paCmds Where to store the command descriptors. 159 | * @param cCmds Number of entries available in the descriptor array. 160 | * @param pcCmds Where to store the amount of command descriptors returned on success. 161 | */ 162 | int PSPEmuDbgHlpCmdQueryDesc(PSPDBGHLP hDbgHlp, PDBGHLPCMD paCmds, uint32_t cCmds, uint32_t *pcCmds); 163 | 164 | #endif /* !INCLUDED_psp_dbg_hlp_h */ 165 | -------------------------------------------------------------------------------- /include/psp-dbg.h: -------------------------------------------------------------------------------- 1 | /** @file 2 | * PSP Emulator - Debugger API. 3 | */ 4 | 5 | /* 6 | * Copyright (C) 2020 Alexander Eichner 7 | * 8 | * This program is free software: you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License as published by 10 | * the Free Software Foundation, version 3. 11 | * 12 | * This program is distributed in the hope that it will be useful, but 13 | * WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 | * General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with this program. If not, see . 19 | */ 20 | #ifndef __psp_dbg_h 21 | #define __psp_dbg_h 22 | 23 | #include 24 | 25 | #include 26 | #include 27 | 28 | 29 | /** PSP debugger handle. */ 30 | typedef struct PSPDBGINT *PSPDBG; 31 | /** Pointer to a PSP debugger handle. */ 32 | typedef PSPDBG *PPSPDBG; 33 | 34 | 35 | /** 36 | * Creates a new debugger instance for the given CCDs listening at the given port. 37 | * 38 | * @returns Status code. 39 | * @param phDbg Where to store the debugger handle on success. 40 | * @param uPort The port to listen on. 41 | * @param cInsnStep Number of instructions to step in a single round 42 | * when the CCD is running, 0 for default count. 43 | * Only use something different when you know what you are doing. 44 | * @param PspAddrRunUpTo Runs until this address is hit like without a debugger enabled 45 | * and drops into it when hit. 46 | * @param pahCcds Array of CCD handles to handle with this debugger instance. 47 | * @param cCcds Number of entris in the given array. 48 | * @param hDbgHlp Debug helper module handle to use, optional. 49 | */ 50 | int PSPEmuDbgCreate(PPSPDBG phDbg, uint16_t uPort, uint32_t cInsnsStep, PSPADDR PspAddrRunUpTo, const PPSPCCD pahCcds, uint32_t cCcds, 51 | PSPDBGHLP hDbgHlp); 52 | 53 | /** 54 | * Destroys the given debugger handle. 55 | * 56 | * @returns Status code. 57 | * @param hDbg The debugger handle to destroy. 58 | */ 59 | int PSPEmuDbgDestroy(PSPDBG hDbg); 60 | 61 | /** 62 | * Executes the main debugger runloop, listening for requests from the client and executing them. 63 | * 64 | * @returns Status code. 65 | * @param hDbg The debugger handle. 66 | * 67 | * @note Don't access the assigned CCD handles directly when this is active, weird things could happen. 68 | */ 69 | int PSPEmuDbgRunloop(PSPDBG hDbg); 70 | 71 | /** 72 | * Kicks the given debugger handle out of the runloop. 73 | * 74 | * @returns Status code. 75 | * @param hDbg The debugger handle. 76 | */ 77 | int PSPEmuDbgKick(PSPDBG hDbg); 78 | 79 | #endif /* __psp_dbg_h */ 80 | -------------------------------------------------------------------------------- /include/psp-dev.h: -------------------------------------------------------------------------------- 1 | /** @file 2 | * PSP Emulator - Device interface. 3 | */ 4 | 5 | /* 6 | * Copyright (C) 2020 Alexander Eichner 7 | * 8 | * This program is free software: you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License as published by 10 | * the Free Software Foundation, version 3. 11 | * 12 | * This program is distributed in the hope that it will be useful, but 13 | * WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 | * General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with this program. If not, see . 19 | */ 20 | #ifndef __psp_dev_h 21 | #define __psp_dev_h 22 | 23 | #include 24 | 25 | #include 26 | #include 27 | 28 | /** Pointer to a const PSP device registration record. */ 29 | typedef const struct PSPDEVREG *PCPSPDEVREG; 30 | /** Pointer to a PSP device registration record. */ 31 | typedef struct PSPDEVREG *PPSPDEVREG; 32 | 33 | 34 | /** Pointer to a const device interface callback table. */ 35 | typedef const struct PSPDEVIF *PCPSPDEVIF; 36 | 37 | /** 38 | * Device interface callback table. 39 | */ 40 | typedef struct PSPDEVIF 41 | { 42 | 43 | /** 44 | * Sets an interrupt request. 45 | * 46 | * @returns Status code. 47 | * @param pDevIf Pointer to this table. 48 | * @param idPrio The priority group of the device. 49 | * @param idIrq The interrupt ID of the device. 50 | * @param fAssert Flag whether to assert or de-assert the interrupt line. 51 | */ 52 | int (*pfnIrqSet)(PCPSPDEVIF pDevIf, uint32_t idPrio, uint8_t idIrq, bool fAssert); 53 | 54 | } PSPDEVIF; 55 | /** Pointer to a device interface callback table. */ 56 | typedef PSPDEVIF *PPSPDEVIF; 57 | 58 | 59 | /** 60 | * PSP device instance. 61 | */ 62 | typedef struct PSPDEV 63 | { 64 | /** Pointer to the next device. */ 65 | struct PSPDEV *pNext; 66 | /** Pointer to the device registration record. */ 67 | PCPSPDEVREG pReg; 68 | /** Pointer to the device interface callback to use. */ 69 | PCPSPDEVIF pDevIf; 70 | /** The I/O manager the device is attached to. */ 71 | PSPIOM hIoMgr; 72 | /** The global config structure. */ 73 | PCPSPEMUCFG pCfg; 74 | /** Instance data - variable in size. */ 75 | uint8_t abInstance[1]; 76 | } PSPDEV; 77 | typedef PSPDEV *PPSPDEV; 78 | typedef const PSPDEV *PCPSPDEV; 79 | 80 | 81 | /** Initialization handler. */ 82 | typedef int (FNPSPDEVINIT)(PPSPDEV pDev); 83 | /** Initialization handler pointer. */ 84 | typedef FNPSPDEVINIT *PFNPSPDEVINIT; 85 | 86 | /** Destruction handler. */ 87 | typedef void (FNPSPDEVDESTRUCT)(PPSPDEV pDev); 88 | /** Initialization handler pointer. */ 89 | typedef FNPSPDEVDESTRUCT *PFNPSPDEVDESTRUCT; 90 | 91 | /** 92 | * PSP SMN device registration record. 93 | */ 94 | typedef struct PSPDEVREG 95 | { 96 | /** Device name. */ 97 | const char *pszName; 98 | /** Short device description. */ 99 | const char *pszDesc; 100 | /** Size of the device instance state. */ 101 | size_t cbInstance; 102 | /** Initialization callback. */ 103 | PFNPSPDEVINIT pfnInit; 104 | /** Destruction callback. */ 105 | PFNPSPDEVDESTRUCT pfnDestruct; 106 | 107 | /** 108 | * Reset the device state to the one right after initialization, optional. 109 | * 110 | * @returns Status code. 111 | * @param pDev The device instance to reset.s 112 | */ 113 | int (*pfnReset) (PPSPDEV pDev); 114 | } PSPDEVREG; 115 | 116 | 117 | /** 118 | * Creates a new device instance of the given device registration record, iniitalizes it and 119 | * registers the SMN handlers with the given SMN manager. 120 | * 121 | * @returns Status code. 122 | * @param hIoMgr The I/O manager handle this device will be attached to. 123 | * @param pDevReg The device template to use. 124 | * @param pDevIf The device interface callback table to use. 125 | * @param pCfg The config to use for the device. 126 | * @param ppDev Where to store the device on success. 127 | */ 128 | int PSPEmuDevCreate(PSPIOM hIoMgr, PCPSPDEVREG pDevReg, PCPSPDEVIF pDevIf, PCPSPEMUCFG pCfg, PPSPDEV *ppDev); 129 | 130 | 131 | /** 132 | * Destroys the given SMN device instance. 133 | * 134 | * @returns Status code. 135 | * @param pDev The device to destroy. 136 | */ 137 | int PSPEmuDevDestroy(PPSPDEV pDev); 138 | 139 | 140 | #endif /* __psp_dev_h */ 141 | 142 | -------------------------------------------------------------------------------- /include/psp-devs.h: -------------------------------------------------------------------------------- 1 | /** @file 2 | * PSP Emulator - Known MMIO devices 3 | */ 4 | 5 | /* 6 | * Copyright (C) 2020 Alexander Eichner 7 | * 8 | * This program is free software: you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License as published by 10 | * the Free Software Foundation, version 3. 11 | * 12 | * This program is distributed in the hope that it will be useful, but 13 | * WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 | * General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with this program. If not, see . 19 | */ 20 | #ifndef __psp_devs_h 21 | #define __psp_devs_h 22 | 23 | #include 24 | 25 | #include 26 | 27 | extern const PSPDEVREG g_DevRegCcpV5; 28 | extern const PSPDEVREG g_DevRegTimer1; 29 | extern const PSPDEVREG g_DevRegTimer2; 30 | extern const PSPDEVREG g_DevRegFuse; 31 | extern const PSPDEVREG g_DevRegFlash; 32 | extern const PSPDEVREG g_DevRegSmu; 33 | extern const PSPDEVREG g_DevRegMp2; 34 | extern const PSPDEVREG g_DevRegSts; 35 | extern const PSPDEVREG g_DevRegMmioUnk; 36 | extern const PSPDEVREG g_DevRegAcpi; 37 | extern const PSPDEVREG g_DevRegGpio; 38 | extern const PSPDEVREG g_DevRegIoMux; 39 | extern const PSPDEVREG g_DevRegRtc; 40 | extern const PSPDEVREG g_DevRegLpc; 41 | extern const PSPDEVREG g_DevRegMmioVersion; 42 | 43 | extern const PSPDEVREG g_DevRegSmnUnk; 44 | 45 | extern const PSPDEVREG g_DevRegX86Unk; 46 | extern const PSPDEVREG g_DevRegX86Uart; 47 | extern const PSPDEVREG g_DevRegX86Mem; 48 | 49 | #endif /* __psp_devs_h */ 50 | 51 | -------------------------------------------------------------------------------- /include/psp-disasm.h: -------------------------------------------------------------------------------- 1 | /** @file 2 | * PSP Emulator - Disassembler API 3 | */ 4 | 5 | /* 6 | * Copyright (C) 2020 Alexander Eichner 7 | * 8 | * This program is free software: you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License as published by 10 | * the Free Software Foundation, version 3. 11 | * 12 | * This program is distributed in the hope that it will be useful, but 13 | * WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 | * General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with this program. If not, see . 19 | */ 20 | #ifndef __psp_disasm_h 21 | #define __psp_disasm_h 22 | 23 | #include 24 | 25 | /** 26 | * Disassembles a bunch of instructions and formats them into the given destination buffer. 27 | * 28 | * @returns Status code. 29 | * @param pchDst Pointer to the character buffer holding the zero terminated string on success. 30 | * @param cch Size of the destination buffer. 31 | * @param cInsnsDisasm Maximum number of instructions to disassemble, 0 for as much as possible. 32 | * @param pbCode The code to disassemble. 33 | * @param cbCode Number of code bytes. 34 | * @param uAddrStart The address of the first instruction. 35 | * @param fThumb Flag whether to disassemble in THUMB or ARM mode. 36 | */ 37 | int PSPEmuDisasm(char *pchDst, size_t cch, uint32_t cInsnsDisasm, uint8_t *pbCode, size_t cbCode, PSPADDR uAddrStart, bool fThumb); 38 | 39 | #endif /* __psp_disasm_h */ 40 | -------------------------------------------------------------------------------- /include/psp-flash.h: -------------------------------------------------------------------------------- 1 | /** @file 2 | * PSP Emulator - API for handling the flash filesystem 3 | */ 4 | 5 | /* 6 | * Copyright (C) 2020 Alexander Eichner 7 | * 8 | * This program is free software: you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License as published by 10 | * the Free Software Foundation, version 3. 11 | * 12 | * This program is distributed in the hope that it will be useful, but 13 | * WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 | * General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with this program. If not, see . 19 | */ 20 | #ifndef INCLUDED_psp_flash_h 21 | #define INCLUDED_psp_flash_h 22 | 23 | #include 24 | 25 | #include 26 | 27 | #include 28 | 29 | 30 | /** Opaque PSP flash filesystem handle. */ 31 | typedef struct PSPFFSINT *PSPFFS; 32 | /** Pointer to a PSP flash filesystem handle. */ 33 | typedef PSPFFS *PPSPFFS; 34 | 35 | 36 | /** 37 | * Creates a new flash filesystem instance for the given flash image and config. 38 | * 39 | * @returns Status code. 40 | * @param phFfs Where to store the handle to the filesystem instance on success. 41 | * @param idPsp The PSP identification value to load the correct directories from any combo directory. 42 | * @param pvFlash The start of the flash region. 43 | * @param cbFlash Size of the flash region. 44 | */ 45 | int PSPFlashFsCreate(PPSPFFS phFfs, uint32_t idPsp, const void *pvFlash, size_t cbFlash); 46 | 47 | 48 | /** 49 | * Destroys the given flash filesystem instance. 50 | * 51 | * @returns nothing. 52 | * @param hFfs The flash filesystem instance handle. 53 | */ 54 | void PSPFlashFsDestroy(PSPFFS hFfs); 55 | 56 | 57 | /** 58 | * Queries the L1 PSP directory from the given flash image. 59 | * 60 | * @returns Status code. 61 | * @param hFfs The flash filesystem instance handle. 62 | * @param ppDirL1 Where to store the pointer to the verified L1 directory on success. 63 | * @param pcbDirL1 Where to store the size of the L1 directory on success. 64 | */ 65 | int PSPFlashFsQueryL1Dir(PSPFFS hFfs, PCPSPFFSDIR *ppDirL1, size_t *pcbDirL1); 66 | 67 | 68 | /** 69 | * Queries the directory from the selected L1 and possibly L2 directory and copies it 70 | * to the given buffer. 71 | * 72 | * @return Status code. 73 | * @param hFfs The flash filesystem instance handle. 74 | * @param pDirHdr The directory header to fill in (L1 directory magic), optional. 75 | * @param paDirEntries Where to store the merged entries. 76 | * @param cEntriesMax Maximum number of entries fitting into the array. 77 | * @param fMergeL2 Flag whether to merge the L2 directory into this as well (kind of what the off chip BL is doing at the beginning). 78 | * 79 | * @note L2 directory entries are removed from the merged directory if merging is enabled. 80 | * @note Excessive entries not fitting into the buffer are cut off. 81 | */ 82 | int PSPFlashFsDirQuery(PSPFFS hFfs, PPSPFFSDIRHDR pDirHdr, PPSPFFSDIRENTRY paDirEntries, size_t cEntriesMax, bool fMergeL2); 83 | 84 | 85 | /** 86 | * Queries the given entry from the flash region parsing the directories etc. 87 | * 88 | * @returns Status code. 89 | * @param hFfs The flash filesystem instance handle. 90 | * @param enmEntry The entry type to read. 91 | * @param ppvEntry Where to store the pointer to the entry start on success. 92 | * @param pcbEntry Where to store the size of the entry on success. 93 | */ 94 | int PSPFlashFsQueryEntry(PSPFFS hFfs, PSPFFSDIRENTRYTYPE enmEntry, const void **ppvEntry, size_t *pcbEntry); 95 | 96 | #endif /* !INCLUDED_psp_flash_h */ 97 | -------------------------------------------------------------------------------- /include/psp-iolog-replay.h: -------------------------------------------------------------------------------- 1 | /** @file 2 | * PSP Emulator - I/O log replay. 3 | */ 4 | 5 | /* 6 | * Copyright (C) 2020 Alexander Eichner 7 | * 8 | * This program is free software: you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License as published by 10 | * the Free Software Foundation, version 3. 11 | * 12 | * This program is distributed in the hope that it will be useful, but 13 | * WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 | * General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with this program. If not, see . 19 | */ 20 | #ifndef INCLUDED_psp_iolog_replay_h 21 | #define INCLUDED_psp_iolog_replay_h 22 | 23 | #include 24 | 25 | #include 26 | 27 | 28 | /** Opaque PSP I/O log replay handle. */ 29 | typedef struct PSPIOLOGREPLAYINT *PSPIOLOGREPLAY; 30 | /** Pointer to a PSP I/O log replay handle. */ 31 | typedef PSPIOLOGREPLAY *PPSPIOLOGREPLAY; 32 | 33 | 34 | /** 35 | * Creates a new I/O log replay instance. 36 | * 37 | * @returns Status code. 38 | * @param phIoLogReplay Where to store the handle to the I/O log replay instance on success. 39 | * @param pszIoLogFilename The I/O log to use for replay. 40 | */ 41 | int PSPIoLogReplayCreate(PPSPIOLOGREPLAY phIoLogReplay, const char *pszIoLogFilename); 42 | 43 | 44 | /** 45 | * Destroys the given I/O log replay instance. 46 | * 47 | * @returns nothing. 48 | * @param hIoLogReplay The I/O log replay handle to destroy. 49 | */ 50 | void PSPIoLogReplayDestroy(PSPIOLOGREPLAY hIoLogReplay); 51 | 52 | 53 | /** 54 | * Registers the given CCD handle with the I/O log replay instance. 55 | * 56 | * @returns Status code. 57 | * @param hIoLogReplay The I/O log replay. 58 | * @param hCcd The CCD handle to register. 59 | */ 60 | int PSPIoLogReplayCcdRegister(PSPIOLOGREPLAY hIoLogReplay, PSPCCD hCcd); 61 | 62 | 63 | /** 64 | * Deregisters the given CCD handle from the given I/O log replay instance. 65 | * 66 | * @returns Status code. 67 | * @param hProxy The proxy handle. 68 | * @param hCcd The CCD handle to deregister. 69 | */ 70 | int PSPIoLogReplayCcdDeregister(PSPIOLOGREPLAY hIoLogReplay, PSPCCD hCcd); 71 | 72 | #endif /* !INCLUDED_psp_iolog_replay_h */ 73 | 74 | -------------------------------------------------------------------------------- /include/psp-iolog.h: -------------------------------------------------------------------------------- 1 | /** @file 2 | * PSP Emulator - I/O log. 3 | */ 4 | 5 | /* 6 | * Copyright (C) 2020 Alexander Eichner 7 | * 8 | * This program is free software: you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License as published by 10 | * the Free Software Foundation, version 3. 11 | * 12 | * This program is distributed in the hope that it will be useful, but 13 | * WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 | * General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with this program. If not, see . 19 | */ 20 | #ifndef __psp_iolog_h 21 | #define __psp_iolog_h 22 | 23 | #include 24 | #include 25 | 26 | /** Opaque PSP I/O log writer handle. */ 27 | typedef struct PSPIOLOGWRINT *PSPIOLOGWR; 28 | /** Pointer to a PSP I/O log writer handle. */ 29 | typedef PSPIOLOGWR *PPSPIOLOGWR; 30 | 31 | /** Opaque PSP I/O log reader handle. */ 32 | typedef struct PSPIOLOGRDRINT *PSPIOLOGRDR; 33 | /** Pointer to a PSP I/O log reader handle. */ 34 | typedef PSPIOLOGRDR *PPSPIOLOGRDR; 35 | 36 | 37 | /** 38 | * I/O log reader event. 39 | */ 40 | typedef struct PSPIOLOGRDREVT 41 | { 42 | /** The address space being accessed. */ 43 | PSPADDRSPACE enmAddrSpace; 44 | /** The CCD ID causing the access. */ 45 | uint32_t idCcd; 46 | /** The program counter causing the access. */ 47 | PSPADDR PspAddrPc; 48 | /** Size of the access in bytes. */ 49 | size_t cbAcc; 50 | /** Flag whether the access was a read or write. */ 51 | bool fWrite; 52 | /** Pointer to the data being read or written. */ 53 | const void *pvData; 54 | /** Address space dependent address. */ 55 | union 56 | { 57 | /** SMN address. */ 58 | SMNADDR SmnAddr; 59 | /** PSP MMIO address. */ 60 | PSPADDR PspAddrMmio; 61 | /** x86 address. */ 62 | X86PADDR PhysX86Addr; 63 | } u; 64 | } PSPIOLOGRDREVT; 65 | /** Pointer to a I/O log reader event. */ 66 | typedef PSPIOLOGRDREVT *PPSPIOLOGRDREVT; 67 | /** Pointer to a const I/O log reader event. */ 68 | typedef const PSPIOLOGRDREVT *PCPSPIOLOGRDREVT; 69 | 70 | 71 | /** 72 | * Creates a new I/O log writer instance. 73 | * 74 | * @returns Status code. 75 | * @param phIoLogWr Where to store the I/O log writer handle on success. 76 | * @param fFlags Flags controlling the behavior, MBZ. 77 | * @param pszFilename The filename of the I/O log. 78 | */ 79 | int PSPEmuIoLogWrCreate(PPSPIOLOGWR phIoLogWr, uint32_t fFlags, const char *pszFilename); 80 | 81 | 82 | /** 83 | * Destroys a given I/O log handle. 84 | * 85 | * @returns nothing. 86 | * @param hIoLogWr The I/O log writer handle to destroy. 87 | */ 88 | void PSPEmuIoLogWrDestroy(PSPIOLOGWR hIoLogWr); 89 | 90 | 91 | /** 92 | * Add a SMN access to the I/O log. 93 | * 94 | * @returns Status code. 95 | * @param hIoLogWr The I/O log writer handle. 96 | * @param idCcd The CCD id the access originates from. 97 | * @param SmnAddr The SMN address the access started at. 98 | * @param fWrite Flag whether this access is a write. 99 | * @param cb Size of the access in bytes. 100 | * @param pv Data being read or written depending on the write flag. 101 | */ 102 | int PSPEmuIoLogWrSmnAccAdd(PSPIOLOGWR hIoLogWr, uint32_t idCcd, PSPADDR PspAddrPc, SMNADDR SmnAddr, bool fWrite, size_t cb, const void *pv); 103 | 104 | 105 | /** 106 | * Add a PSP MMIO access to the I/O log. 107 | * 108 | * @returns Status code. 109 | * @param hIoLogWr The I/O log writer handle. 110 | * @param idCcd The CCD id the access originates from. 111 | * @param PspAddrMmio The MMIO address the access started at. 112 | * @param fWrite Flag whether this access is a write. 113 | * @param cb Size of the access in bytes. 114 | * @param pv Data being read or written depending on the write flag. 115 | */ 116 | int PSPEmuIoLogWrMmioAccAdd(PSPIOLOGWR hIoLogWr, uint32_t idCcd, PSPADDR PspAddrPc, PSPADDR PspAddrMmio, bool fWrite, size_t cb, const void *pv); 117 | 118 | 119 | /** 120 | * Add a PSP x86 access to the I/O log. 121 | * 122 | * @returns Status code. 123 | * @param hIoLogWr The I/O log writer handle. 124 | * @param idCcd The CCD id the access originates from. 125 | * @param PhysX86Addr The physical x86 address the access started at. 126 | * @param fWrite Flag whether this access is a write. 127 | * @param cb Size of the access in bytes. 128 | * @param pv Data being read or written depending on the write flag. 129 | */ 130 | int PSPEmuIoLogWrX86AccAdd(PSPIOLOGWR hIoLogWr, uint32_t idCcd, PSPADDR PspAddrPc, X86PADDR PhysX86Addr, bool fWrite, size_t cb, const void *pv); 131 | 132 | 133 | /** 134 | * Create a new I/O log reader instance. 135 | * 136 | * @returns Status code. 137 | * @param phIoLogRdr Where to store the handle to the reader instance on success. 138 | * @param pszFilename The I/O log file to open. 139 | */ 140 | int PSPEmuIoLogRdrCreate(PPSPIOLOGRDR phIoLogRdr, const char *pszFilename); 141 | 142 | 143 | /** 144 | * Destroys the given I/O log reader instance. 145 | * 146 | * @returns nothing. 147 | * @param hIoLogRdr The I/O log reader instance to destroy. 148 | */ 149 | void PSPEmuIoLogRdrDestroy(PSPIOLOGRDR hIoLogRdr); 150 | 151 | 152 | /** 153 | * Queries the next I/O event from the given I/O log reader instance. 154 | * 155 | * @returns Status code. 156 | * @param hIoLogRdr The I/O log reader instance. 157 | * @param ppIoLogEvt Where to store the pointer to the next event on success. 158 | * 159 | * @note Call PSPEmuIoLogRdrEvtFree() when done to free allocated resources for the given event. 160 | */ 161 | int PSPEmuIoLogRdrEvtQueryNext(PSPIOLOGRDR hIoLogRdr, PCPSPIOLOGRDREVT *ppIoLogEvt); 162 | 163 | 164 | /** 165 | * Frees the given I/O log event returned from a previous PSPEmuIoLogRdrEvtQueryNext() call. 166 | * 167 | * @returns Status code. 168 | * @param hIoLogRdr The I/O log reader instance. 169 | * @param pIoLogEvt The I/O event to free. 170 | */ 171 | int PSPEmuIoLogRdrEvtFree(PSPIOLOGRDR hIoLogRdr, PCPSPIOLOGRDREVT pIoLogEvt); 172 | 173 | #endif /* __psp_iolog_h */ 174 | -------------------------------------------------------------------------------- /include/psp-irq.h: -------------------------------------------------------------------------------- 1 | /** @file 2 | * PSP Emulator - Interrupt controller. 3 | */ 4 | 5 | /* 6 | * Copyright (C) 2020 Alexander Eichner 7 | * 8 | * This program is free software: you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License as published by 10 | * the Free Software Foundation, version 3. 11 | * 12 | * This program is distributed in the hope that it will be useful, but 13 | * WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 | * General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with this program. If not, see . 19 | */ 20 | #ifndef INCLUDED_psp_irq_h 21 | #define INCLUDED_psp_irq_h 22 | 23 | #include 24 | 25 | #include 26 | #include 27 | 28 | 29 | /** Opaque PSP interrupt controller handle. */ 30 | typedef struct PSPIRQINT *PSPIRQ; 31 | /** Pointer to a PSP interrupt controller handle. */ 32 | typedef PSPIRQ *PPSPIRQ; 33 | 34 | 35 | /** 36 | * Creates a new interrupt controller instance. 37 | * 38 | * @returns Status code. 39 | * @param phIrq Where to store the IRQ controller handle on success. 40 | * @param hPspCore The PSP core the interrupt controller is connected to. 41 | * @param hIoMgr The I/O manager handle for the given PSP core to register MMIO handlers 42 | * for the interrupt controller registers. 43 | */ 44 | int PSPIrqCreate(PPSPIRQ phIrq, PSPCORE hPspCore, PSPIOM hIoMgr); 45 | 46 | 47 | /** 48 | * Destroys a given interrupt controller handle. 49 | * 50 | * @returns nothing. 51 | * @param hIrq The interrupt controller handle to destroy. 52 | */ 53 | void PSPIrqDestroy(PSPIRQ hIrq); 54 | 55 | 56 | /** 57 | * Resets the interrupt controller state. 58 | * 59 | * @returns nothing. 60 | * @param hIrq The interrupt controller handle. 61 | */ 62 | void PSPIrqReset(PSPIRQ hIrq); 63 | 64 | 65 | /** 66 | * Sets an interrupt request for the specified priority group and interrupt number. 67 | * 68 | * @returns Status code. 69 | * @param hIrq The interrupt controller handle. 70 | * @param uPrioGrp The priority group of the device sending the interrupt. 71 | * @param uIrq The interrupt number inside the priority group of the device. 72 | * @param fAssert Flag whether the interrupt line is asserted. 73 | */ 74 | int PSPIrqSet(PSPIRQ hIrq, uint32_t uPrioGrp, uint8_t uIrq, bool fAssert); 75 | 76 | #endif /* !INCLUDED_psp_irq_h */ 77 | -------------------------------------------------------------------------------- /include/psp-profile.h: -------------------------------------------------------------------------------- 1 | /** @file 2 | * PSP Emulator - Profile definitions for PSPs and specific AMD CPUs. 3 | */ 4 | 5 | /* 6 | * Copyright (C) 2020 Alexander Eichner 7 | * 8 | * This program is free software: you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License as published by 10 | * the Free Software Foundation, version 3. 11 | * 12 | * This program is distributed in the hope that it will be useful, but 13 | * WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 | * General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with this program. If not, see . 19 | */ 20 | #ifndef INCLUDED_psp_profile_h 21 | #define INCLUDED_psp_profile_h 22 | 23 | #include 24 | 25 | 26 | /** 27 | * Micro architecture of the CPU. 28 | */ 29 | typedef enum PSPEMUMICROARCH 30 | { 31 | /** Invalid value. */ 32 | PSPEMUMICROARCH_INVALID = 0, 33 | /** Original Zen. */ 34 | PSPEMUMICROARCH_ZEN, 35 | /* Zen+ */ 36 | PSPEMUMICROARCH_ZEN_PLUS, 37 | /* Zen2 */ 38 | PSPEMUMICROARCH_ZEN2, 39 | /* Zen3 */ 40 | PSPEMUMICROARCH_ZEN3, 41 | /** 32bit hack. */ 42 | PSPEMUMICROARCH_32BIT_HACK = 0x7fffffff 43 | } PSPEMUMICROARCH; 44 | 45 | 46 | /** 47 | * AMD CPU segment. 48 | */ 49 | typedef enum PSPEMUAMDCPUSEGMENT 50 | { 51 | /** Invalid segment. */ 52 | PSPEMUAMDCPUSEGMENT_INVALID = 0, 53 | /** Ryzen (Consumer). */ 54 | PSPEMUAMDCPUSEGMENT_RYZEN, 55 | /** Ryzen Pro (Business). */ 56 | PSPEMUAMDCPUSEGMENT_RYZEN_PRO, 57 | /** Threadripper (HEDT). */ 58 | PSPEMUAMDCPUSEGMENT_THREADRIPPER, 59 | /** Epyc (Server). */ 60 | PSPEMUAMDCPUSEGMENT_EPYC, 61 | /** 32bit hack. */ 62 | PSPEMUAMDCPUSEGMENT_32BIT_HACK = 0x7fffffff 63 | } PSPEMUAMDCPUSEGMENT; 64 | 65 | 66 | /** 67 | * Bootloader stage. 68 | */ 69 | typedef enum PSPBLSTAGE 70 | { 71 | /** Invalid bootloader stage. */ 72 | PSPBLSTAGE_INVALID = 0, 73 | /** on-chip BL stage. */ 74 | PSPBLSTAGE_ON_CHIP, 75 | /** off-chip BL stage. */ 76 | PSPBLSTAGE_OFF_CHIP, 77 | /** @todo ABL stages. */ 78 | /** Any stage. */ 79 | PSPBLSTAGE_ANY, 80 | /** Unknown stage. */ 81 | PSPBLSTAGE_UNKNOWN, 82 | /** 32bit hack. */ 83 | PSPBLSTAGE_32BIT_HACK = 0x7fffffff 84 | } PSPBLSTAGE; 85 | 86 | 87 | /** 88 | * PSP address descriptor. 89 | */ 90 | typedef struct PSPADDRDESC 91 | { 92 | /** The address space. */ 93 | PSPADDRSPACE enmAddrSpace; 94 | /** The address. */ 95 | union 96 | { 97 | /** Raw value (used for the initialization macros). */ 98 | uint64_t u64Raw; 99 | /** PSP physical address. */ 100 | PSPPADDR PspAddr; 101 | /** SMN address. */ 102 | SMNADDR SmnAddr; 103 | /** X86 address. */ 104 | X86PADDR PhysX86Addr; 105 | } u; 106 | } PSPADDRDESC; 107 | /** Pointer to a PSP proxy address. */ 108 | typedef PSPADDRDESC *PPSPADDRDESC; 109 | /** Pointer to a const PSP proxy address. */ 110 | typedef const PSPADDRDESC *PCPSPADDRDESC; 111 | 112 | 113 | /** 114 | * PSP blocked address range descriptor for proxy mode. 115 | */ 116 | typedef struct PSPPROXYADDRBLOCKEDDESC 117 | { 118 | /** Name of the blocked region. */ 119 | const char *pszRegion; 120 | /** The bootloader stage. */ 121 | PSPBLSTAGE enmBlStage; 122 | /** Start address being blocked. */ 123 | PSPADDRDESC AddrStart; 124 | /** Size of the region in bytes being blocked. */ 125 | size_t cbRegion; 126 | /** Access size being blocked, 0 means size doesn't matter. */ 127 | size_t cbAcc; 128 | /** Access related flags controlling when it is being blocked. */ 129 | uint32_t fAccess; 130 | /** Proxy feature related flags. */ 131 | uint32_t fProxyFeat; 132 | /** Value to return on reads if blocked. */ 133 | uint32_t u32ValRead; 134 | } PSPPROXYADDRBLOCKEDDESC; 135 | /** Pointer to a blocked range descriptor. */ 136 | typedef PSPPROXYADDRBLOCKEDDESC *PPSPPROXYADDRBLOCKEDDESC; 137 | /** Pointer to a const blocked range descriptor. */ 138 | typedef const PSPPROXYADDRBLOCKEDDESC *PCPSPPROXYADDRBLOCKEDDESC; 139 | 140 | 141 | /** Read accesses are blocked. */ 142 | #define PSPPROXY_ADDR_BLOCKED_ACCESS_F_READ BIT(0) 143 | /** Write accesses are blocked. */ 144 | #define PSPPROXY_ADDR_BLOCKED_ACCESS_F_WRITE BIT(1) 145 | 146 | 147 | /** The range is blocked when the proxy uses the SPI communication channel. */ 148 | #define PSPPROXY_ADDR_BLOCKED_FEAT_F_SPI BIT(0) 149 | /** The range is blocked when the proxy uses the x86 UART communication channel. */ 150 | #define PSPPROXY_ADDR_BLOCKED_FEAT_F_X86_UART BIT(1) 151 | /** The range is blocked when the proxy is instructed to not release the x86 cores. */ 152 | #define PSPPROXY_ADDR_BLOCKED_FEAT_F_NO_X86_RELEASE BIT(2) 153 | 154 | 155 | /** Initializes a non writeable PSP MMIO range for every BL stage no matter the access size. */ 156 | #define PSPPROXY_ADDR_BLOCKED_MMIO_INIT_WR(a_pszName, a_AddrMmio, a_cbRegion) \ 157 | { (a_pszName), PSPBLSTAGE_ANY, { PSPADDRSPACE_PSP_MMIO, .u = { (a_AddrMmio) } }, (a_cbRegion), 0, PSPPROXY_ADDR_BLOCKED_ACCESS_F_WRITE, 0, 0} 158 | /** Initializes a non accessible SMN range for every BL stage no matter the access size for a specific proxy feature. */ 159 | #define PSPPROXY_ADDR_BLOCKED_SMN_INIT_ALL_FEAT(a_pszName, a_AddrSmn, a_cbRegion, a_u32ValRead, a_fProxyFeat) \ 160 | { (a_pszName), PSPBLSTAGE_ANY, { PSPADDRSPACE_SMN, .u = { (a_AddrSmn) } }, (a_cbRegion), 0, PSPPROXY_ADDR_BLOCKED_ACCESS_F_WRITE | PSPPROXY_ADDR_BLOCKED_ACCESS_F_READ, (a_fProxyFeat), (a_u32ValRead) } 161 | /** Initializes a non accessible x86 range for every BL stage no matter the access size for a specific proxy feature. */ 162 | #define PSPPROXY_ADDR_BLOCKED_X86_INIT_ALL_FEAT(a_pszName, a_PhysX86Addr, a_cbRegion, a_u32ValRead, a_fProxyFeat) \ 163 | { (a_pszName), PSPBLSTAGE_ANY, { PSPADDRSPACE_X86, .u = { (a_PhysX86Addr) } }, (a_cbRegion), 0, PSPPROXY_ADDR_BLOCKED_ACCESS_F_WRITE | PSPPROXY_ADDR_BLOCKED_ACCESS_F_READ, (a_fProxyFeat), (a_u32ValRead) } 164 | /** @todo More macros as the need arises. */ 165 | 166 | 167 | /** 168 | * PSP profile. 169 | */ 170 | typedef struct PSPPROFILE 171 | { 172 | /** PSP profile identifier. */ 173 | const char *pszId; 174 | /** PSP profile description. */ 175 | const char *pszDesc; 176 | /** The micro architecture we are emulating. */ 177 | PSPEMUMICROARCH enmMicroArch; 178 | /** The PSP version(?) value the on chip bootloader is writing into PSPPROFILE::PspAddrMmioVersion, 179 | * used to load the proper directories from the flash image when starting with the off chip bootloader. */ 180 | uint32_t u32PspOnChipBlVersion; 181 | /** SRAM size in bytes. */ 182 | size_t cbSram; 183 | /** Physical address of the BRSP in SRAM. */ 184 | PSPPADDR PspAddrBrsp; 185 | /** Location of the PSP Version(?) register written to by the on chip BL (and read by it and maybe others). */ 186 | PSPPADDR PspAddrMmioVersion; 187 | /** Location of the status port. */ 188 | PSPPADDR PspAddrMmioSts; 189 | /** Location where the flash starts in SMN. */ 190 | SMNADDR SmnAddrFlashStart; 191 | /** Array of blocked MMIO ranges for proxy mode. */ 192 | PCPSPPROXYADDRBLOCKEDDESC paAddrProxyBlockedMmio; 193 | /** Number of entries in the blocked MMIO range array. */ 194 | uint32_t cAddrProxyBlockedMmio; 195 | /** Array of blocked SMN ranges for proxy mode. */ 196 | PCPSPPROXYADDRBLOCKEDDESC paAddrProxyBlockedSmn; 197 | /** Number of entries in the blocked SMN range array. */ 198 | uint32_t cAddrProxyBlockedSmn; 199 | /** Array of blocked x86 ranges for proxy mode. */ 200 | PCPSPPROXYADDRBLOCKEDDESC paAddrProxyBlockedX86; 201 | /** Number of entries in the blocked x86 range array. */ 202 | uint32_t cAddrProxyBlockedX86; 203 | } PSPPROFILE; 204 | /** Pointer to a PSP profile. */ 205 | typedef PSPPROFILE *PPSPPROFILE; 206 | /** Pointer to a const PSP profile. */ 207 | typedef const PSPPROFILE *PCPSPPROFILE; 208 | 209 | 210 | /** 211 | * AMD CPU profile. 212 | */ 213 | typedef struct PSPAMDCPUPROFILE 214 | { 215 | /** CPU profile identifier. */ 216 | const char *pszId; 217 | /** CPU profile description. */ 218 | const char *pszDesc; 219 | /** The micro architecture we are emulating. */ 220 | PSPEMUMICROARCH enmMicroArch; 221 | /** The CPU segment we are emulating. */ 222 | PSPEMUAMDCPUSEGMENT enmCpuSegment; 223 | /** Number of CCDs per socket. */ 224 | uint32_t cCcdsPerSocket; 225 | /** Maximum number of sockets supported by the CPU. */ 226 | uint32_t cSocketsMax; 227 | /** Number of cores per CCX. */ 228 | uint32_t cCoresPerCcx; 229 | /** Number of CCXs enabled/available for the CPU model. */ 230 | uint32_t cCcxs; 231 | /** Number of total cores enabled on the CCD. */ 232 | uint32_t cCoresPerCcd; 233 | /** Pointer to the assigned PSP profile for the CPU entry. */ 234 | PCPSPPROFILE pPspProfile; 235 | /** Array of blocked SMN ranges for proxy mode specific for the selected CPU profile. */ 236 | PCPSPPROXYADDRBLOCKEDDESC paAddrProxyBlockedSmn; 237 | /** Number of entries in the blocked SMN range array. */ 238 | uint32_t cAddrProxyBlockedSmn; 239 | } PSPAMDCPUPROFILE; 240 | /** Pointer to an AMD CPU profile. */ 241 | typedef PSPAMDCPUPROFILE *PPSPAMDCPUPROFILE; 242 | /** Pointer to a const AMD CPU profile. */ 243 | typedef const PSPAMDCPUPROFILE *PCPSPAMDCPUPROFILE; 244 | 245 | 246 | 247 | /** 248 | * Gets the PSP profile with the given ID. 249 | * 250 | * @returns Pointer to the PSP profile if found, NULL if not found. 251 | * @param pszId The ID to look for. 252 | */ 253 | PCPSPPROFILE PSPProfilePspGetById(const char *pszId); 254 | 255 | 256 | /** 257 | * Gets the AMD CPU profile with the given ID. 258 | * 259 | * @returns Pointer to the AMD CPU profile if found, NULL if not found. 260 | * @param pszId The ID to look for. 261 | */ 262 | PCPSPAMDCPUPROFILE PSPProfileAmdCpuGetById(const char *pszId); 263 | 264 | 265 | /** 266 | * Gets the default AMD CPU profile. 267 | * 268 | * @returns Pointer to the AMD CPU profile if found, NULL if not found. 269 | */ 270 | PCPSPAMDCPUPROFILE PSPProfileAmdCpuGetDefault(void); 271 | 272 | #endif /* !INCLUDED_psp_profile_h */ 273 | 274 | -------------------------------------------------------------------------------- /include/psp-proxy.h: -------------------------------------------------------------------------------- 1 | /** @file 2 | * PSP Emulator - API for proxying accesses to a real PSP. 3 | */ 4 | 5 | /* 6 | * Copyright (C) 2020 Alexander Eichner 7 | * 8 | * This program is free software: you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License as published by 10 | * the Free Software Foundation, version 3. 11 | * 12 | * This program is distributed in the hope that it will be useful, but 13 | * WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 | * General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with this program. If not, see . 19 | */ 20 | #ifndef __psp_proxy_h 21 | #define __psp_proxy_h 22 | 23 | #include 24 | 25 | #include 26 | #include 27 | #include 28 | 29 | 30 | /** Opaque PSP proxy handle. */ 31 | typedef struct PSPPROXYINT *PSPPROXY; 32 | /** Pointer to a PSP proxy handle. */ 33 | typedef PSPPROXY *PPSPPROXY; 34 | 35 | 36 | /** 37 | * Creates a new proxy instance. 38 | * 39 | * @returns Status code. 40 | * @param phProxy Where to store the handle to the proxy instance on success. 41 | * @param pCfg Pointer to the global emulator config. 42 | */ 43 | int PSPProxyCreate(PPSPPROXY phProxy, PPSPEMUCFG pCfg); 44 | 45 | 46 | /** 47 | * Destroys the given proxy handle. 48 | * 49 | * @returns nothing. 50 | * @param hProxy The proxy handle to destroy. 51 | */ 52 | void PSPProxyDestroy(PSPPROXY hProxy); 53 | 54 | 55 | /** 56 | * Registers the given CCD handle for hardware access proxying. 57 | * 58 | * @returns Status code. 59 | * @param hProxy The proxy handle. 60 | * @param hCcd The CCD handle to register. 61 | */ 62 | int PSPProxyCcdRegister(PSPPROXY hProxy, PSPCCD hCcd); 63 | 64 | 65 | /** 66 | * Deregisters the given CCD handle with the given proxy. 67 | * 68 | * @returns Status code. 69 | * @param hProxy The proxy handle. 70 | * @param hCcd The CCD handle to deregister. 71 | */ 72 | int PSPProxyCcdDeregister(PSPPROXY hProxy, PSPCCD hCcd); 73 | 74 | 75 | /** 76 | * Registers the given x86 ICE bridge for hardware access proxying. 77 | * 78 | * @returns Status code. 79 | * @param hProxy The proxy handle. 80 | * @param hX86Ice The ICE bridge handle to register. 81 | */ 82 | int PSPProxyX86IceRegister(PSPPROXY hProxy, PSPX86ICE hX86Ice); 83 | 84 | 85 | /** 86 | * Registers the given x86 ICE bridge from the given proxy. 87 | * 88 | * @returns Status code. 89 | * @param hProxy The proxy handle. 90 | * @param hX86Ice The ICE bridge handle to deregister. 91 | */ 92 | int PSPProxyX86IceDeregister(PSPPROXY hProxy, PSPX86ICE hX86Ice); 93 | 94 | 95 | /** 96 | * Returns whether accessing the given MMIO address is allowed accessing through the proxy 97 | * for the given stage. 98 | * 99 | * @returns Status code. 100 | * @param hProxy The proxy handle. 101 | * @param PspAddrMmio The MMIO address being accessed. 102 | * @param cbAcc Size of the access in bytes. 103 | * @param fWrite Flag whether this is a read of write access. 104 | * @param enmStage The bootloader stage. 105 | * @param pvReadVal Where to store the value to return for blocked reads. 106 | */ 107 | bool PSPProxyIsMmioAccessAllowed(PSPPROXY hProxy, PSPADDR PspAddrMmio, size_t cbAcc, bool fWrite, PSPBLSTAGE enmStage, 108 | void *pvReadVal); 109 | 110 | 111 | /** 112 | * Returns whether accessing the given SMN address is allowed accessing through the proxy 113 | * for the given stage. 114 | * 115 | * @returns Status code. 116 | * @param hProxy The proxy handle. 117 | * @param SmnAddr The SMN address being accessed. 118 | * @param cbAcc Size of the access in bytes. 119 | * @param fWrite Flag whether this is a read of write access. 120 | * @param enmStage The bootloader stage. 121 | * @param pvReadVal Where to store the value to return for blocked reads. 122 | */ 123 | bool PSPProxyIsSmnAccessAllowed(PSPPROXY hProxy, SMNADDR SmnAddr, size_t cbAcc, bool fWrite, PSPBLSTAGE enmStage, 124 | void *pvReadVal); 125 | 126 | 127 | /** 128 | * Returns whether accessing the given SMN address is allowed accessing through the proxy 129 | * for the given stage. 130 | * 131 | * @returns Status code. 132 | * @param hProxy The proxy handle. 133 | * @param PhysX86Addr The physical x86 address being accessed. 134 | * @param cbAcc Size of the access in bytes. 135 | * @param fWrite Flag whether this is a read of write access. 136 | * @param enmStage The bootloader stage. 137 | * @param pvReadVal Where to store the value to return for blocked reads. 138 | */ 139 | bool PSPProxyIsX86AccessAllowed(PSPPROXY hProxy, X86PADDR PhysX86Addr, size_t cbAcc, bool fWrite, PSPBLSTAGE enmStage, 140 | void *pvReadVal); 141 | 142 | 143 | #endif /* !__psp_proxy_h */ 144 | -------------------------------------------------------------------------------- /include/psp-svc.h: -------------------------------------------------------------------------------- 1 | /** @file 2 | * PSP Emulator - API for the emulated supervisor part (SVC) 3 | */ 4 | 5 | /* 6 | * Copyright (C) 2019-2020 Alexander Eichner 7 | * 8 | * This program is free software: you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License as published by 10 | * the Free Software Foundation, version 3. 11 | * 12 | * This program is distributed in the hope that it will be useful, but 13 | * WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 | * General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with this program. If not, see . 19 | */ 20 | #ifndef __psp_svc_h 21 | #define __psp_svc_h 22 | 23 | #include 24 | 25 | #include 26 | 27 | #include "psp-core.h" 28 | #include "psp-iom.h" 29 | 30 | /** Opaque PSP SVC state handle. */ 31 | typedef struct PSPSVCINT *PSPSVC; 32 | /** Pointer to a PSP emulation core handle. */ 33 | typedef PSPSVC *PPSPSVC; 34 | 35 | /** 36 | * Creates a new emulated PSP supervisor state. 37 | * 38 | * @returns Status code. 39 | * @param phSvcState Where to store the SVC state handle on success. 40 | * @param hPspCore The PSP core handle. 41 | * @param hIoMgr The I/O manager handle associated with the given PSP core. 42 | * @param hPspProxyCtx PSP proxy context to use for SVC emulation. 43 | */ 44 | int PSPEmuSvcStateCreate(PPSPSVC phSvcState, PSPCORE hPspCore, PSPIOM hIoMgr, PSPPROXYCTX hPspProxyCtx); 45 | 46 | /** 47 | * Destroys a given PSP sueprvisor state. 48 | * 49 | * @returns nothing. 50 | * @param hSvcState The SVC state handle to destroy. 51 | */ 52 | void PSPEmuSvcStateDestroy(PSPSVC hSvcState); 53 | 54 | #endif /* __psp_svc_h */ 55 | -------------------------------------------------------------------------------- /include/psp-x86-ice.h: -------------------------------------------------------------------------------- 1 | /** @file 2 | * PSP Emulator - API for the x86 ICE (In-circuit emulator) network interface. 3 | */ 4 | 5 | /* 6 | * Copyright (C) 2020 Alexander Eichner 7 | * 8 | * This program is free software: you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License as published by 10 | * the Free Software Foundation, version 3. 11 | * 12 | * This program is distributed in the hope that it will be useful, but 13 | * WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 | * General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with this program. If not, see . 19 | */ 20 | #ifndef INCLUDED_psp_x86_ice_h 21 | #define INCLUDED_psp_x86_ice_h 22 | 23 | #include 24 | 25 | 26 | /** Opaque PSP x86 ICE handle. */ 27 | typedef struct PSPX86ICEINT *PSPX86ICE; 28 | /** Pointer to a PSP x86 ICE handle. */ 29 | typedef PSPX86ICE *PPSPX86ICE; 30 | 31 | 32 | /** 33 | * x86 I/O port read handler. 34 | * 35 | * @returns Status code. 36 | * @param hX86Ice The X86 ICE instance triggering the callback. 37 | * @param IoPort The absolute I/O port to read from. 38 | * @param cbRead Number of bytes to read. 39 | * @param pvVal Where to store the read data. 40 | * @param pvUser Opaque user data passed during registration. 41 | */ 42 | typedef int (FNPSPX86ICEIOPORTREAD)(PSPX86ICE hX86Ice, uint16_t IoPort, size_t cbRead, void *pvVal, void *pvUser); 43 | /** x86 I/O port read handler pointer. */ 44 | typedef FNPSPX86ICEIOPORTREAD *PFNPSPX86ICEIOPORTREAD; 45 | 46 | 47 | /** 48 | * x86 I/O port write handler. 49 | * 50 | * @returns Status code. 51 | * @param hX86Ice The X86 ICE instance triggering the callback. 52 | * @param IoPort The absolute I/O port to write to. 53 | * @param cbWrite Number of bytes to write. 54 | * @param pvVal The data to write. 55 | * @param pvUser Opaque user data passed during registration. 56 | */ 57 | typedef int (FNPSPX86ICEIOPORTWRITE)(PSPX86ICE hX86Ice, uint16_t IoPort, size_t cbWrite, const void *pvVal, void *pvUser); 58 | /** x86 I/O port write handler pointer. */ 59 | typedef FNPSPX86ICEIOPORTWRITE *PFNPSPX86ICEIOPORTWRITE; 60 | 61 | 62 | /** 63 | * x86 MMIO access type. 64 | */ 65 | typedef enum PSPX86ICEMEMTYPE 66 | { 67 | /** Invalid memory type. */ 68 | PSPX86ICEMEMTYPE_INVALID = 0, 69 | /** RAM access. */ 70 | PSPX86ICEMEMTYPE_RAM, 71 | /** MMIO access. */ 72 | PSPX86ICEMEMTYPE_MMIO, 73 | /** Unknown memory type. */ 74 | PSPX86ICEMEMTYPE_UNKNOWN, 75 | /** 32bit hack. */ 76 | PSPX86ICEMEMTYPE_32BIT_HACK = 0x7fffffff 77 | } PSPX86ICEMEMTYPE; 78 | 79 | 80 | /** 81 | * x86 memory read handler. 82 | * 83 | * @returns Status code. 84 | * @param hX86Ice The X86 ICE instance triggering the callback. 85 | * @param PhysX86Addr The absolute x86 physical address to read from. 86 | * @param cbRead Number of bytes to read. 87 | * @param pvVal Where to store the read data. 88 | * @param pvUser Opaque user data passed during registration. 89 | */ 90 | typedef int (FNPSPX86ICEMEMREAD)(PSPX86ICE hX86Ice, X86PADDR PhysX86Addr, PSPX86ICEMEMTYPE enmMemType, size_t cbRead, void *pvVal, void *pvUser); 91 | /** x86 memory read handler pointer. */ 92 | typedef FNPSPX86ICEMEMREAD *PFNPSPX86ICEMEMREAD; 93 | 94 | 95 | /** 96 | * x86 memory write handler. 97 | * 98 | * @returns Status code. 99 | * @param hX86Ice The X86 ICE instance triggering the callback. 100 | * @param PhysX86Addr The absolute x86 physical address to write to. 101 | * @param cbWrite Number of bytes to write. 102 | * @param pvVal The data to write. 103 | * @param pvUser Opaque user data passed during registration. 104 | */ 105 | typedef int (FNPSPX86ICEMEMWRITE)(PSPX86ICE hX86Ice, X86PADDR PhysX86Addr, PSPX86ICEMEMTYPE enmMemType, size_t cbWrite, const void *pvVal, void *pvUser); 106 | /** x86 memory write handler pointer. */ 107 | typedef FNPSPX86ICEMEMWRITE *PFNPSPX86ICEMEMWRITE; 108 | 109 | 110 | /** 111 | * x86 MSR read handler. 112 | * 113 | * @returns Status code. 114 | * @param hX86Ice The X86 ICE instance triggering the callback. 115 | * @param idMsr The MSR to read. 116 | * @param idKey The key to use ((was?) required on for some MSRs on some older AMD CPUs) 117 | * @param pu64Val Where to store the read value. 118 | * @param pvUser Opaque user data passed during registration. 119 | */ 120 | typedef int (FNPSPX86ICEMSRREAD)(PSPX86ICE hX86Ice, uint32_t idMsr, uint32_t idKey, uint64_t *pu64Val, void *pvUser); 121 | /** x86 MSR read handler pointer. */ 122 | typedef FNPSPX86ICEMSRREAD *PFNPSPX86ICEMSRREAD; 123 | 124 | 125 | /** 126 | * x86 MSR write handler. 127 | * 128 | * @returns Status code. 129 | * @param hX86Ice The X86 ICE instance triggering the callback. 130 | * @param idMsr The MSR to write. 131 | * @param idKey The key to use ((was?) required on for some MSRs on some older AMD CPUs) 132 | * @param u64Val The value to write. 133 | * @param pvUser Opaque user data passed during registration. 134 | */ 135 | typedef int (FNPSPX86ICEMSRWRITE)(PSPX86ICE hX86Ice, uint32_t idMsr, uint32_t idKey, uint64_t u64Val, void *pvUser); 136 | /** x86 MSR write handler pointer. */ 137 | typedef FNPSPX86ICEMSRWRITE *PFNPSPX86ICEMSRWRITE; 138 | 139 | 140 | /** 141 | * Creates a new x86 ICE instance. 142 | * 143 | * @returns Status code. 144 | * @param phX86Ice Where to store the handle to the x86 ICE instance on success. 145 | * @param uPort The TCP port to listen on. 146 | */ 147 | int PSPX86IceCreate(PPSPX86ICE phX86Ice, uint16_t uPort); 148 | 149 | 150 | /** 151 | * Destroys the given x86 ICE handle. 152 | * 153 | * @returns nothing. 154 | * @param hX86Ice The x86 ICE handle to destroy. 155 | */ 156 | void PSPX86IceDestroy(PSPX86ICE hX86Ice); 157 | 158 | 159 | /** 160 | * Sets the given I/O port read/write handlers which get called for a matching request. 161 | * 162 | * @returns Status code. 163 | * @param hX86Ice The x86 ICE instance handle. 164 | * @param pfnIoPortRead The read handler to set. 165 | * @param pfnIoPortWrite The write handler to set. 166 | * @param pvUser Opaque user data passed in the callbacks. 167 | */ 168 | int PSPX86IceIoPortRwHandlerSet(PSPX86ICE hX86Ice, PFNPSPX86ICEIOPORTREAD pfnIoPortRead, PFNPSPX86ICEIOPORTWRITE pfnIoPortWrite, void *pvUser); 169 | 170 | 171 | /** 172 | * Sets the given memory read/write handlers which get called for a matching request. 173 | * 174 | * @returns Status code. 175 | * @param hX86Ice The x86 ICE instance handle. 176 | * @param pfnMemRead The read handler to set. 177 | * @param pfnMemWrite The write handler to set. 178 | * @param pvUser Opaque user data passed in the callbacks. 179 | */ 180 | int PSPX86IceMemRwHandlerSet(PSPX86ICE hX86Ice, PFNPSPX86ICEMEMREAD pfnMemRead, PFNPSPX86ICEMEMWRITE pfnMemWrite, void *pvUser); 181 | 182 | 183 | /** 184 | * Sets the given MSR read/write handlers which get called for a matching request. 185 | * 186 | * @returns Status code. 187 | * @param hX86Ice The x86 ICE instance handle. 188 | * @param pfnMsrRead The read handler to set. 189 | * @param pfnMsrWrite The write handler to set. 190 | * @param pvUser Opaque user data passed in the callbacks. 191 | */ 192 | int PSPX86IceMsrRwHandlerSet(PSPX86ICE hX86Ice, PFNPSPX86ICEMSRREAD pfnMsrRead, PFNPSPX86ICEMSRWRITE pfnMsrWrite, void *pvUser); 193 | 194 | #endif /* !INCLUDED_psp_x86_ice_h */ 195 | -------------------------------------------------------------------------------- /os/file.c: -------------------------------------------------------------------------------- 1 | /** @file 2 | * PSP Emulator - OS abstraction for file accesses. 3 | */ 4 | 5 | /* 6 | * Copyright (C) 2020 Alexander Eichner 7 | * 8 | * This program is free software: you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License as published by 10 | * the Free Software Foundation, version 3. 11 | * 12 | * This program is distributed in the hope that it will be useful, but 13 | * WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 | * General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with this program. If not, see . 19 | */ 20 | /********************************************************************************************************************************* 21 | * Header Files * 22 | *********************************************************************************************************************************/ 23 | #include 24 | #include 25 | #include 26 | 27 | #include 28 | 29 | #include 30 | 31 | 32 | /********************************************************************************************************************************* 33 | * Internal Functions * 34 | *********************************************************************************************************************************/ 35 | 36 | int OSFileLoadAll(const char *pszFilename, void **ppv, size_t *pcb) 37 | { 38 | int rc = 0; 39 | FILE *pFwFile = fopen(pszFilename, "rb"); 40 | if (pFwFile) 41 | { 42 | /* Determine file size. */ 43 | rc = fseek(pFwFile, 0, SEEK_END); 44 | if (!rc) 45 | { 46 | long cbFw = ftell(pFwFile); 47 | if (cbFw != -1) 48 | { 49 | rewind(pFwFile); 50 | 51 | void *pvFw = malloc(cbFw); 52 | if (pvFw) 53 | { 54 | size_t cbRead = fread(pvFw, cbFw, 1, pFwFile); 55 | if (cbRead == 1) 56 | { 57 | *ppv = pvFw; 58 | *pcb = cbFw; 59 | return STS_INF_SUCCESS; 60 | } 61 | 62 | free(pvFw); 63 | rc = STS_ERR_INVALID_PARAMETER; 64 | } 65 | else 66 | rc = STS_ERR_INVALID_PARAMETER; 67 | } 68 | else 69 | rc = STS_ERR_INVALID_PARAMETER; 70 | } 71 | else 72 | rc = STS_ERR_INVALID_PARAMETER; 73 | 74 | fclose(pFwFile); 75 | } 76 | else 77 | rc = STS_ERR_INVALID_PARAMETER; 78 | 79 | return rc; 80 | } 81 | 82 | 83 | int OSFileLoadAllFree(void *pv, size_t cb) 84 | { 85 | free(pv); 86 | return STS_INF_SUCCESS; 87 | } 88 | 89 | -------------------------------------------------------------------------------- /os/posix/lock.c: -------------------------------------------------------------------------------- 1 | /** @file 2 | * PSP Emulator - OS abstraction for lock related APIs, Posix implementation. 3 | */ 4 | 5 | /* 6 | * Copyright (C) 2020 Alexander Eichner 7 | * 8 | * This program is free software: you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License as published by 10 | * the Free Software Foundation, version 3. 11 | * 12 | * This program is distributed in the hope that it will be useful, but 13 | * WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 | * General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with this program. If not, see . 19 | */ 20 | /********************************************************************************************************************************* 21 | * Header Files * 22 | *********************************************************************************************************************************/ 23 | #include 24 | #include 25 | 26 | #include 27 | #include 28 | 29 | #include 30 | 31 | 32 | /********************************************************************************************************************************* 33 | * Structures and Typedefs * 34 | *********************************************************************************************************************************/ 35 | 36 | /** 37 | * Internal POSIX lock instance based on pthreads mutex implementation. 38 | */ 39 | typedef struct OSLOCKINT 40 | { 41 | /** The pthread mutex handle. */ 42 | pthread_mutex_t hMtx; 43 | } OSLOCKINT; 44 | /** Pointer to a the lock instance. */ 45 | typedef OSLOCKINT *POSLOCKINT; 46 | /** Pointer to a const lock instance. */ 47 | typedef const OSLOCKINT *PCOSLOCKINT; 48 | 49 | 50 | /********************************************************************************************************************************* 51 | * Internal Functions * 52 | *********************************************************************************************************************************/ 53 | 54 | int OSLockCreate(POSLOCK phLock) 55 | { 56 | int rc = STS_INF_SUCCESS; 57 | POSLOCKINT pThis = (POSLOCKINT)calloc(1, sizeof(*pThis)); 58 | if (pThis) 59 | { 60 | int rcPsx = pthread_mutex_init(&pThis->hMtx, NULL /*attr*/); 61 | if (!rcPsx) 62 | { 63 | *phLock = pThis; 64 | return STS_INF_SUCCESS; 65 | } 66 | else 67 | rc = STS_ERR_INVALID_PARAMETER; /** @todo Status codes. */ 68 | 69 | free(pThis); 70 | } 71 | else 72 | rc = STS_ERR_NO_MEMORY; 73 | 74 | return rc; 75 | } 76 | 77 | 78 | int OSLockDestroy(OSLOCK hLock) 79 | { 80 | POSLOCKINT pThis = hLock; 81 | int rc = STS_INF_SUCCESS; 82 | int rcPsx = pthread_mutex_destroy(&pThis->hMtx); 83 | if (!rcPsx) 84 | free(pThis); 85 | else 86 | rc = STS_ERR_INVALID_PARAMETER; 87 | 88 | return rc; 89 | } 90 | 91 | 92 | int OSLockAcquire(OSLOCK hLock) 93 | { 94 | POSLOCKINT pThis = hLock; 95 | int rc = STS_INF_SUCCESS; 96 | int rcPsx = pthread_mutex_lock(&pThis->hMtx); 97 | if (rcPsx) 98 | rc = STS_ERR_INVALID_PARAMETER; 99 | 100 | return rc; 101 | } 102 | 103 | 104 | int OSLockRelease(OSLOCK hLock) 105 | { 106 | POSLOCKINT pThis = hLock; 107 | int rc = STS_INF_SUCCESS; 108 | int rcPsx = pthread_mutex_unlock(&pThis->hMtx); 109 | if (rcPsx) 110 | rc = STS_ERR_INVALID_PARAMETER; 111 | 112 | return rc; 113 | } 114 | 115 | -------------------------------------------------------------------------------- /os/posix/thread.c: -------------------------------------------------------------------------------- 1 | /** @file 2 | * PSP Emulator - OS abstraction for threads, Posix implementation. 3 | */ 4 | 5 | /* 6 | * Copyright (C) 2020 Alexander Eichner 7 | * 8 | * This program is free software: you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License as published by 10 | * the Free Software Foundation, version 3. 11 | * 12 | * This program is distributed in the hope that it will be useful, but 13 | * WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 | * General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with this program. If not, see . 19 | */ 20 | /********************************************************************************************************************************* 21 | * Header Files * 22 | *********************************************************************************************************************************/ 23 | #include 24 | #include 25 | 26 | #include 27 | #include 28 | 29 | #include 30 | 31 | 32 | /********************************************************************************************************************************* 33 | * Structures and Typedefs * 34 | *********************************************************************************************************************************/ 35 | 36 | /** 37 | * Internal POSIX thread instance based on pthreads implementation. 38 | */ 39 | typedef struct OSTHREADINT 40 | { 41 | /** The pthread handle. */ 42 | pthread_t hPThrd; 43 | /** The handler to call. */ 44 | PFNOSTHREADMAIN pfnMain; 45 | /** Opaque user data to pass. */ 46 | void *pvUser; 47 | /** Status code upon exit. */ 48 | int rcExit; 49 | } OSTHREADINT; 50 | /** Pointer to a the thread instance. */ 51 | typedef OSTHREADINT *POSTHREADINT; 52 | /** Pointer to a const thread instance. */ 53 | typedef const OSTHREADINT *PCOSTHREADINT; 54 | 55 | 56 | /********************************************************************************************************************************* 57 | * Internal Functions * 58 | *********************************************************************************************************************************/ 59 | 60 | /** 61 | * Posix thread entry point. 62 | * 63 | * @returns Opaque return value. 64 | * @param pvArg Opaque user data. 65 | */ 66 | static void *osThreadPosixMain(void *pvArg) 67 | { 68 | POSTHREADINT pThis = (POSTHREADINT)pvArg; 69 | 70 | int rc = pThis->pfnMain(pThis, pThis->pvUser); 71 | pThis->rcExit = rc; 72 | 73 | return NULL; 74 | } 75 | 76 | 77 | int OSThreadCreate(POSTHREAD phThread, PFNOSTHREADMAIN pfnMain, void *pvUser) 78 | { 79 | int rc = STS_INF_SUCCESS; 80 | POSTHREADINT pThis = (POSTHREADINT)calloc(1, sizeof(*pThis)); 81 | if (pThis) 82 | { 83 | pThis->pfnMain = pfnMain; 84 | pThis->pvUser = pvUser; 85 | 86 | int rcPsx = pthread_create(&pThis->hPThrd, NULL /*attr*/, osThreadPosixMain, pThis); 87 | if (!rcPsx) 88 | { 89 | *phThread = pThis; 90 | return STS_INF_SUCCESS; 91 | } 92 | else 93 | rc = STS_ERR_INVALID_PARAMETER; /** @todo Status codes. */ 94 | 95 | free(pThis); 96 | } 97 | else 98 | rc = STS_ERR_NO_MEMORY; 99 | 100 | return rc; 101 | } 102 | 103 | 104 | int OSThreadDestroy(OSTHREAD hThread, int *prcThread) 105 | { 106 | POSTHREADINT pThis = hThread; 107 | 108 | int rc = STS_INF_SUCCESS; 109 | int rcPsx = pthread_join(pThis->hPThrd, NULL); 110 | if (!rcPsx) 111 | { 112 | if (prcThread) 113 | *prcThread = pThis->rcExit; 114 | free(pThis); 115 | } 116 | else 117 | rc = STS_ERR_INVALID_PARAMETER; /** @todo Status code. */ 118 | 119 | return rc; 120 | } 121 | 122 | -------------------------------------------------------------------------------- /os/posix/time.c: -------------------------------------------------------------------------------- 1 | /** @file 2 | * PSP Emulator - OS abstraction for timing related APIs, Posix implementation. 3 | */ 4 | 5 | /* 6 | * Copyright (C) 2020 Alexander Eichner 7 | * 8 | * This program is free software: you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License as published by 10 | * the Free Software Foundation, version 3. 11 | * 12 | * This program is distributed in the hope that it will be useful, but 13 | * WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 | * General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with this program. If not, see . 19 | */ 20 | /********************************************************************************************************************************* 21 | * Header Files * 22 | *********************************************************************************************************************************/ 23 | #include 24 | 25 | #include 26 | 27 | 28 | /********************************************************************************************************************************* 29 | * Internal Functions * 30 | *********************************************************************************************************************************/ 31 | 32 | uint64_t OSTimeTsGetNano(void) 33 | { 34 | struct timespec Tp; 35 | int rcPsx = clock_gettime(CLOCK_MONOTONIC, &Tp); 36 | if (!rcPsx) 37 | return ((uint64_t)Tp.tv_sec * 1000ULL * 1000ULL * 1000ULL) + Tp.tv_nsec; 38 | 39 | return 0; 40 | } 41 | 42 | -------------------------------------------------------------------------------- /profiles/amd-cpu-ryzen5-5600x.h: -------------------------------------------------------------------------------- 1 | /** @file 2 | * PSP Emulator - CPU profile for an AMD Ryzen 5 5600X. 3 | */ 4 | 5 | /* 6 | * Copyright (C) 2020 Alexander Eichner 7 | * 8 | * This program is free software: you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License as published by 10 | * the Free Software Foundation, version 3. 11 | * 12 | * This program is distributed in the hope that it will be useful, but 13 | * WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 | * General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with this program. If not, see . 19 | */ 20 | #ifndef PSPEMU_PROFILES_psp_amd_cpu_ryzen5_5600x_h 21 | #define PSPEMU_PROFILES_psp_amd_cpu_ryzen5_5600x_h 22 | 23 | 24 | /** 25 | * CPU profile for an AMD CPU Ryzen 5 5600X 26 | */ 27 | static const PSPAMDCPUPROFILE g_AmdCpu_Ryzen5_5600X = 28 | { 29 | /** pszId */ 30 | "ryzen5-5600x", 31 | /** pszDesc */ 32 | "AMD Ryzen 5 5600X Six Core CPU", 33 | /** enmMicroArch */ 34 | PSPEMUMICROARCH_ZEN3, 35 | /** enmCpuSegment */ 36 | PSPEMUAMDCPUSEGMENT_RYZEN, 37 | /** cCcdsPerSocket */ 38 | 1, 39 | /** cSocketsMax */ 40 | 1, 41 | /** cCoresPerCcx */ 42 | 6, 43 | /** cCcxs */ 44 | 1, 45 | /** cCoresPerCcd */ 46 | 6, 47 | /** pPspProfile. */ 48 | &g_PspProfileZen3, 49 | /** paAddrProxyBlockedSmn */ 50 | NULL, 51 | /** cAddrProxyBlockedSmn */ 52 | 0 53 | }; 54 | 55 | #endif /* !PSPEMU_PROFILES_psp_amd_cpu_ryzen5_5600x_h */ 56 | 57 | -------------------------------------------------------------------------------- /profiles/amd-cpu-ryzen7-1800x.h: -------------------------------------------------------------------------------- 1 | /** @file 2 | * PSP Emulator - CPU profile for an AMD Ryzen 7 1800X. 3 | */ 4 | 5 | /* 6 | * Copyright (C) 2020 Alexander Eichner 7 | * 8 | * This program is free software: you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License as published by 10 | * the Free Software Foundation, version 3. 11 | * 12 | * This program is distributed in the hope that it will be useful, but 13 | * WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 | * General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with this program. If not, see . 19 | */ 20 | #ifndef PSPEMU_PROFILES_psp_amd_cpu_ryzen7_1800x_h 21 | #define PSPEMU_PROFILES_psp_amd_cpu_ryzen7_1800x_h 22 | 23 | 24 | /** 25 | * Standard SMN ranges being blocked in proxy mode. 26 | */ 27 | static const PSPPROXYADDRBLOCKEDDESC g_aProxyBlockedSmn_AmdCpu_Ryzen7_1800x[] = 28 | { 29 | /* 30 | * The following monitor commands release the x86 cores on an Ryzen 1800x (1 CCD, 2CCX, 8 cores/16 threads): 31 | * 32 | * monitor proxy.SmnWrite 0x18002ff0 4 0x80000000 33 | * monitor proxy.SmnWrite 0x18022ff0 4 0x80000000 34 | * monitor proxy.SmnWrite 0x18042ff0 4 0x80000000 35 | * monitor proxy.SmnWrite 0x18062ff0 4 0x80000000 36 | * monitor proxy.SmnWrite 0x18402ff0 4 0x80000000 37 | * monitor proxy.SmnWrite 0x18422ff0 4 0x80000000 38 | * monitor proxy.SmnWrite 0x18442ff0 4 0x80000000 39 | * monitor proxy.SmnWrite 0x18462ff0 4 0x80000000 40 | */ 41 | PSPPROXY_ADDR_BLOCKED_SMN_INIT_ALL_FEAT("X86Ccx0Core0", 0x18002ff0, 4, 0, PSPPROXY_ADDR_BLOCKED_FEAT_F_NO_X86_RELEASE), 42 | PSPPROXY_ADDR_BLOCKED_SMN_INIT_ALL_FEAT("X86Ccx0Core1", 0x18022ff0, 4, 0, PSPPROXY_ADDR_BLOCKED_FEAT_F_NO_X86_RELEASE), 43 | PSPPROXY_ADDR_BLOCKED_SMN_INIT_ALL_FEAT("X86Ccx0Core2", 0x18042ff0, 4, 0, PSPPROXY_ADDR_BLOCKED_FEAT_F_NO_X86_RELEASE), 44 | PSPPROXY_ADDR_BLOCKED_SMN_INIT_ALL_FEAT("X86Ccx0Core3", 0x18062ff0, 4, 0, PSPPROXY_ADDR_BLOCKED_FEAT_F_NO_X86_RELEASE), 45 | PSPPROXY_ADDR_BLOCKED_SMN_INIT_ALL_FEAT("X86Ccx1Core0", 0x18402ff0, 4, 0, PSPPROXY_ADDR_BLOCKED_FEAT_F_NO_X86_RELEASE), 46 | PSPPROXY_ADDR_BLOCKED_SMN_INIT_ALL_FEAT("X86Ccx1Core1", 0x18422ff0, 4, 0, PSPPROXY_ADDR_BLOCKED_FEAT_F_NO_X86_RELEASE), 47 | PSPPROXY_ADDR_BLOCKED_SMN_INIT_ALL_FEAT("X86Ccx1Core2", 0x18442ff0, 4, 0, PSPPROXY_ADDR_BLOCKED_FEAT_F_NO_X86_RELEASE), 48 | PSPPROXY_ADDR_BLOCKED_SMN_INIT_ALL_FEAT("X86Ccx1Core3", 0x18462ff0, 4, 0, PSPPROXY_ADDR_BLOCKED_FEAT_F_NO_X86_RELEASE) 49 | }; 50 | 51 | 52 | /** 53 | * CPU profile for an AMD CPU Ryzen 7 1800X 54 | */ 55 | static const PSPAMDCPUPROFILE g_AmdCpu_Ryzen7_1800X = 56 | { 57 | /** pszId */ 58 | "ryzen7-1800x", 59 | /** pszDesc */ 60 | "AMD Ryzen 7 1800X Eight Core CPU", 61 | /** enmMicroArch */ 62 | PSPEMUMICROARCH_ZEN, 63 | /** enmCpuSegment */ 64 | PSPEMUAMDCPUSEGMENT_RYZEN, 65 | /** cCcdsPerSocket */ 66 | 1, 67 | /** cSocketsMax */ 68 | 1, 69 | /** cCoresPerCcx */ 70 | 4, 71 | /** cCcxs */ 72 | 2, 73 | /** cCoresPerCcd */ 74 | 8, 75 | /** pPspProfile. */ 76 | &g_PspProfileZen, 77 | /** paAddrProxyBlockedSmn */ 78 | &g_aProxyBlockedSmn_AmdCpu_Ryzen7_1800x[0], 79 | /** cAddrProxyBlockedSmn */ 80 | ELEMENTS(g_aProxyBlockedSmn_AmdCpu_Ryzen7_1800x) 81 | }; 82 | 83 | #endif /* !PSPEMU_PROFILES_psp_amd_cpu_ryzen7_1800x_h */ 84 | 85 | -------------------------------------------------------------------------------- /profiles/amd-cpu-zen-synthetic.h: -------------------------------------------------------------------------------- 1 | /** @file 2 | * PSP Emulator - CPU profile for an synthetic AMD CPU used as the default. 3 | */ 4 | 5 | /* 6 | * Copyright (C) 2020 Alexander Eichner 7 | * 8 | * This program is free software: you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License as published by 10 | * the Free Software Foundation, version 3. 11 | * 12 | * This program is distributed in the hope that it will be useful, but 13 | * WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 | * General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with this program. If not, see . 19 | */ 20 | #ifndef PSPEMU_PROFILES_psp_amd_cpu_zen_synthetic_h 21 | #define PSPEMU_PROFILES_psp_amd_cpu_zen_synthetic_h 22 | 23 | 24 | /** 25 | * CPU profile for an AMD Zen based synthetic CPU. 26 | */ 27 | static const PSPAMDCPUPROFILE g_AmdCpu_Zen_Synthetic = 28 | { 29 | /** pszId */ 30 | "zen-synthetic", 31 | /** pszDesc */ 32 | "AMD Zen based Synthetic", 33 | /** enmMicroArch */ 34 | PSPEMUMICROARCH_ZEN, 35 | /** enmCpuSegment */ 36 | PSPEMUAMDCPUSEGMENT_RYZEN, 37 | /** cCcdsPerSocket */ 38 | 1, 39 | /** cSocketsMax */ 40 | 1, 41 | /** cCoresPerCcx */ 42 | 1, 43 | /** cCcxs */ 44 | 1, 45 | /** cCoresPerCcd */ 46 | 1, 47 | /** pPspProfile. */ 48 | &g_PspProfileZen, 49 | /** paAddrProxyBlockedSmn */ 50 | NULL, 51 | /** cAddrProxyBlockedSmn */ 52 | 0 53 | }; 54 | 55 | #endif /* !PSPEMU_PROFILES_psp_amd_cpu_zen_synthetic_h */ 56 | 57 | -------------------------------------------------------------------------------- /profiles/amd-psp-zen-2.h: -------------------------------------------------------------------------------- 1 | /** @file 2 | * PSP Emulator - Generic PSP profile for a Zen 2 CPU. 3 | */ 4 | 5 | /* 6 | * Copyright (C) 2020 Alexander Eichner 7 | * 8 | * This program is free software: you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License as published by 10 | * the Free Software Foundation, version 3. 11 | * 12 | * This program is distributed in the hope that it will be useful, but 13 | * WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 | * General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with this program. If not, see . 19 | */ 20 | #ifndef PSPEMU_PROFILES_psp_amd_zen_2_h 21 | #define PSPEMU_PROFILES_psp_amd_zen_2_h 22 | 23 | 24 | /** 25 | * Generic PSP profile for a standard Zen 2 CPU. 26 | */ 27 | static const PSPPROFILE g_PspProfileZen2 = 28 | { 29 | /** pszId */ 30 | "zen2-standard", 31 | /** pszDesc */ 32 | "PSP profile for a standard Zen 2 based CPU", 33 | /** enmMicroArch */ 34 | PSPEMUMICROARCH_ZEN2, 35 | /** u32PspOnChipBlVersion */ 36 | 0xbc0b0552, 37 | /** cbSram. */ 38 | 320 * _1K, 39 | /** PspAddrBrsp */ 40 | 0x4f000, 41 | /** PspAddrMmioVersion */ 42 | 0x03200048, 43 | /** PspAddrMmioSts */ 44 | 0x032000d8, 45 | /** SmnAddrFlashStart */ 46 | 0x44000000, 47 | /** paAddrProxyBlockedMmio */ 48 | &g_aProxyBlockedMmioStd[0], 49 | /** cAddrProxyBlockedMmio */ 50 | ELEMENTS(g_aProxyBlockedMmioStd), 51 | /** paAddrProxyBlockedSmn */ 52 | &g_aProxyBlockedSmnStd[0], 53 | /** cAddrProxyBlockedSmn */ 54 | ELEMENTS(g_aProxyBlockedSmnStd), 55 | /** paAddrProxyBlockedX86 */ 56 | &g_aProxyBlockedX86Std[0], 57 | /** cAddrProxyBlockedX86 */ 58 | ELEMENTS(g_aProxyBlockedX86Std) 59 | }; 60 | 61 | #endif /* !PSPEMU_PROFILES_psp_amd_zen_2_h */ 62 | 63 | -------------------------------------------------------------------------------- /profiles/amd-psp-zen-3.h: -------------------------------------------------------------------------------- 1 | /** @file 2 | * PSP Emulator - Generic PSP profile for a Zen 3 CPU. 3 | */ 4 | 5 | /* 6 | * Copyright (C) 2020 Alexander Eichner 7 | * 8 | * This program is free software: you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License as published by 10 | * the Free Software Foundation, version 3. 11 | * 12 | * This program is distributed in the hope that it will be useful, but 13 | * WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 | * General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with this program. If not, see . 19 | */ 20 | #ifndef PSPEMU_PROFILES_psp_amd_zen_3_h 21 | #define PSPEMU_PROFILES_psp_amd_zen_3_h 22 | 23 | 24 | /** 25 | * Generic PSP profile for a standard Zen 3 CPU. 26 | */ 27 | static const PSPPROFILE g_PspProfileZen3 = 28 | { 29 | /** pszId */ 30 | "zen3-standard", 31 | /** pszDesc */ 32 | "PSP profile for a standard Zen 3 based CPU", 33 | /** enmMicroArch */ 34 | PSPEMUMICROARCH_ZEN3, 35 | /** idPsp */ 36 | 0xbc0c0100, 37 | /** cbSram. */ 38 | 320 * _1K, 39 | /** PspAddrBrsp */ 40 | 0x4f000, 41 | /** PspAddrMmioVersion */ 42 | 0x03200048, 43 | /** PspAddrMmioSts */ 44 | 0x032000d8, 45 | /** SmnAddrFlashStart */ 46 | 0x44000000, 47 | /** paAddrProxyBlockedMmio */ 48 | &g_aProxyBlockedMmioStd[0], 49 | /** cAddrProxyBlockedMmio */ 50 | ELEMENTS(g_aProxyBlockedMmioStd), 51 | /** paAddrProxyBlockedSmn */ 52 | &g_aProxyBlockedSmnStd[0], 53 | /** cAddrProxyBlockedSmn */ 54 | ELEMENTS(g_aProxyBlockedSmnStd), 55 | /** paAddrProxyBlockedX86 */ 56 | &g_aProxyBlockedX86Std[0], 57 | /** cAddrProxyBlockedX86 */ 58 | ELEMENTS(g_aProxyBlockedX86Std) 59 | }; 60 | 61 | #endif /* !PSPEMU_PROFILES_psp_amd_zen_3_h */ 62 | 63 | -------------------------------------------------------------------------------- /profiles/amd-psp-zen-plus.h: -------------------------------------------------------------------------------- 1 | /** @file 2 | * PSP Emulator - Generic PSP profile for a Zen+ CPU. 3 | */ 4 | 5 | /* 6 | * Copyright (C) 2020 Alexander Eichner 7 | * 8 | * This program is free software: you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License as published by 10 | * the Free Software Foundation, version 3. 11 | * 12 | * This program is distributed in the hope that it will be useful, but 13 | * WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 | * General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with this program. If not, see . 19 | */ 20 | #ifndef PSPEMU_PROFILES_psp_amd_zen_plus_h 21 | #define PSPEMU_PROFILES_psp_amd_zen_plus_h 22 | 23 | 24 | /** 25 | * Generic PSP profile for a standard Zen+ CPU. 26 | */ 27 | static const PSPPROFILE g_PspProfileZenPlus = 28 | { 29 | /** pszId */ 30 | "zen+-standard", 31 | /** pszDesc */ 32 | "PSP profile for a standard Zen+ based CPU", 33 | /** enmMicroArch */ 34 | PSPEMUMICROARCH_ZEN_PLUS, 35 | /** u32PspOnChipBlVersion */ 36 | 0xbc090072, 37 | /** cbSram. */ 38 | _256K, 39 | /** PspAddrBrsp */ 40 | 0x3f000, 41 | /** PspAddrMmioVersion */ 42 | 0x0320004c, 43 | /** PspAddrMmioSts */ 44 | 0x032000f0, 45 | /** SmnAddrFlashStart */ 46 | 0x0a000000, 47 | /** paAddrProxyBlockedMmio */ 48 | &g_aProxyBlockedMmioStd[0], 49 | /** cAddrProxyBlockedMmio */ 50 | ELEMENTS(g_aProxyBlockedMmioStd), 51 | /** paAddrProxyBlockedSmn */ 52 | &g_aProxyBlockedSmnStd[0], 53 | /** cAddrProxyBlockedSmn */ 54 | ELEMENTS(g_aProxyBlockedSmnStd), 55 | /** paAddrProxyBlockedX86 */ 56 | &g_aProxyBlockedX86Std[0], 57 | /** cAddrProxyBlockedX86 */ 58 | ELEMENTS(g_aProxyBlockedX86Std) 59 | }; 60 | 61 | #endif /* !PSPEMU_PROFILES_psp_amd_zen_plus_h */ 62 | 63 | -------------------------------------------------------------------------------- /profiles/amd-psp-zen.h: -------------------------------------------------------------------------------- 1 | /** @file 2 | * PSP Emulator - Generic PSP profile for a Zen CPU. 3 | */ 4 | 5 | /* 6 | * Copyright (C) 2020 Alexander Eichner 7 | * 8 | * This program is free software: you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License as published by 10 | * the Free Software Foundation, version 3. 11 | * 12 | * This program is distributed in the hope that it will be useful, but 13 | * WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 | * General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with this program. If not, see . 19 | */ 20 | #ifndef PSPEMU_PROFILES_psp_amd_zen_h 21 | #define PSPEMU_PROFILES_psp_amd_zen_h 22 | 23 | 24 | /** 25 | * Generic PSP profile for a standard Zen CPU. 26 | */ 27 | static const PSPPROFILE g_PspProfileZen = 28 | { 29 | /** pszId */ 30 | "zen-standard", 31 | /** pszDesc */ 32 | "PSP profile for a standard Zen based CPU", 33 | /** enmMicroArch */ 34 | PSPEMUMICROARCH_ZEN, 35 | /** u32PspOnChipBlVersion */ 36 | 0xbc090072, 37 | /** cbSram. */ 38 | _256K, 39 | /** PspAddrBrsp */ 40 | 0x3f000, 41 | /** PspAddrMmioVersion */ 42 | 0x0320004c, 43 | /** PspAddrMmioSts */ 44 | 0x032000e8, 45 | /** SmnAddrFlashStart */ 46 | 0x0a000000, 47 | /** paAddrProxyBlockedMmio */ 48 | &g_aProxyBlockedMmioStd[0], 49 | /** cAddrProxyBlockedMmio */ 50 | ELEMENTS(g_aProxyBlockedMmioStd), 51 | /** paAddrProxyBlockedSmn */ 52 | &g_aProxyBlockedSmnStd[0], 53 | /** cAddrProxyBlockedSmn */ 54 | ELEMENTS(g_aProxyBlockedSmnStd), 55 | /** paAddrProxyBlockedX86 */ 56 | &g_aProxyBlockedX86Std[0], 57 | /** cAddrProxyBlockedX86 */ 58 | ELEMENTS(g_aProxyBlockedX86Std) 59 | }; 60 | 61 | #endif /* !PSPEMU_PROFILES_psp_amd_zen_h */ 62 | 63 | -------------------------------------------------------------------------------- /profiles/proxy-blocked-range-std.h: -------------------------------------------------------------------------------- 1 | /** @file 2 | * PSP Emulator - Generic proxy blocked address ranges. 3 | */ 4 | 5 | /* 6 | * Copyright (C) 2020 Alexander Eichner 7 | * 8 | * This program is free software: you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License as published by 10 | * the Free Software Foundation, version 3. 11 | * 12 | * This program is distributed in the hope that it will be useful, but 13 | * WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 | * General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with this program. If not, see . 19 | */ 20 | #ifndef PSPEMU_PROFILES_proxy_blocke_range_std_h 21 | #define PSPEMU_PROFILES_proxy_blocke_range_std_h 22 | 23 | 24 | /** 25 | * Standard MMIO ranges being blocked in proxy mode. 26 | */ 27 | static const PSPPROXYADDRBLOCKEDDESC g_aProxyBlockedMmioStd[] = 28 | { 29 | PSPPROXY_ADDR_BLOCKED_MMIO_INIT_WR("SomeReset?", 0x320001c, 4), 30 | PSPPROXY_ADDR_BLOCKED_MMIO_INIT_WR("SomeReset?", 0x3a0001c, 4) 31 | }; 32 | 33 | 34 | /** 35 | * Standard SMN ranges being blocked in proxy mode. 36 | */ 37 | static const PSPPROXYADDRBLOCKEDDESC g_aProxyBlockedSmnStd[] = 38 | { 39 | PSPPROXY_ADDR_BLOCKED_SMN_INIT_ALL_FEAT("Flash", 0x02dc4000, 32, 0, PSPPROXY_ADDR_BLOCKED_FEAT_F_SPI) 40 | }; 41 | 42 | 43 | /** 44 | * Standard X86 ranges being blocked in proxy mode. 45 | */ 46 | static const PSPPROXYADDRBLOCKEDDESC g_aProxyBlockedX86Std[] = 47 | { 48 | PSPPROXY_ADDR_BLOCKED_X86_INIT_ALL_FEAT("Uart", 0xfffdfc0003f8, 8, 0xff, PSPPROXY_ADDR_BLOCKED_FEAT_F_X86_UART) 49 | }; 50 | 51 | #endif /* !PSPEMU_PROFILES_proxy_blocke_range_std_h */ 52 | 53 | -------------------------------------------------------------------------------- /psp-dbg-hlp.c: -------------------------------------------------------------------------------- 1 | /** @file 2 | * PSP Emulator - Debug helper API. 3 | */ 4 | 5 | /* 6 | * Copyright (C) 2020 Alexander Eichner 7 | * 8 | * This program is free software: you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License as published by 10 | * the Free Software Foundation, version 3. 11 | * 12 | * This program is distributed in the hope that it will be useful, but 13 | * WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 | * General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with this program. If not, see . 19 | */ 20 | 21 | #include 22 | #include 23 | #include 24 | #include 25 | 26 | #include 27 | 28 | #include 29 | 30 | 31 | /** 32 | * Comand descriptor record. 33 | */ 34 | typedef struct PSPDBGHLPCMDREC 35 | { 36 | /** Pointer to the next record. */ 37 | struct PSPDBGHLPCMDREC *pNext; 38 | /** Pointer to the array of registered commands. */ 39 | PCDBGHLPCMD paCmds; 40 | /** Number of commands in the array. */ 41 | uint32_t cCmds; 42 | /** Opaque user data for the commands. */ 43 | void *pvUser; 44 | } PSPDBGHLPCMDREC; 45 | /** Pointer to a command descriptor record. */ 46 | typedef PSPDBGHLPCMDREC *PPSPDBGHLPCMDREC; 47 | /** Pointer to a const command descriptor record. */ 48 | typedef const PSPDBGHLPCMDREC *PCPSPDBGHLPCMDREC; 49 | 50 | 51 | /** 52 | * The debug helper module instance data. 53 | */ 54 | typedef struct PSPDBGHLPINT 55 | { 56 | /** Reference count. */ 57 | volatile uint32_t cRefs; 58 | /** Overall number of commands registered. */ 59 | uint32_t cCmds; 60 | /** Head to the list of registered commands. */ 61 | PPSPDBGHLPCMDREC pCmdsHead; 62 | } PSPDBGHLPINT; 63 | /** Pointer to the tracer instance data. */ 64 | typedef PSPDBGHLPINT *PPSPDBGHLPINT; 65 | /** Pointer to a const tracer instance. */ 66 | typedef const PSPDBGHLPINT *PCPSPDBGHLPINT; 67 | 68 | 69 | /** 70 | * Destroys the given debug helper module instance. 71 | * 72 | * @returns nothing. 73 | * @param pThis The debug helper module instance. 74 | */ 75 | static void pspEmuDbgHlpDestroy(PPSPDBGHLPINT pThis) 76 | { 77 | while (pThis->pCmdsHead) 78 | { 79 | PPSPDBGHLPCMDREC pCmdRec = pThis->pCmdsHead; 80 | pThis->pCmdsHead = pCmdRec->pNext; 81 | free(pCmdRec); 82 | } 83 | free(pThis); 84 | } 85 | 86 | 87 | /** 88 | * Tries to find the given command in the set of registered commands and returns the 89 | * descriptor or NULL if not found. 90 | * 91 | * @returns Pointer to the command descriptor or NULL if not found. 92 | * @param pThis The debug helper module instance. 93 | * @param pszCmd The command to look for. 94 | * @param ppvUser Where to store the opaque user data the command was registered with if found, optional. 95 | */ 96 | static PCDBGHLPCMD pspEmuDbgHlpCmdFind(PPSPDBGHLPINT pThis, const char *pszCmd, void **ppvUser) 97 | { 98 | PPSPDBGHLPCMDREC pCmdRecCur = pThis->pCmdsHead; 99 | while (pCmdRecCur) 100 | { 101 | for (uint32_t i = 0; i < pCmdRecCur->cCmds; i++) 102 | { 103 | if (!strcmp(pCmdRecCur->paCmds[i].pszCmd, pszCmd)) 104 | { 105 | if (ppvUser) 106 | *ppvUser = pCmdRecCur->pvUser; 107 | return &pCmdRecCur->paCmds[i]; 108 | } 109 | } 110 | 111 | pCmdRecCur = pCmdRecCur->pNext; 112 | } 113 | 114 | return NULL; /* Nothing found. */ 115 | } 116 | 117 | 118 | int PSPEmuDbgHlpCreate(PPSPDBGHLP phDbgHlp) 119 | { 120 | int rc = STS_INF_SUCCESS; 121 | PPSPDBGHLPINT pThis = (PPSPDBGHLPINT)calloc(1, sizeof(*pThis)); 122 | if (pThis) 123 | { 124 | pThis->cRefs = 1; 125 | pThis->cCmds = 0; 126 | pThis->pCmdsHead = NULL; 127 | *phDbgHlp = pThis; 128 | } 129 | else 130 | rc = STS_ERR_NO_MEMORY; 131 | 132 | return rc; 133 | } 134 | 135 | 136 | uint32_t PSPEmuDbgHlpRetain(PSPDBGHLP hDbgHlp) 137 | { 138 | PPSPDBGHLPINT pThis = hDbgHlp; 139 | 140 | return ++pThis->cRefs; /** @todo Atomics when going multi threaded. */ 141 | } 142 | 143 | 144 | uint32_t PSPEmuDbgHlpRelease(PSPDBGHLP hDbgHlp) 145 | { 146 | PPSPDBGHLPINT pThis = hDbgHlp; 147 | 148 | uint32_t cRefs = --pThis->cRefs; /** @todo Atomics when going multi threaded. */ 149 | if (!cRefs) 150 | pspEmuDbgHlpDestroy(pThis); 151 | 152 | return cRefs; 153 | } 154 | 155 | 156 | int PSPEmuDbgHlpCmdRegister(PSPDBGHLP hDbgHlp, PCDBGHLPCMD paCmds, uint32_t cCmds, void *pvUser) 157 | { 158 | PPSPDBGHLPINT pThis = hDbgHlp; 159 | 160 | /* No debugger, no command registration. */ 161 | if (!pThis) 162 | return STS_INF_SUCCESS; 163 | 164 | /* Check that there is no command existing with the same name already. */ 165 | for (uint32_t i = 0; i < cCmds; i++) 166 | { 167 | if (pspEmuDbgHlpCmdFind(pThis, paCmds[i].pszCmd, NULL /*ppvUser*/) != NULL) 168 | return STS_ERR_INVALID_PARAMETER; /** @todo New status code. */ 169 | } 170 | 171 | int rc = STS_INF_SUCCESS; 172 | PPSPDBGHLPCMDREC pCmdRec = (PPSPDBGHLPCMDREC)calloc(1, sizeof(*pCmdRec)); 173 | if (pCmdRec) 174 | { 175 | pCmdRec->paCmds = paCmds; 176 | pCmdRec->cCmds = cCmds; 177 | pCmdRec->pvUser = pvUser; 178 | pCmdRec->pNext = pThis->pCmdsHead; 179 | pThis->pCmdsHead = pCmdRec; 180 | pThis->cCmds += cCmds; 181 | } 182 | else 183 | rc = STS_ERR_NO_MEMORY; 184 | 185 | return rc; 186 | } 187 | 188 | 189 | int PSPEmuDbgHlpCmdDeregister(PSPDBGHLP hDbgHlp, PCDBGHLPCMD paCmds) 190 | { 191 | return STS_ERR_GENERAL_ERROR; /** @todo */ 192 | } 193 | 194 | 195 | int PSPEmuDbgHlpCmdExec(PSPDBGHLP hDbgHlp, const char *pszCmd, const char *pszArgs, PCPSPDBGOUTHLP pOutHlp) 196 | { 197 | PPSPDBGHLPINT pThis = hDbgHlp; 198 | void *pvCmdUser = NULL; 199 | PCDBGHLPCMD pCmd = pspEmuDbgHlpCmdFind(pThis, pszCmd, &pvCmdUser); 200 | int rc = STS_ERR_NOT_FOUND; 201 | if (pCmd) 202 | rc = pCmd->pfnCmd(pThis, pOutHlp, pszArgs, pvCmdUser); 203 | 204 | return rc; 205 | } 206 | 207 | 208 | uint32_t PSPEmuDbgHlpCmdGetCount(PSPDBGHLP hDbgHlp) 209 | { 210 | PPSPDBGHLPINT pThis = hDbgHlp; 211 | 212 | return pThis->cCmds; 213 | } 214 | 215 | 216 | int PSPEmuDbgHlpCmdQueryDesc(PSPDBGHLP hDbgHlp, PDBGHLPCMD paCmds, uint32_t cCmds, uint32_t *pcCmds) 217 | { 218 | PPSPDBGHLPINT pThis = hDbgHlp; 219 | 220 | if (!paCmds || !cCmds) 221 | return STS_ERR_INVALID_PARAMETER; 222 | 223 | if (pcCmds) 224 | *pcCmds = MIN(pThis->cCmds, cCmds); 225 | 226 | PPSPDBGHLPCMDREC pRecCur = pThis->pCmdsHead; 227 | while (pRecCur) 228 | { 229 | size_t cThisCopy = MIN(cCmds, pRecCur->cCmds); 230 | memcpy(&paCmds[0], &pRecCur->paCmds[0], cThisCopy * sizeof(*paCmds)); 231 | pRecCur = pRecCur->pNext; 232 | } 233 | 234 | return STS_INF_SUCCESS; 235 | } 236 | 237 | -------------------------------------------------------------------------------- /psp-dev-acpi.c: -------------------------------------------------------------------------------- 1 | /** @file 2 | * PSP Emulator - ACPI PM interface accessible through x86 MMIO. 3 | */ 4 | 5 | /* 6 | * Copyright (C) 2020 Alexander Eichner 7 | * 8 | * This program is free software: you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License as published by 10 | * the Free Software Foundation, version 3. 11 | * 12 | * This program is distributed in the hope that it will be useful, but 13 | * WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 | * General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with this program. If not, see . 19 | */ 20 | 21 | #include 22 | 23 | #include 24 | 25 | #include 26 | #include 27 | 28 | 29 | /** 30 | * ACPI device instance data. 31 | */ 32 | typedef struct PSPDEVACPI 33 | { 34 | /** Pointer to the owning device instance. */ 35 | PPSPDEV pDev; 36 | /** MMIO region handle. */ 37 | PSPIOMREGIONHANDLE hMmioX86; 38 | } PSPDEVACPI; 39 | /** Pointer to the device instance data. */ 40 | typedef PSPDEVACPI *PPSPDEVACPI; 41 | 42 | static void pspDevX86AcpiRead(X86PADDR offMmio, size_t cbRead, void *pvVal, void *pvUser) 43 | { 44 | PPSPDEVACPI pThis = (PPSPDEVACPI)pvUser; 45 | 46 | if (cbRead != sizeof(uint16_t)) 47 | { 48 | PSPEmuTraceEvtAddString(NULL, PSPTRACEEVTSEVERITY_ERROR, PSPTRACEEVTORIGIN_ACPI, 49 | "Invalid register read size %u cbRead=%zu", offMmio, cbRead); 50 | return; 51 | } 52 | 53 | uint16_t *pu16Val = (uint16_t *)pvVal; 54 | switch (pThis->pDev->pCfg->enmAcpiState) 55 | { 56 | case PSPEMUACPISTATE_S0: 57 | *pu16Val = (0 & 0x7) << 10; 58 | break; 59 | case PSPEMUACPISTATE_S1: 60 | *pu16Val = (1 & 0x7) << 10; 61 | break; 62 | case PSPEMUACPISTATE_S2: 63 | *pu16Val = (2 & 0x7) << 10; 64 | break; 65 | case PSPEMUACPISTATE_S3: 66 | *pu16Val = (3 & 0x7) << 10; 67 | break; 68 | case PSPEMUACPISTATE_S4: 69 | *pu16Val = (4 & 0x7) << 10; 70 | break; 71 | case PSPEMUACPISTATE_S5: 72 | *pu16Val = (5 & 0x7) << 10; 73 | break; 74 | default: 75 | PSPEmuTraceEvtAddString(NULL, PSPTRACEEVTSEVERITY_ERROR, PSPTRACEEVTORIGIN_ACPI, 76 | "Invalid ACPI state configured: %d", pThis->pDev->pCfg->enmAcpiState); 77 | } 78 | } 79 | 80 | static int pspDevAcpiInit(PPSPDEV pDev) 81 | { 82 | PPSPDEVACPI pThis = (PPSPDEVACPI)&pDev->abInstance[0]; 83 | 84 | pThis->pDev = pDev; 85 | 86 | /* Register MMIO ranges. */ 87 | int rc = PSPEmuIoMgrX86MmioRegister(pDev->hIoMgr, 0xfed80804, 2, 88 | pspDevX86AcpiRead, NULL, pThis, 89 | "AcpiPmCtrl", &pThis->hMmioX86); 90 | return rc; 91 | } 92 | 93 | 94 | static void pspDevAcpiDestruct(PPSPDEV pDev) 95 | { 96 | /* Nothing to do so far. */ 97 | } 98 | 99 | 100 | /** 101 | * Device registration structure. 102 | */ 103 | const PSPDEVREG g_DevRegAcpi = 104 | { 105 | /** pszName */ 106 | "acpi", 107 | /** pszDesc */ 108 | "ACPI related interfaces", 109 | /** cbInstance */ 110 | sizeof(PSPDEVACPI), 111 | /** pfnInit */ 112 | pspDevAcpiInit, 113 | /** pfnDestruct */ 114 | pspDevAcpiDestruct, 115 | /** pfnReset */ 116 | NULL 117 | }; 118 | 119 | -------------------------------------------------------------------------------- /psp-dev-flash.c: -------------------------------------------------------------------------------- 1 | /** @file 2 | * PSP Emulator - Flash ROM device attached to SMN. 3 | */ 4 | 5 | /* 6 | * Copyright (C) 2020 Alexander Eichner 7 | * 8 | * This program is free software: you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License as published by 10 | * the Free Software Foundation, version 3. 11 | * 12 | * This program is distributed in the hope that it will be useful, but 13 | * WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 | * General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with this program. If not, see . 19 | */ 20 | #include 21 | #include 22 | #include 23 | 24 | #include 25 | 26 | #include 27 | 28 | #include 29 | 30 | 31 | /** 32 | * Flash device instance data. 33 | */ 34 | typedef struct PSPDEVFLASH 35 | { 36 | /** Device instance pointer. */ 37 | PPSPDEV pDev; 38 | /** SMN region handle. */ 39 | PSPIOMREGIONHANDLE hSmn; 40 | /** SMN region handle to the control interface living at 0x2dc4000. */ 41 | PSPIOMREGIONHANDLE hSmnCtrl; 42 | /** SMN region handle to the bank control interface living at 0x2dc405c for Zen2+ systems. */ 43 | PSPIOMREGIONHANDLE hSmnBankCtrl; 44 | /** The currently selected flash bank (16MB chunks). */ 45 | uint32_t uBank; 46 | /** SPI flash trace file if configured. */ 47 | FILE *pSpiFlashTrace; 48 | /** Start timestamp. */ 49 | uint64_t tsStart; 50 | /** Last accessed offset. */ 51 | SMNADDR offAccLast; 52 | /** Packet ID. */ 53 | uint64_t idPacket; 54 | } PSPDEVFLASH; 55 | /** Pointer to the device instance data. */ 56 | typedef PSPDEVFLASH *PPSPDEVFLASH; 57 | 58 | 59 | static uint32_t pspDevFlashGetBankedOffset(PPSPDEVFLASH pThis, SMNADDR offSmn) 60 | { 61 | if (pThis->uBank * 16 * _1M < pThis->pDev->pCfg->cbFlashRom) 62 | return offSmn + pThis->uBank * 16 * _1M; 63 | 64 | return offSmn; 65 | } 66 | 67 | 68 | static void *pspDevFlashGetBankedStart(PPSPDEVFLASH pThis, SMNADDR offSmn) 69 | { 70 | 71 | return (uint8_t *)pThis->pDev->pCfg->pvFlashRom + pspDevFlashGetBankedOffset(pThis, offSmn); 72 | } 73 | 74 | 75 | static void pspDevFlashRead(SMNADDR offSmn, size_t cbRead, void *pvDst, void *pvUser) 76 | { 77 | PPSPDEVFLASH pThis = (PPSPDEVFLASH)pvUser; 78 | const uint8_t *pbFlash = (const uint8_t *)pspDevFlashGetBankedStart(pThis, offSmn); 79 | 80 | if (offSmn + cbRead <= 16 * _1M) 81 | memcpy(pvDst, pbFlash, cbRead); 82 | else 83 | printf("%s: ATTEMPTED out of bounds read from offSmn=%#x cbRead=%zu -> IGNORED\n", __FUNCTION__, offSmn, cbRead); 84 | 85 | /* Log the access if enabled. */ 86 | if (pThis->pSpiFlashTrace) 87 | { 88 | /* Generate a new packet ID and read command if the last access isn't adjacent to this one. */ 89 | uint32_t offFlash = pspDevFlashGetBankedOffset(pThis, offSmn); 90 | uint64_t tsCmd = OSTimeTsGetNano() - pThis->tsStart; 91 | uint64_t tsCmdSec = tsCmd / (1000 * 1000 * 1000); 92 | uint64_t tsCmdNs = tsCmd % (1000 * 1000 * 1000); 93 | 94 | if (offSmn != pThis->offAccLast) 95 | { 96 | pThis->idPacket++; 97 | int cchWritten = fprintf(pThis->pSpiFlashTrace, "%llu.%llu000000,%llu,0x03,0xFF\n", 98 | tsCmdSec, tsCmdNs++, pThis->idPacket); 99 | cchWritten = fprintf(pThis->pSpiFlashTrace, "%llu.%llu000000,%llu,0x%02x,0xFF\n", 100 | tsCmdSec, tsCmdNs++, pThis->idPacket, (offFlash >> 16) & 0xff); 101 | cchWritten = fprintf(pThis->pSpiFlashTrace, "%llu.%llu000000,%llu,0x%02x,0xFF\n", 102 | tsCmdSec, tsCmdNs++, pThis->idPacket, (offFlash >> 8) & 0xff); 103 | cchWritten = fprintf(pThis->pSpiFlashTrace, "%llu.%llu000000,%llu,0x%02x,0xFF\n", 104 | tsCmdSec, tsCmdNs++, pThis->idPacket, offFlash & 0xff); 105 | } 106 | 107 | pThis->offAccLast = offSmn + cbRead; 108 | while (cbRead) 109 | { 110 | int cchWritten = fprintf(pThis->pSpiFlashTrace, "%llu.%llu000000,%llu,0x00,0x%02x\n", 111 | tsCmdSec, tsCmdNs++, pThis->idPacket, *pbFlash); 112 | pbFlash++; 113 | cbRead--; 114 | } 115 | fflush(pThis->pSpiFlashTrace); 116 | } 117 | } 118 | 119 | 120 | static void pspDevFlashWrite(SMNADDR offSmn, size_t cbWrite, const void *pvVal, void *pvUser) 121 | { 122 | PPSPDEVFLASH pThis = (PPSPDEVFLASH)pvUser; 123 | 124 | if (offSmn + cbWrite <= 16 * _1M) 125 | memcpy(pspDevFlashGetBankedStart(pThis, offSmn), pvVal, cbWrite); 126 | else 127 | printf("%s: ATTEMPTED out of bounds write from offSmn=%#x cbWrite=%zu -> IGNORED\n", __FUNCTION__, offSmn, cbWrite); 128 | } 129 | 130 | 131 | static void pspDevFlashSpiCtrlRead(SMNADDR offSmn, size_t cbRead, void *pvDst, void *pvUser) 132 | { 133 | PPSPDEVFLASH pThis = (PPSPDEVFLASH)pvUser; 134 | 135 | printf("%s: ATTEMPTED read from offSmn=%#x cbRead=%zu -> return all 0\n", __FUNCTION__, offSmn, cbRead); 136 | memset(pvDst, 0, cbRead); 137 | } 138 | 139 | 140 | static void pspDevFlashSpiCtrlWrite(SMNADDR offSmn, size_t cbWrite, const void *pvVal, void *pvUser) 141 | { 142 | PPSPDEVFLASH pThis = (PPSPDEVFLASH)pvUser; 143 | 144 | printf("%s: ATTEMPTED write access to offSmn=%#x cbWrite=%zu -> IGNORED\n", __FUNCTION__, offSmn, cbWrite); 145 | } 146 | 147 | 148 | static void pspDevFlashSpiBankCtrlRead(SMNADDR offSmn, size_t cbRead, void *pvDst, void *pvUser) 149 | { 150 | PPSPDEVFLASH pThis = (PPSPDEVFLASH)pvUser; 151 | 152 | *(uint32_t *)pvDst = pThis->uBank; 153 | } 154 | 155 | 156 | static void pspDevFlashSpiBankCtrlWrite(SMNADDR offSmn, size_t cbWrite, const void *pvVal, void *pvUser) 157 | { 158 | PPSPDEVFLASH pThis = (PPSPDEVFLASH)pvUser; 159 | 160 | pThis->uBank = *(uint32_t *)pvVal & 0xff; 161 | } 162 | 163 | 164 | static int pspDevFlashInit(PPSPDEV pDev) 165 | { 166 | PPSPDEVFLASH pThis = (PPSPDEVFLASH)&pDev->abInstance[0]; 167 | 168 | pThis->pDev = pDev; 169 | pThis->uBank = 0; 170 | pThis->offAccLast = UINT32_MAX - 1; 171 | pThis->idPacket = 0; 172 | 173 | SMNADDR SmnAddrFlash = pDev->pCfg->pPspProfile->SmnAddrFlashStart; 174 | int rc = PSPEmuIoMgrSmnRegister(pDev->hIoMgr, SmnAddrFlash, 16 * _1M, 175 | pspDevFlashRead, pspDevFlashWrite, pThis, 176 | "SPI flash", &pThis->hSmn); 177 | if (!rc) 178 | rc = PSPEmuIoMgrSmnRegister(pDev->hIoMgr, 0x2dc4000, 0x20, 179 | pspDevFlashSpiCtrlRead, pspDevFlashSpiCtrlWrite, pThis, 180 | "SPI Control", &pThis->hSmnCtrl); 181 | if ( !rc 182 | && pDev->pCfg->pPspProfile->enmMicroArch >= PSPEMUMICROARCH_ZEN2) 183 | rc = PSPEmuIoMgrSmnRegister(pDev->hIoMgr, 0x2dc405c, 4, 184 | pspDevFlashSpiBankCtrlRead, pspDevFlashSpiBankCtrlWrite, pThis, 185 | "SPI Bank Ctrl", &pThis->hSmnBankCtrl); 186 | if ( !rc 187 | && pDev->pCfg->pszSpiFlashTrace) 188 | { 189 | pThis->pSpiFlashTrace = fopen(pDev->pCfg->pszSpiFlashTrace, "wb"); 190 | if (pThis->pSpiFlashTrace) 191 | { 192 | /* Write the header. */ 193 | const char szHdr[] = "Time [s],Packet ID,MOSI,MISO\n"; 194 | size_t cWritten = fwrite(&szHdr[0], sizeof(szHdr) - 1, 1, pThis->pSpiFlashTrace); 195 | if (cWritten != 1) 196 | rc = -1; 197 | pThis->tsStart = OSTimeTsGetNano(); 198 | } 199 | else 200 | rc = -1; 201 | } 202 | 203 | return rc; 204 | } 205 | 206 | 207 | static void pspDevFlashDestruct(PPSPDEV pDev) 208 | { 209 | PPSPDEVFLASH pThis = (PPSPDEVFLASH)&pDev->abInstance[0]; 210 | 211 | if (pThis->pSpiFlashTrace) 212 | fclose(pThis->pSpiFlashTrace); 213 | } 214 | 215 | 216 | /** 217 | * Device registration structure. 218 | */ 219 | const PSPDEVREG g_DevRegFlash = 220 | { 221 | /** pszName */ 222 | "flash", 223 | /** pszDesc */ 224 | "Flash device", 225 | /** cbInstance */ 226 | sizeof(PSPDEVFLASH), 227 | /** pfnInit */ 228 | pspDevFlashInit, 229 | /** pfnDestruct */ 230 | pspDevFlashDestruct, 231 | /** pfnReset */ 232 | NULL 233 | }; 234 | 235 | -------------------------------------------------------------------------------- /psp-dev-fuse.c: -------------------------------------------------------------------------------- 1 | /** @file 2 | * PSP Emulator - Some sort of fuse information which is mapped into MMIO and SMN space. 3 | */ 4 | 5 | /* 6 | * Copyright (C) 2020 Alexander Eichner 7 | * 8 | * This program is free software: you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License as published by 10 | * the Free Software Foundation, version 3. 11 | * 12 | * This program is distributed in the hope that it will be useful, but 13 | * WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 | * General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with this program. If not, see . 19 | */ 20 | 21 | #include 22 | 23 | #include 24 | 25 | #include 26 | 27 | 28 | /** 29 | * Fuse device instance data. 30 | */ 31 | typedef struct PSPDEVFUSE 32 | { 33 | /** Pointer to the owning device instance. */ 34 | PPSPDEV pDev; 35 | /** MMIO region handle. */ 36 | PSPIOMREGIONHANDLE hMmio; 37 | /** SMN region handle. */ 38 | PSPIOMREGIONHANDLE hSmn; 39 | /** MMIO region handle for some key size fuse on Zen2. */ 40 | PSPIOMREGIONHANDLE hMmioKeySz; 41 | } PSPDEVFUSE; 42 | /** Pointer to the device instance data. */ 43 | typedef PSPDEVFUSE *PPSPDEVFUSE; 44 | 45 | 46 | static void pspDevFuseRegRead(uint32_t offReg, size_t cbRead, void *pvVal, void *pvUser) 47 | { 48 | PPSPDEVFUSE pThis = (PPSPDEVFUSE)pvUser; 49 | bool fPspDbgMode = pThis->pDev->pCfg->fPspDbgMode; 50 | 51 | switch (offReg) 52 | { 53 | case 0: 54 | /* 55 | * The on chip bootloader waits in on_chip_bl_main() until bit 8 is set 56 | * and this is also read from SMN and expected to match whats read from MMIO 57 | * in psp_verify_equal_fuse_info_on_all_ccx_hang_on_mismatch(). 58 | */ 59 | *(uint32_t *)pvVal = 0x1a060900 | (fPspDbgMode ? BIT(10) : 0); /* Value read from a real EPYC system. */ 60 | break; 61 | } 62 | } 63 | 64 | static void pspDevFuseMmioRead(PSPADDR offMmio, size_t cbRead, void *pvVal, void *pvUser) 65 | { 66 | pspDevFuseRegRead(offMmio, cbRead, pvVal, pvUser); 67 | } 68 | 69 | 70 | static void pspDevFuseSmnRead(SMNADDR offSmn, size_t cbRead, void *pvVal, void *pvUser) 71 | { 72 | pspDevFuseRegRead(offSmn, cbRead, pvVal, pvUser); 73 | } 74 | 75 | 76 | static void pspDevFuseKeySzMmioRead(PSPADDR offMmio, size_t cbRead, void *pvVal, void *pvUser) 77 | { 78 | if (cbRead != sizeof(uint32_t)) 79 | { 80 | printf("%s: offMmio=%#x cbRead=%zu -> Unsupported access width\n", __FUNCTION__, offMmio, cbRead); 81 | return; 82 | } 83 | 84 | /* Zen2 uses 4096 bit modulus and the key size is determined from this register. */ 85 | *(uint32_t *)pvVal = BIT(8) | BIT(9); 86 | } 87 | 88 | 89 | static int pspDevMmioFuseInit(PPSPDEV pDev) 90 | { 91 | PPSPDEVFUSE pThis = (PPSPDEVFUSE)&pDev->abInstance[0]; 92 | 93 | pThis->pDev = pDev; 94 | 95 | /* Register MMIO ranges. */ 96 | int rc = PSPEmuIoMgrMmioRegister(pDev->hIoMgr, 0x03010104, 4, 97 | pspDevFuseMmioRead, NULL, pThis, 98 | "Fuse1", &pThis->hMmio); 99 | if (!rc) 100 | rc = PSPEmuIoMgrSmnRegister(pDev->hIoMgr, 0x03810104, 4, 101 | pspDevFuseSmnRead, NULL, pThis, 102 | "Fuse1", &pThis->hSmn); 103 | if ( !rc 104 | && pDev->pCfg->pPspProfile->enmMicroArch >= PSPEMUMICROARCH_ZEN2) 105 | rc = PSPEmuIoMgrMmioRegister(pDev->hIoMgr, 0x3200050, 4, 106 | pspDevFuseKeySzMmioRead, NULL, pThis, 107 | "FuseKeySz", &pThis->hMmioKeySz); 108 | return rc; 109 | } 110 | 111 | 112 | static void pspDevMmioFuseDestruct(PPSPDEV pDev) 113 | { 114 | /* Nothing to do so far. */ 115 | } 116 | 117 | 118 | /** 119 | * Device registration structure. 120 | */ 121 | const PSPDEVREG g_DevRegFuse = 122 | { 123 | /** pszName */ 124 | "fuse", 125 | /** pszDesc */ 126 | "Fuse device mapped into MMIO and SMN space", 127 | /** cbInstance */ 128 | sizeof(PSPDEVFUSE), 129 | /** pfnInit */ 130 | pspDevMmioFuseInit, 131 | /** pfnDestruct */ 132 | pspDevMmioFuseDestruct, 133 | /** pfnReset */ 134 | NULL 135 | }; 136 | 137 | -------------------------------------------------------------------------------- /psp-dev-gpio.c: -------------------------------------------------------------------------------- 1 | /** @file 2 | * PSP Emulator - GPIO registers as obtained from AMD PPR. 3 | */ 4 | 5 | /* 6 | * Copyright (C) 2020 Alexander Eichner 7 | * 8 | * This program is free software: you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License as published by 10 | * the Free Software Foundation, version 3. 11 | * 12 | * This program is distributed in the hope that it will be useful, but 13 | * WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 | * General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with this program. If not, see . 19 | */ 20 | 21 | #include 22 | 23 | #include 24 | 25 | #include 26 | #include 27 | 28 | 29 | /** Number of register per GPIO bank. */ 30 | #define PSPEMU_GPIO_DEV_REGS_PER_BANK 64 31 | 32 | /** Pointer to the device instance data. */ 33 | typedef struct PSPDEVGPIO *PPSPDEVGPIO; 34 | 35 | 36 | /** 37 | * Single GPIO bank with values. 38 | */ 39 | typedef struct GPIOBANK 40 | { 41 | /** Pointer to the owning device. */ 42 | PPSPDEVGPIO pDev; 43 | /** MMIO region handle for this bank. */ 44 | PSPIOMREGIONHANDLE hMmioX86; 45 | /** The bank number. */ 46 | uint32_t idBank; 47 | /** The GPIO register values - 64 registers per bank. */ 48 | uint32_t aGpioRegs[PSPEMU_GPIO_DEV_REGS_PER_BANK]; 49 | } GPIOBANK; 50 | /** Pointer to a GPIO bank. */ 51 | typedef GPIOBANK *PGPIOBANK; 52 | /** Pointer to a const bank. */ 53 | typedef const GPIOBANK *PCGPIOBANK; 54 | 55 | 56 | /** 57 | * GPIO device instance data. 58 | */ 59 | typedef struct PSPDEVGPIO 60 | { 61 | /** Pointer to the owning device instance. */ 62 | PPSPDEV pDev; 63 | /** The GPIO banks. */ 64 | GPIOBANK aBanks[4]; 65 | } PSPDEVGPIO; 66 | 67 | 68 | static const char *s_apszGpioBankDesc[] = 69 | { 70 | "GPIO Bank 0", 71 | "GPIO Bank 1", 72 | "GPIO Bank 2", 73 | "GPIO Bank 3" 74 | }; 75 | 76 | 77 | static void pspDevX86GpioBankRead(X86PADDR offMmio, size_t cbRead, void *pvVal, void *pvUser) 78 | { 79 | PCGPIOBANK pBank = (PCGPIOBANK)pvUser; 80 | 81 | if (cbRead != sizeof(uint32_t)) 82 | { 83 | PSPEmuTraceEvtAddString(NULL, PSPTRACEEVTSEVERITY_ERROR, PSPTRACEEVTORIGIN_GPIO, 84 | "Invalid register read size %u cbRead=%zu", offMmio, cbRead); 85 | return; 86 | } 87 | 88 | *(uint32_t *)pvVal = pBank->aGpioRegs[offMmio / sizeof(uint32_t)]; 89 | } 90 | 91 | 92 | static void pspDevX86GpioBankWrite(X86PADDR offMmio, size_t cbWrite, const void *pvVal, void *pvUser) 93 | { 94 | PGPIOBANK pBank = (PGPIOBANK)pvUser; 95 | 96 | if (cbWrite != sizeof(uint32_t)) 97 | { 98 | PSPEmuTraceEvtAddString(NULL, PSPTRACEEVTSEVERITY_ERROR, PSPTRACEEVTORIGIN_GPIO, 99 | "Invalid register write size %u cbWrite=%zu", offMmio, cbWrite); 100 | return; 101 | } 102 | 103 | pBank->aGpioRegs[offMmio / sizeof(uint32_t)] = *(const uint32_t *)pvVal; 104 | } 105 | 106 | 107 | static int pspDevGpioInit(PPSPDEV pDev) 108 | { 109 | int rc = 0; 110 | PPSPDEVGPIO pThis = (PPSPDEVGPIO)&pDev->abInstance[0]; 111 | 112 | pThis->pDev = pDev; 113 | 114 | size_t cbBankMmio = PSPEMU_GPIO_DEV_REGS_PER_BANK * sizeof(uint32_t); 115 | for (uint32_t i = 0; i < ELEMENTS(pThis->aBanks) && !rc; i++) 116 | { 117 | PGPIOBANK pBank = &pThis->aBanks[i]; 118 | 119 | pBank->pDev = pThis; 120 | pBank->idBank = i; 121 | 122 | rc = PSPEmuIoMgrX86MmioRegister(pDev->hIoMgr, 0xfed81500 + i * cbBankMmio, cbBankMmio, 123 | pspDevX86GpioBankRead, pspDevX86GpioBankWrite, pBank, 124 | s_apszGpioBankDesc[i], &pBank->hMmioX86); 125 | } 126 | 127 | return rc; 128 | } 129 | 130 | 131 | static void pspDevGpioDestruct(PPSPDEV pDev) 132 | { 133 | /* Nothing to do so far. */ 134 | } 135 | 136 | 137 | /** 138 | * Device registration structure. 139 | */ 140 | const PSPDEVREG g_DevRegGpio = 141 | { 142 | /** pszName */ 143 | "gpio", 144 | /** pszDesc */ 145 | "GPIO register banks", 146 | /** cbInstance */ 147 | sizeof(PSPDEVGPIO), 148 | /** pfnInit */ 149 | pspDevGpioInit, 150 | /** pfnDestruct */ 151 | pspDevGpioDestruct, 152 | /** pfnReset */ 153 | NULL 154 | }; 155 | 156 | -------------------------------------------------------------------------------- /psp-dev-iomux.c: -------------------------------------------------------------------------------- 1 | /** @file 2 | * PSP Emulator - IOMUX registers as obtained from AMD PPR. 3 | */ 4 | 5 | /* 6 | * Copyright (C) 2020 Alexander Eichner 7 | * 8 | * This program is free software: you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License as published by 10 | * the Free Software Foundation, version 3. 11 | * 12 | * This program is distributed in the hope that it will be useful, but 13 | * WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 | * General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with this program. If not, see . 19 | */ 20 | 21 | #include 22 | 23 | #include 24 | 25 | #include 26 | #include 27 | 28 | 29 | /** 30 | * I/O MUX device instance data. 31 | */ 32 | typedef struct PSPDEVIOMUX 33 | { 34 | /** Pointer to the owning device instance. */ 35 | PPSPDEV pDev; 36 | /** MMIO region handle. */ 37 | PSPIOMREGIONHANDLE hMmioX86; 38 | /** I/O mux register values. */ 39 | uint8_t aIoMuxRegs[145]; 40 | } PSPDEVIOMUX; 41 | /** Pointer to the device instance data. */ 42 | typedef struct PSPDEVIOMUX *PPSPDEVIOMUX; 43 | 44 | 45 | static void pspDevX86IoMuxRead(X86PADDR offMmio, size_t cbRead, void *pvVal, void *pvUser) 46 | { 47 | PPSPDEVIOMUX pThis = (PPSPDEVIOMUX)pvUser; 48 | 49 | if (cbRead != sizeof(uint8_t)) 50 | { 51 | PSPEmuTraceEvtAddString(NULL, PSPTRACEEVTSEVERITY_ERROR, PSPTRACEEVTORIGIN_IOMUX, 52 | "Invalid register read size %u cbRead=%zu", offMmio, cbRead); 53 | return; 54 | } 55 | 56 | *(uint8_t *)pvVal = pThis->aIoMuxRegs[offMmio]; 57 | } 58 | 59 | 60 | static void pspDevX86IoMuxWrite(X86PADDR offMmio, size_t cbWrite, const void *pvVal, void *pvUser) 61 | { 62 | PPSPDEVIOMUX pThis = (PPSPDEVIOMUX)pvUser; 63 | 64 | if (cbWrite != sizeof(uint8_t)) 65 | { 66 | PSPEmuTraceEvtAddString(NULL, PSPTRACEEVTSEVERITY_ERROR, PSPTRACEEVTORIGIN_IOMUX, 67 | "Invalid register write size %u cbWrite=%zu", offMmio, cbWrite); 68 | return; 69 | } 70 | 71 | pThis->aIoMuxRegs[offMmio] = *(const uint8_t *)pvVal; 72 | } 73 | 74 | 75 | static int pspDevIoMuxInit(PPSPDEV pDev) 76 | { 77 | PPSPDEVIOMUX pThis = (PPSPDEVIOMUX)&pDev->abInstance[0]; 78 | 79 | pThis->pDev = pDev; 80 | 81 | return PSPEmuIoMgrX86MmioRegister(pDev->hIoMgr, 0xfed80d00, sizeof(pThis->aIoMuxRegs), 82 | pspDevX86IoMuxRead, pspDevX86IoMuxWrite, pThis, 83 | "I/O MUX", &pThis->hMmioX86); 84 | } 85 | 86 | 87 | static void pspDevIoMuxDestruct(PPSPDEV pDev) 88 | { 89 | /* Nothing to do so far. */ 90 | } 91 | 92 | 93 | /** 94 | * Device registration structure. 95 | */ 96 | const PSPDEVREG g_DevRegIoMux = 97 | { 98 | /** pszName */ 99 | "iomux", 100 | /** pszDesc */ 101 | "I/O MUX registers", 102 | /** cbInstance */ 103 | sizeof(PSPDEVIOMUX), 104 | /** pfnInit */ 105 | pspDevIoMuxInit, 106 | /** pfnDestruct */ 107 | pspDevIoMuxDestruct, 108 | /** pfnReset */ 109 | NULL 110 | }; 111 | 112 | -------------------------------------------------------------------------------- /psp-dev-lpc.c: -------------------------------------------------------------------------------- 1 | /** @file 2 | * PSP Emulator - LPC host bridge device implementation. 3 | */ 4 | 5 | /* 6 | * Copyright (C) 2020 Alexander Eichner 7 | * 8 | * This program is free software: you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License as published by 10 | * the Free Software Foundation, version 3. 11 | * 12 | * This program is distributed in the hope that it will be useful, but 13 | * WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 | * General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with this program. If not, see . 19 | */ 20 | 21 | #include 22 | 23 | #include 24 | 25 | #include 26 | #include 27 | 28 | 29 | /** 30 | * LPC device instance data. 31 | */ 32 | typedef struct PSPDEVLPC 33 | { 34 | /** Pointer to the owning device instance. */ 35 | PPSPDEV pDev; 36 | /** MMIO region handle for the SuperIO access port. */ 37 | PSPIOMREGIONHANDLE hMmioX86; 38 | /** MMIO region handle for the SuperIO access port (0x2e/0x2f). */ 39 | PSPIOMREGIONHANDLE hMmioX862e; 40 | } PSPDEVLPC; 41 | /** Pointer to an LPC device instance. */ 42 | typedef PSPDEVLPC *PPSPDEVLPC; 43 | 44 | 45 | static void pspDevLpcRead(X86PADDR offMmio, size_t cbRead, void *pvVal, void *pvUser) 46 | { 47 | PPSPDEVLPC pBank = (PPSPDEVLPC)pvUser; 48 | 49 | if (cbRead != sizeof(uint8_t)) 50 | { 51 | PSPEmuTraceEvtAddString(NULL, PSPTRACEEVTSEVERITY_ERROR, PSPTRACEEVTORIGIN_LPC, 52 | "Invalid register read size %u cbRead=%zu", offMmio, cbRead); 53 | return; 54 | } 55 | 56 | /** @todo */ 57 | } 58 | 59 | 60 | static void pspDevLpcWrite(X86PADDR offMmio, size_t cbWrite, const void *pvVal, void *pvUser) 61 | { 62 | PPSPDEVLPC pBank = (PPSPDEVLPC)pvUser; 63 | 64 | if (cbWrite != sizeof(uint8_t)) 65 | { 66 | PSPEmuTraceEvtAddString(NULL, PSPTRACEEVTSEVERITY_ERROR, PSPTRACEEVTORIGIN_LPC, 67 | "Invalid register write size %u cbWrite=%zu", offMmio, cbWrite); 68 | return; 69 | } 70 | 71 | /** @todo */ 72 | } 73 | 74 | 75 | static int pspDevLpcInit(PPSPDEV pDev) 76 | { 77 | int rc = 0; 78 | PPSPDEVLPC pThis = (PPSPDEVLPC)&pDev->abInstance[0]; 79 | 80 | pThis->pDev = pDev; 81 | /** @todo: Emulate PCI config space so we can catch the actual range used 82 | * for wide I/O instead of hardocding it here. */ 83 | rc = PSPEmuIoMgrX86MmioRegister(pDev->hIoMgr, 0xfffdfc00164e, 2, 84 | pspDevLpcRead, pspDevLpcWrite, pThis, 85 | "LPC host bridge", &pThis->hMmioX86); 86 | if (!rc) 87 | rc = PSPEmuIoMgrX86MmioRegister(pDev->hIoMgr, 0xfffdfc00002e, 2, 88 | pspDevLpcRead, pspDevLpcWrite, pThis, 89 | "SuperIO 0x2e", &pThis->hMmioX862e); 90 | 91 | return rc; 92 | } 93 | 94 | 95 | static void pspDevLpcDestruct(PPSPDEV pDev) 96 | { 97 | /* Nothing to do so far. */ 98 | } 99 | 100 | 101 | /** 102 | * Device registration structure. 103 | */ 104 | const PSPDEVREG g_DevRegLpc = 105 | { 106 | /** pszName */ 107 | "lpc", 108 | /** pszDesc */ 109 | "LPC host bridge", 110 | /** cbInstance */ 111 | sizeof(PSPDEVLPC), 112 | /** pfnInit */ 113 | pspDevLpcInit, 114 | /** pfnDestruct */ 115 | pspDevLpcDestruct, 116 | /** pfnReset */ 117 | NULL 118 | }; 119 | 120 | -------------------------------------------------------------------------------- /psp-dev-mmio-unknown.c: -------------------------------------------------------------------------------- 1 | /** @file 2 | * PSP Emulator - Unknown devices mapped directly into MMIO space. 3 | */ 4 | 5 | /* 6 | * Copyright (C) 2020 Alexander Eichner 7 | * 8 | * This program is free software: you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License as published by 10 | * the Free Software Foundation, version 3. 11 | * 12 | * This program is distributed in the hope that it will be useful, but 13 | * WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 | * General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with this program. If not, see . 19 | */ 20 | 21 | #include 22 | 23 | #include 24 | 25 | 26 | /** 27 | * Unknown device instance data. 28 | */ 29 | typedef struct PSPDEVUNK 30 | { 31 | /** Pointer to the owning device instance. */ 32 | PPSPDEV pDev; 33 | /** 0x03006038 register handle. */ 34 | PSPIOMREGIONHANDLE hMmio0x03006038; 35 | /** 0x03200044 register handle. */ 36 | PSPIOMREGIONHANDLE hMmio0x03200044; 37 | /** 0x0301003c register handle. */ 38 | PSPIOMREGIONHANDLE hMmio0x0301003c; 39 | /** 0x030101c0 register handle for Zen2. */ 40 | PSPIOMREGIONHANDLE hMmio0x030101c0; 41 | } PSPDEVUNK; 42 | /** Pointer to the device instance data. */ 43 | typedef PSPDEVUNK *PPSPDEVUNK; 44 | 45 | 46 | static void pspDevUnkMmioRead0x03006038(PSPADDR offMmio, size_t cbRead, void *pvVal, void *pvUser) 47 | { 48 | printf("%s: offMmio=%#x cbRead=%zu\n", __FUNCTION__, offMmio, cbRead); 49 | 50 | switch (offMmio) 51 | { 52 | case 0x0: 53 | /* The on chip bootloader waits for bit 0 to go 1. */ 54 | *(uint32_t *)pvVal = 0x1; 55 | break; 56 | } 57 | } 58 | 59 | static void pspDevUnkMmioRead0x0301003c(PSPADDR offMmio, size_t cbRead, void *pvVal, void *pvUser) 60 | { 61 | PPSPDEVUNK pThis = (PPSPDEVUNK)pvUser; 62 | bool fPspDbgMode = pThis->pDev->pCfg->fPspDbgMode; 63 | 64 | *(uint32_t *)pvVal = fPspDbgMode ? 0x1 : 0; /* Enables debug output on a Ryzen Pro off chip bootloaders. */ 65 | } 66 | 67 | static void pspDevUnkMmioRead0x030101c0(PSPADDR offMmio, size_t cbRead, void *pvVal, void *pvUser) 68 | { 69 | PPSPDEVUNK pThis = (PPSPDEVUNK)pvUser; 70 | bool fPspDbgMode = pThis->pDev->pCfg->fPspDbgMode; 71 | 72 | *(uint32_t *)pvVal = fPspDbgMode ? 0x80102 : 0x100; /* Disables signature verification in Zen2 off chip BLs. */ 73 | } 74 | 75 | 76 | static int pspDevMmioUnkInit(PPSPDEV pDev) 77 | { 78 | PPSPDEVUNK pThis = (PPSPDEVUNK)&pDev->abInstance[0]; 79 | 80 | pThis->pDev = pDev; 81 | 82 | /* Register MMIO ranges. */ 83 | int rc = PSPEmuIoMgrMmioRegister(pDev->hIoMgr, 0x03006038, 4, 84 | pspDevUnkMmioRead0x03006038, NULL, pThis, 85 | NULL /*pszDesc*/, &pThis->hMmio0x03006038); 86 | 87 | /* For the Ryzen off chip bootloader determining whether to print strings to x86 UART. */ 88 | if (!rc) 89 | rc = PSPEmuIoMgrMmioRegister(pDev->hIoMgr, 0x0301003c, 4, 90 | pspDevUnkMmioRead0x0301003c, NULL, pThis, 91 | NULL /*pszDesc*/, &pThis->hMmio0x0301003c); 92 | 93 | if ( !rc 94 | && pDev->pCfg->pPspProfile->enmMicroArch >= PSPEMUMICROARCH_ZEN2) 95 | rc = PSPEmuIoMgrMmioRegister(pDev->hIoMgr, 0x030101c0, 4, 96 | pspDevUnkMmioRead0x030101c0, NULL, pThis, 97 | NULL /*pszDesc*/, &pThis->hMmio0x030101c0); 98 | 99 | #if 0 100 | if (!rc) 101 | rc = PSPEmuIoMgrMmioRegister(pDev->hIoMgr, 0x03200044, 4, 102 | pspDevUnkMmioRead0x03006038, NULL, pThis, 103 | &pThis->hMmio0x03200044); 104 | #endif 105 | return rc; 106 | } 107 | 108 | 109 | static void pspDevMmioUnkDestruct(PPSPDEV pDev) 110 | { 111 | /* Nothing to do so far. */ 112 | } 113 | 114 | 115 | /** 116 | * Device registration structure. 117 | */ 118 | const PSPDEVREG g_DevRegMmioUnk = 119 | { 120 | /** pszName */ 121 | "mmio-unknown", 122 | /** pszDesc */ 123 | "Unknown MMIO registers device", 124 | /** cbInstance */ 125 | sizeof(PSPDEVUNK), 126 | /** pfnInit */ 127 | pspDevMmioUnkInit, 128 | /** pfnDestruct */ 129 | pspDevMmioUnkDestruct, 130 | /** pfnReset */ 131 | NULL 132 | }; 133 | 134 | -------------------------------------------------------------------------------- /psp-dev-mp2.c: -------------------------------------------------------------------------------- 1 | /** @file 2 | * PSP Emulator - MP2 device (ARM core configured as I2C controller) attached to SMN. 3 | */ 4 | 5 | /* 6 | * Copyright (C) 2020 Alexander Eichner 7 | * 8 | * This program is free software: you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License as published by 10 | * the Free Software Foundation, version 3. 11 | * 12 | * This program is distributed in the hope that it will be useful, but 13 | * WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 | * General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with this program. If not, see . 19 | */ 20 | 21 | #include 22 | #include 23 | 24 | #include 25 | 26 | #include 27 | 28 | 29 | /** 30 | * MP2 device instance data. 31 | */ 32 | typedef struct PSPDEVMP2 33 | { 34 | /** SMN region handle for the firmware region. */ 35 | PSPIOMREGIONHANDLE hSmnFw; 36 | /** SMN region handle for the SRAM1 region. */ 37 | PSPIOMREGIONHANDLE hSmnSram1; 38 | /** The memory the firmware is loaded to residing at SMN address 0x3f00000. */ 39 | uint8_t abFw[192 * _1K]; 40 | /** An SRAM1 region used for some sort of config residing at SMN address 0x3f50000. */ 41 | uint8_t abSram1[1376]; 42 | } PSPDEVMP2; 43 | /** Pointer to the device instance data. */ 44 | typedef PSPDEVMP2 *PPSPDEVMP2; 45 | 46 | 47 | static void pspDevMp2FwRead(SMNADDR offSmn, size_t cbRead, void *pvDst, void *pvUser) 48 | { 49 | PPSPDEVMP2 pThis = (PPSPDEVMP2)pvUser; 50 | 51 | memcpy(pvDst, &pThis->abFw[offSmn], cbRead); 52 | } 53 | 54 | 55 | static void pspDevMp2FwWrite(SMNADDR offSmn, size_t cbWrite, const void *pvVal, void *pvUser) 56 | { 57 | PPSPDEVMP2 pThis = (PPSPDEVMP2)pvUser; 58 | 59 | memcpy(&pThis->abFw[offSmn], pvVal, cbWrite); 60 | } 61 | 62 | 63 | static void pspDevMp2Sram1Read(SMNADDR offSmn, size_t cbRead, void *pvDst, void *pvUser) 64 | { 65 | PPSPDEVMP2 pThis = (PPSPDEVMP2)pvUser; 66 | 67 | memcpy(pvDst, &pThis->abSram1[offSmn], cbRead); 68 | } 69 | 70 | 71 | static void pspDevMp2Sram1Write(SMNADDR offSmn, size_t cbWrite, const void *pvVal, void *pvUser) 72 | { 73 | PPSPDEVMP2 pThis = (PPSPDEVMP2)pvUser; 74 | 75 | memcpy(&pThis->abSram1[offSmn], pvVal, cbWrite); 76 | } 77 | 78 | 79 | static int pspDevMp2Init(PPSPDEV pDev) 80 | { 81 | PPSPDEVMP2 pThis = (PPSPDEVMP2)&pDev->abInstance[0]; 82 | 83 | int rc = PSPEmuIoMgrSmnRegister(pDev->hIoMgr, 0x03f00000, sizeof(pThis->abFw), 84 | pspDevMp2FwRead, pspDevMp2FwWrite, pThis, 85 | "MP2 SRAM0", &pThis->hSmnFw); 86 | if (!rc) 87 | rc = PSPEmuIoMgrSmnRegister(pDev->hIoMgr, 0x03f50000, sizeof(pThis->abSram1), 88 | pspDevMp2Sram1Read, pspDevMp2Sram1Write, pThis, 89 | "MP2 SRAM1", &pThis->hSmnSram1); 90 | 91 | return rc; 92 | } 93 | 94 | 95 | static void pspDevMp2Destruct(PPSPDEV pDev) 96 | { 97 | /* Nothing to do so far. */ 98 | } 99 | 100 | 101 | /** 102 | * Device registration structure. 103 | */ 104 | const PSPDEVREG g_DevRegMp2 = 105 | { 106 | /** pszName */ 107 | "mp2", 108 | /** pszDesc */ 109 | "MP2 device", 110 | /** cbInstance */ 111 | sizeof(PSPDEVMP2), 112 | /** pfnInit */ 113 | pspDevMp2Init, 114 | /** pfnDestruct */ 115 | pspDevMp2Destruct, 116 | /** pfnReset */ 117 | NULL 118 | }; 119 | 120 | -------------------------------------------------------------------------------- /psp-dev-rtc.c: -------------------------------------------------------------------------------- 1 | /** @file 2 | * PSP Emulator - Standard RTC/CMOS device implementation. 3 | */ 4 | 5 | /* 6 | * Copyright (C) 2020 Alexander Eichner 7 | * 8 | * This program is free software: you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License as published by 10 | * the Free Software Foundation, version 3. 11 | * 12 | * This program is distributed in the hope that it will be useful, but 13 | * WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 | * General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with this program. If not, see . 19 | */ 20 | 21 | #include 22 | 23 | #include 24 | 25 | #include 26 | #include 27 | 28 | 29 | /** 128 bytes per CMOS bank. */ 30 | #define PSPEMU_RTC_CMOS_BANK_SZ 128 31 | 32 | /** Pointer to the device instance data. */ 33 | typedef struct PSPDEVRTC *PPSPDEVRTC; 34 | 35 | 36 | /** 37 | * Single CMOS bank with values. 38 | */ 39 | typedef struct CMOSBANK 40 | { 41 | /** Pointer to the owning device. */ 42 | PPSPDEVRTC pDev; 43 | /** MMIO region handle for this bank. */ 44 | PSPIOMREGIONHANDLE hMmioX86; 45 | /** The bank number. */ 46 | uint32_t idBank; 47 | /** The current selected offset in the CMOS bank. */ 48 | uint8_t offBank; 49 | /** The CMOS bank data. */ 50 | uint8_t abBank[PSPEMU_RTC_CMOS_BANK_SZ]; 51 | } CMOSBANK; 52 | /** Pointer to a GPIO bank. */ 53 | typedef CMOSBANK *PCMOSBANK; 54 | /** Pointer to a const bank. */ 55 | typedef const CMOSBANK *PCCMOSBANK; 56 | 57 | 58 | /** 59 | * RTC device instance data. 60 | */ 61 | typedef struct PSPDEVRTC 62 | { 63 | /** Pointer to the owning device instance. */ 64 | PPSPDEV pDev; 65 | /** The CMOS banks. */ 66 | CMOSBANK aBanks[2]; 67 | } PSPDEVRTC; 68 | 69 | 70 | static const char *s_apszCmosBankDesc[] = 71 | { 72 | "CMOS Bank 0", 73 | "CMOS Bank 1" 74 | }; 75 | 76 | 77 | static void pspDevRtcCmosBankRead(X86PADDR offMmio, size_t cbRead, void *pvVal, void *pvUser) 78 | { 79 | PCCMOSBANK pBank = (PCCMOSBANK)pvUser; 80 | 81 | if (cbRead != sizeof(uint8_t)) 82 | { 83 | PSPEmuTraceEvtAddString(NULL, PSPTRACEEVTSEVERITY_ERROR, PSPTRACEEVTORIGIN_RTC, 84 | "Invalid register read size %u cbRead=%zu", offMmio, cbRead); 85 | return; 86 | } 87 | 88 | uint8_t *pbVal = (uint8_t *)pvVal; 89 | if (offMmio == 0) 90 | *pbVal = 0xff; /* Address register is write-only. */ 91 | else 92 | *pbVal = pBank->abBank[pBank->offBank]; 93 | } 94 | 95 | 96 | static void pspDevRtcCmosBankWrite(X86PADDR offMmio, size_t cbWrite, const void *pvVal, void *pvUser) 97 | { 98 | PCMOSBANK pBank = (PCMOSBANK)pvUser; 99 | 100 | if (cbWrite != sizeof(uint8_t)) 101 | { 102 | PSPEmuTraceEvtAddString(NULL, PSPTRACEEVTSEVERITY_ERROR, PSPTRACEEVTORIGIN_RTC, 103 | "Invalid register write size %u cbWrite=%zu", offMmio, cbWrite); 104 | return; 105 | } 106 | 107 | uint8_t bVal = *(const uint8_t *)pvVal; 108 | if (offMmio == 0) 109 | pBank->offBank = bVal & 0x7f; 110 | else 111 | pBank->abBank[pBank->offBank] = bVal; 112 | } 113 | 114 | 115 | static int pspDevRtcInit(PPSPDEV pDev) 116 | { 117 | int rc = 0; 118 | PPSPDEVRTC pThis = (PPSPDEVRTC)&pDev->abInstance[0]; 119 | 120 | pThis->pDev = pDev; 121 | 122 | for (uint32_t i = 0; i < ELEMENTS(pThis->aBanks) && !rc; i++) 123 | { 124 | PCMOSBANK pBank = &pThis->aBanks[i]; 125 | 126 | pBank->pDev = pThis; 127 | pBank->idBank = i; 128 | 129 | rc = PSPEmuIoMgrX86MmioRegister(pDev->hIoMgr, 0xfffdfc000070 + i * 2, 2, 130 | pspDevRtcCmosBankRead, pspDevRtcCmosBankWrite, pBank, 131 | s_apszCmosBankDesc[i], &pBank->hMmioX86); 132 | } 133 | 134 | return rc; 135 | } 136 | 137 | 138 | static void pspDevRtcDestruct(PPSPDEV pDev) 139 | { 140 | /* Nothing to do so far. */ 141 | } 142 | 143 | 144 | /** 145 | * Device registration structure. 146 | */ 147 | const PSPDEVREG g_DevRegRtc = 148 | { 149 | /** pszName */ 150 | "rtc", 151 | /** pszDesc */ 152 | "RTC/CMOS device", 153 | /** cbInstance */ 154 | sizeof(PSPDEVRTC), 155 | /** pfnInit */ 156 | pspDevRtcInit, 157 | /** pfnDestruct */ 158 | pspDevRtcDestruct, 159 | /** pfnReset */ 160 | NULL 161 | }; 162 | 163 | -------------------------------------------------------------------------------- /psp-dev-smu.c: -------------------------------------------------------------------------------- 1 | /** @file 2 | * PSP Emulator - SMU attached to SMN. 3 | */ 4 | 5 | /* 6 | * Copyright (C) 2020 Alexander Eichner 7 | * 8 | * This program is free software: you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License as published by 10 | * the Free Software Foundation, version 3. 11 | * 12 | * This program is distributed in the hope that it will be useful, but 13 | * WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 | * General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with this program. If not, see . 19 | */ 20 | 21 | #include 22 | #include 23 | 24 | #include 25 | 26 | #include 27 | 28 | 29 | /** 30 | * SMU device instance data. 31 | */ 32 | typedef struct PSPDEVSMU 33 | { 34 | /** SMN region handle. */ 35 | PSPIOMREGIONHANDLE hSmn; 36 | /** SMN region handle for the interrupt read register? */ 37 | PSPIOMREGIONHANDLE hSmnIntrRdy; 38 | /** SMN region handle for the message passing interface. */ 39 | PSPIOMREGIONHANDLE hSmnMsg; 40 | /** SMN region handle for the firmware region. */ 41 | PSPIOMREGIONHANDLE hSmnFw; 42 | /** Message status register. */ 43 | uint32_t u32RegMsgSts; 44 | /** Argument/Return value register. */ 45 | uint32_t u32RegMsgArgRet; 46 | /** Message ID register. */ 47 | uint32_t u32RegMsgId; 48 | /** The memory the firmware is loaded to residing at SMN address 0x3c00000. */ 49 | uint8_t abFw[_256K]; 50 | } PSPDEVSMU; 51 | /** Pointer to the device instance data. */ 52 | typedef PSPDEVSMU *PPSPDEVSMU; 53 | 54 | 55 | static void pspDevSmuRead(SMNADDR offSmn, size_t cbRead, void *pvDst, void *pvUser) 56 | { 57 | PPSPDEVSMU pThis = (PPSPDEVSMU)pvUser; 58 | 59 | if (cbRead != sizeof(uint32_t)) 60 | { 61 | printf("%s: offSmn=%#x cbRead=%zu -> Unsupported access width\n", __FUNCTION__, offSmn, cbRead); 62 | return; 63 | } 64 | 65 | switch (offSmn) 66 | { 67 | case 0: /* Maybe some sort of status register. */ 68 | { 69 | *(uint32_t *)pvDst = 0x1; /* Some SMU ready/online bit the off chip bootloader waits for after the firmware was loaded. */ 70 | break; 71 | } 72 | } 73 | } 74 | 75 | 76 | static void pspDevSmuMsgRead(SMNADDR offSmn, size_t cbRead, void *pvDst, void *pvUser) 77 | { 78 | PPSPDEVSMU pThis = (PPSPDEVSMU)pvUser; 79 | 80 | if (cbRead != sizeof(uint32_t)) 81 | { 82 | printf("%s: offSmn=%#x cbRead=%zu -> Unsupported access width\n", __FUNCTION__, offSmn, cbRead); 83 | return; 84 | } 85 | 86 | switch (offSmn) 87 | { 88 | case 0: /* Message argument register. */ 89 | { 90 | *(uint32_t *)pvDst = pThis->u32RegMsgArgRet; 91 | break; 92 | } 93 | case 4: /* Status register. */ 94 | { 95 | *(uint32_t *)pvDst = pThis->u32RegMsgSts; 96 | break; 97 | } 98 | case 20: /* Message ID register. */ 99 | { 100 | *(uint32_t *)pvDst = pThis->u32RegMsgId; 101 | break; 102 | } 103 | default: 104 | printf("%s: offSmn=%#x cbRead=%zu -> Unsupported register offset\n", __FUNCTION__, offSmn, cbRead); 105 | } 106 | } 107 | 108 | 109 | static void pspDevSmuMsgWrite(SMNADDR offSmn, size_t cbWrite, const void *pvVal, void *pvUser) 110 | { 111 | PPSPDEVSMU pThis = (PPSPDEVSMU)pvUser; 112 | 113 | if (cbWrite != sizeof(uint32_t)) 114 | { 115 | printf("%s: offSmn=%#x cbWrite=%zu -> Unsupported access width\n", __FUNCTION__, offSmn, cbWrite); 116 | return; 117 | } 118 | 119 | switch (offSmn) 120 | { 121 | case 0: /* Message argument register. */ 122 | { 123 | pThis->u32RegMsgArgRet = *(const uint32_t *)pvVal; 124 | break; 125 | } 126 | case 4: /* Status register. */ 127 | { 128 | pThis->u32RegMsgSts = *(const uint32_t *)pvVal; 129 | break; 130 | } 131 | case 20: /* Message ID register which kicks off the request. */ 132 | case 24: /* Zen 2 has the Message ID register reloacted it looks like. */ 133 | { 134 | pThis->u32RegMsgId = *(const uint32_t *)pvVal; 135 | printf("SMU: Executing request %#x with argument %#x\n", pThis->u32RegMsgId, pThis->u32RegMsgArgRet); 136 | /* Writing the message register, executes the request and sets the ready bit when done. */ 137 | pThis->u32RegMsgSts |= 0x1; 138 | break; 139 | } 140 | default: 141 | printf("%s: offSmn=%#x cbWrite=%zu -> Unsupported register offset\n", __FUNCTION__, offSmn, cbWrite); 142 | } 143 | } 144 | 145 | 146 | static void pspDevSmuFwRead(SMNADDR offSmn, size_t cbRead, void *pvDst, void *pvUser) 147 | { 148 | PPSPDEVSMU pThis = (PPSPDEVSMU)pvUser; 149 | 150 | memcpy(pvDst, &pThis->abFw[offSmn], cbRead); 151 | } 152 | 153 | 154 | static void pspDevSmuFwWrite(SMNADDR offSmn, size_t cbWrite, const void *pvVal, void *pvUser) 155 | { 156 | PPSPDEVSMU pThis = (PPSPDEVSMU)pvUser; 157 | 158 | memcpy(&pThis->abFw[offSmn], pvVal, cbWrite); 159 | } 160 | 161 | 162 | static int pspDevSmuInit(PPSPDEV pDev) 163 | { 164 | PPSPDEVSMU pThis = (PPSPDEVSMU)&pDev->abInstance[0]; 165 | 166 | pThis->u32RegMsgSts = 0x1; /* Ready for message bit? */ 167 | 168 | SMNADDR SmnAddrSmu = pDev->pCfg->pPspProfile->enmMicroArch >= PSPEMUMICROARCH_ZEN2 ? 0x03b10024 : 0x03b10034; 169 | int rc = PSPEmuIoMgrSmnRegister(pDev->hIoMgr, SmnAddrSmu, 4, 170 | pspDevSmuRead, NULL, pThis, 171 | "SmuSts", &pThis->hSmn); 172 | if (!rc) /* The off chip Ryzen bootloader waits for the interrupt ready flag. */ 173 | rc = PSPEmuIoMgrSmnRegister(pDev->hIoMgr, 0x03b10028, 4, 174 | pspDevSmuRead, NULL, pThis, 175 | "SmuSts2", &pThis->hSmnIntrRdy); 176 | if (!rc) 177 | rc = PSPEmuIoMgrSmnRegister(pDev->hIoMgr, 0x03b10700, 7 * sizeof(uint32_t), 178 | pspDevSmuMsgRead, pspDevSmuMsgWrite, pThis, 179 | "SmuMsg", &pThis->hSmnMsg); 180 | if (!rc) 181 | rc = PSPEmuIoMgrSmnRegister(pDev->hIoMgr, 0x03c00000, sizeof(pThis->abFw), 182 | pspDevSmuFwRead, pspDevSmuFwWrite, pThis, 183 | "SmuFw", &pThis->hSmnFw); 184 | return rc; 185 | } 186 | 187 | 188 | static void pspDevSmuDestruct(PPSPDEV pDev) 189 | { 190 | /* Nothing to do so far. */ 191 | } 192 | 193 | 194 | /** 195 | * Device registration structure. 196 | */ 197 | const PSPDEVREG g_DevRegSmu = 198 | { 199 | /** pszName */ 200 | "smu", 201 | /** pszDesc */ 202 | "SMU device", 203 | /** cbInstance */ 204 | sizeof(PSPDEVSMU), 205 | /** pfnInit */ 206 | pspDevSmuInit, 207 | /** pfnDestruct */ 208 | pspDevSmuDestruct, 209 | /** pfnReset */ 210 | NULL 211 | }; 212 | 213 | -------------------------------------------------------------------------------- /psp-dev-status.c: -------------------------------------------------------------------------------- 1 | /** @file 2 | * PSP Emulator - Captures status information from x86 port 80h (0xfffdfc000080) and MMIO 0x32000e8. 3 | */ 4 | 5 | /* 6 | * Copyright (C) 2020 Alexander Eichner 7 | * 8 | * This program is free software: you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License as published by 10 | * the Free Software Foundation, version 3. 11 | * 12 | * This program is distributed in the hope that it will be useful, but 13 | * WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 | * General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with this program. If not, see . 19 | */ 20 | 21 | #include 22 | 23 | #include 24 | #include 25 | 26 | #include 27 | #include 28 | 29 | /** 30 | * Status device instance data. 31 | */ 32 | typedef struct PSPDEVSTS 33 | { 34 | /** Pointer to the owning device instance. */ 35 | PPSPDEV pDev; 36 | /** MMIO region handle. */ 37 | PSPIOMREGIONHANDLE hMmio; 38 | /** X86 MMIO region handle. */ 39 | PSPIOMREGIONHANDLE hX86Mmio; 40 | /** Flag whether the firmware is currently logging a string through port 80h. */ 41 | bool fPort80hLog; 42 | /** Next character to write. */ 43 | uint32_t offWrite; 44 | /** Character buffer holding the string. */ 45 | char achBuf[512]; 46 | } PSPDEVSTS; 47 | /** Pointer to the device instance data. */ 48 | typedef PSPDEVSTS *PPSPDEVSTS; 49 | 50 | /** 51 | * The human readable status code strings. 52 | */ 53 | static const char *g_apszPspFwSts[] = 54 | { 55 | PSPSTATUS_STR_TBL 56 | }; 57 | 58 | 59 | /** 60 | * Logs the given status code from the firmware to the trace log. 61 | * 62 | * @returns nothing. 63 | * @param pThis The status device instance data. 64 | * @param fX86 Flag whether this value was written to the standard 80h x86 port. 65 | * @param uStsVal The status value to log. 66 | */ 67 | static void pspDevStsLogCode(PPSPDEVSTS pThis, bool fX86, uint32_t uStsVal) 68 | { 69 | if (uStsVal < ELEMENTS(g_apszPspFwSts)) 70 | PSPEmuTraceEvtAddString(NULL, PSPTRACEEVTSEVERITY_INFO, PSPTRACEEVTORIGIN_STS, 71 | "POST CODE (%s): %s", fX86 ? "X86" : "PSP", g_apszPspFwSts[uStsVal]); 72 | else 73 | PSPEmuTraceEvtAddString(NULL, PSPTRACEEVTSEVERITY_INFO, PSPTRACEEVTORIGIN_STS, 74 | "POST CODE (%s): UNKNOWN %#x", fX86 ? "X86" : "PSP", uStsVal); 75 | } 76 | 77 | static void pspDevStsMmioRead(PSPADDR offMmio, size_t cbRead, void *pvVal, void *pvUser) 78 | { 79 | PPSPDEVSTS pThis = (PPSPDEVSTS)pvUser; 80 | 81 | if (cbRead != sizeof(uint32_t)) 82 | { 83 | PSPEmuTraceEvtAddString(NULL, PSPTRACEEVTSEVERITY_ERROR, PSPTRACEEVTORIGIN_STS, 84 | "Invalid register read size %u cbRead=%zu", offMmio, cbRead); 85 | return; 86 | } 87 | 88 | *(uint32_t *)pvVal = 0; /** @todo Figure out value on real hardware. */ 89 | } 90 | 91 | static void pspDevStsMmioWrite(PSPADDR offMmio, size_t cbWrite, const void *pvVal, void *pvUser) 92 | { 93 | PPSPDEVSTS pThis = (PPSPDEVSTS)pvUser; 94 | 95 | if (cbWrite != sizeof(uint32_t)) 96 | { 97 | PSPEmuTraceEvtAddString(NULL, PSPTRACEEVTSEVERITY_ERROR, PSPTRACEEVTORIGIN_STS, 98 | "Invalid register write size %u cbWrite=%zu", offMmio, cbWrite); 99 | return; 100 | } 101 | 102 | uint32_t uVal = *(uint32_t *)pvVal; 103 | if (uVal & BIT(8)) 104 | pspDevStsLogCode(pThis, false /*fX86*/, uVal & 0xff); 105 | else 106 | PSPEmuTraceEvtAddString(NULL, PSPTRACEEVTSEVERITY_INFO, PSPTRACEEVTORIGIN_STS, 107 | "PSP STS PORT: %#x", uVal); 108 | } 109 | 110 | static void pspDevStsX86Read(X86PADDR offMmio, size_t cbRead, void *pvVal, void *pvUser) 111 | { 112 | PPSPDEVSTS pThis = (PPSPDEVSTS)pvUser; 113 | 114 | if (cbRead != sizeof(uint32_t)) 115 | { 116 | PSPEmuTraceEvtAddString(NULL, PSPTRACEEVTSEVERITY_ERROR, PSPTRACEEVTORIGIN_STS, 117 | "Invalid register read size %u cbRead=%zu", offMmio, cbRead); 118 | return; 119 | } 120 | 121 | *(uint32_t *)pvVal = 0; /** @todo Figure out value on real hardware. */ 122 | } 123 | 124 | static void pspDevStsX86Write(X86PADDR offMmio, size_t cbWrite, const void *pvVal, void *pvUser) 125 | { 126 | PPSPDEVSTS pThis = (PPSPDEVSTS)pvUser; 127 | 128 | if ( cbWrite != sizeof(uint32_t) 129 | && cbWrite != sizeof(uint8_t)) 130 | { 131 | PSPEmuTraceEvtAddString(NULL, PSPTRACEEVTSEVERITY_ERROR, PSPTRACEEVTORIGIN_STS, 132 | "Invalid register write size %u cbWrite=%zu", offMmio, cbWrite); 133 | return; 134 | } 135 | 136 | switch (cbWrite) 137 | { 138 | case 4: 139 | { 140 | uint32_t uVal = *(uint32_t *)pvVal; 141 | if (uVal == 0x5f535452 /*_STR*/) 142 | { 143 | /* Marks the beginning of a firmware log entry. */ 144 | pThis->fPort80hLog = true; 145 | pThis->offWrite = 0; 146 | } 147 | else if (uVal == 0x5f454e44 /*_END*/) 148 | { 149 | /* Marks the end of a firmware log entry. */ 150 | pThis->fPort80hLog = false; 151 | pThis->achBuf[pThis->offWrite] = '\0'; /* Ensure termination. */ 152 | PSPEmuTraceEvtAddString(NULL, PSPTRACEEVTSEVERITY_INFO, PSPTRACEEVTORIGIN_STS, 153 | "%s", &pThis->achBuf[0]); 154 | pThis->offWrite = 0; 155 | } 156 | else 157 | pspDevStsLogCode(pThis, true /*fX86*/, uVal & 0xffff); 158 | break; 159 | } 160 | case 1: 161 | { 162 | if (pThis->fPort80hLog) 163 | { 164 | if (pThis->offWrite < sizeof(pThis->achBuf) - 1) 165 | pThis->achBuf[pThis->offWrite++] = *(char *)pvVal; 166 | } 167 | else 168 | PSPEmuTraceEvtAddString(NULL, PSPTRACEEVTSEVERITY_ERROR, PSPTRACEEVTORIGIN_STS, 169 | "Invalid register write size %u cbWrite=%zu", offMmio, cbWrite); 170 | } 171 | } 172 | } 173 | 174 | static int pspDevStsInit(PPSPDEV pDev) 175 | { 176 | PPSPDEVSTS pThis = (PPSPDEVSTS)&pDev->abInstance[0]; 177 | 178 | pThis->pDev = pDev; 179 | pThis->fPort80hLog = false; 180 | pThis->offWrite = 0; 181 | 182 | /* Register MMIO ranges. */ 183 | int rc = PSPEmuIoMgrMmioRegister(pDev->hIoMgr, pDev->pCfg->pPspProfile->PspAddrMmioSts, 4, 184 | pspDevStsMmioRead, pspDevStsMmioWrite, pThis, 185 | "PspSts", &pThis->hMmio); 186 | if (!rc) 187 | rc = PSPEmuIoMgrX86MmioRegister(pDev->hIoMgr, 0xfffdfc000080, 4, 188 | pspDevStsX86Read, pspDevStsX86Write, pThis, 189 | "X86Sts",&pThis->hX86Mmio); 190 | return rc; 191 | } 192 | 193 | 194 | static void pspDevStsDestruct(PPSPDEV pDev) 195 | { 196 | /* Nothing to do so far. */ 197 | } 198 | 199 | 200 | /** 201 | * Device registration structure. 202 | */ 203 | const PSPDEVREG g_DevRegSts = 204 | { 205 | /** pszName */ 206 | "status", 207 | /** pszDesc */ 208 | "Status collector device", 209 | /** cbInstance */ 210 | sizeof(PSPDEVSTS), 211 | /** pfnInit */ 212 | pspDevStsInit, 213 | /** pfnDestruct */ 214 | pspDevStsDestruct, 215 | /** pfnReset */ 216 | NULL 217 | }; 218 | 219 | -------------------------------------------------------------------------------- /psp-dev-timer.c: -------------------------------------------------------------------------------- 1 | /** @file 2 | * PSP Emulator - Timer device starting at 0x03010400 and 0x03010424. 3 | */ 4 | 5 | /* 6 | * Copyright (C) 2020 Alexander Eichner 7 | * 8 | * This program is free software: you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License as published by 10 | * the Free Software Foundation, version 3. 11 | * 12 | * This program is distributed in the hope that it will be useful, but 13 | * WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 | * General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with this program. If not, see . 19 | */ 20 | 21 | #include 22 | 23 | #include 24 | 25 | #include 26 | 27 | #include 28 | 29 | 30 | /** 31 | * Timer device instance data. 32 | */ 33 | typedef struct PSPDEVTIMER 34 | { 35 | /** Flag whether to run in realtime. */ 36 | bool fRealtime; 37 | /** Last nanosecond timestamp. */ 38 | uint64_t tsLast; 39 | /** The control register perhaps. */ 40 | uint32_t regCtrl; 41 | /** The counter running at 100MHz. */ 42 | uint32_t regCnt100MHz; 43 | /** MMIO region handle. */ 44 | PSPIOMREGIONHANDLE hMmio; 45 | } PSPDEVTIMER; 46 | /** Pointer to the device instance data. */ 47 | typedef PSPDEVTIMER *PPSPDEVTIMER; 48 | 49 | 50 | static void pspDevTimerMmioRead(PSPADDR offMmio, size_t cbRead, void *pvVal, void *pvUser) 51 | { 52 | PPSPDEVTIMER pThis = (PPSPDEVTIMER)pvUser; 53 | 54 | if (cbRead != sizeof(uint32_t)) 55 | { 56 | printf("%s: offMmio=%#x cbRead=%zu -> Unsupported access width\n", __FUNCTION__, offMmio, cbRead); 57 | return; 58 | } 59 | 60 | uint32_t *pu32Ret = (uint32_t *)pvVal; 61 | switch (offMmio) 62 | { 63 | case 0: /* Control register */ 64 | { 65 | *pu32Ret = pThis->regCtrl; 66 | break; 67 | } 68 | case 32: /* 100MHz counter. */ 69 | { 70 | if (!pThis->fRealtime) 71 | { 72 | *pu32Ret = pThis->regCnt100MHz; 73 | if (pThis->regCtrl & 0x1) 74 | pThis->regCnt100MHz += 1000 * 1000 * 100; /* 1 second jump per read. */ 75 | } 76 | else 77 | { 78 | if (pThis->regCtrl & 0x1) 79 | { 80 | uint64_t tsNow = OSTimeTsGetNano(); 81 | uint64_t tsElapsed = tsNow - pThis->tsLast; 82 | pThis->regCnt100MHz += (uint32_t)(tsElapsed / 10); /* 10ns intervals. */ 83 | *pu32Ret = pThis->regCnt100MHz; 84 | pThis->tsLast = tsNow; 85 | } 86 | } 87 | break; 88 | } 89 | default: 90 | /* Ignore for now. */ 91 | break; 92 | } 93 | } 94 | 95 | static void pspDevTimerMmioWrite(PSPADDR offMmio, size_t cbWrite, const void *pvVal, void *pvUser) 96 | { 97 | PPSPDEVTIMER pThis = (PPSPDEVTIMER)pvUser; 98 | 99 | if ( cbWrite != sizeof(uint32_t) 100 | && cbWrite != sizeof(uint8_t)) 101 | { 102 | printf("%s: offMmio=%#x cbWrite=%zu -> Unsupported access width\n", __FUNCTION__, offMmio, cbWrite); 103 | return; 104 | } 105 | 106 | uint32_t u32Val = 0; 107 | if (cbWrite == sizeof(uint32_t)) 108 | u32Val = *(uint32_t *)pvVal; 109 | else 110 | u32Val = *(uint8_t *)pvVal; 111 | switch (offMmio) 112 | { 113 | case 0: /* Control register */ 114 | { 115 | /* Read the time once if in realtime mode and the timer got enabled. */ 116 | if ( pThis->fRealtime 117 | && (u32Val & 0x1) 118 | && !(pThis->regCtrl & 0x1)) 119 | pThis->tsLast = OSTimeTsGetNano(); 120 | pThis->regCtrl = u32Val; 121 | break; 122 | } 123 | case 1: /* XXX For single byte access by the on chip bl... */ 124 | { 125 | pThis->regCtrl |= u32Val << 8; 126 | break; 127 | } 128 | case 32: /* 100MHz counter. */ 129 | { 130 | pThis->regCnt100MHz = u32Val; 131 | break; 132 | } 133 | default: 134 | /* Ignore for now. */ 135 | break; 136 | } 137 | } 138 | 139 | 140 | static int pspDevTimerInit(PPSPDEV pDev) 141 | { 142 | PPSPDEVTIMER pThis = (PPSPDEVTIMER)&pDev->abInstance[0]; 143 | 144 | pThis->fRealtime = pDev->pCfg->fTimerRealtime; 145 | pThis->tsLast = OSTimeTsGetNano(); 146 | pThis->regCtrl = 0; 147 | pThis->regCnt100MHz = 0; 148 | 149 | /* Register MMIO ranges. */ 150 | int rc = PSPEmuIoMgrMmioRegister(pDev->hIoMgr, 151 | pDev->pReg == &g_DevRegTimer1 152 | ? 0x03010400 153 | : 0x03010424, 154 | sizeof(uint32_t) * 9, 155 | pspDevTimerMmioRead, pspDevTimerMmioWrite, pThis, 156 | pDev->pReg->pszName, &pThis->hMmio); 157 | return rc; 158 | } 159 | 160 | static void pspDevTimerDestruct(PPSPDEV pDev) 161 | { 162 | /* Nothing to do so far. */ 163 | } 164 | 165 | 166 | /** 167 | * Device registration structure. 168 | */ 169 | const PSPDEVREG g_DevRegTimer1 = 170 | { 171 | /** pszName */ 172 | "timer1", 173 | /** pszDesc */ 174 | "Timer device starting at 0x03010400", 175 | /** cbInstance */ 176 | sizeof(PSPDEVTIMER), 177 | /** pfnInit */ 178 | pspDevTimerInit, 179 | /** pfnDestruct */ 180 | pspDevTimerDestruct, 181 | /** pfnReset */ 182 | NULL 183 | }; 184 | 185 | 186 | /** 187 | * Device registration structure. 188 | */ 189 | const PSPDEVREG g_DevRegTimer2 = 190 | { 191 | /** pszName */ 192 | "timer2", 193 | /** pszDesc */ 194 | "Timer device starting at 0x03010424", 195 | /** cbInstance */ 196 | sizeof(PSPDEVTIMER), 197 | /** pfnInit */ 198 | pspDevTimerInit, 199 | /** pfnDestruct */ 200 | pspDevTimerDestruct, 201 | /** pfnReset */ 202 | NULL 203 | }; 204 | 205 | -------------------------------------------------------------------------------- /psp-dev-version.c: -------------------------------------------------------------------------------- 1 | /** @file 2 | * PSP Emulator - Some sort of version(?) register mapped into MMIO space. 3 | */ 4 | 5 | /* 6 | * Copyright (C) 2020 Alexander Eichner 7 | * 8 | * This program is free software: you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License as published by 10 | * the Free Software Foundation, version 3. 11 | * 12 | * This program is distributed in the hope that it will be useful, but 13 | * WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 | * General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with this program. If not, see . 19 | */ 20 | 21 | #include 22 | 23 | 24 | /** 25 | * Version device instance data. 26 | */ 27 | typedef struct PSPDEVVERS 28 | { 29 | /** Pointer to the owning device instance. */ 30 | PPSPDEV pDev; 31 | /** version register handle. */ 32 | PSPIOMREGIONHANDLE hMmioVersion; 33 | /** The version register value written. */ 34 | uint32_t u32RegVersion; 35 | } PSPDEVVERS; 36 | /** Pointer to the device instance data. */ 37 | typedef PSPDEVVERS *PPSPDEVVERS; 38 | 39 | 40 | static void pspDevVersMmioRead(PSPADDR offMmio, size_t cbRead, void *pvVal, void *pvUser) 41 | { 42 | PPSPDEVVERS pThis = (PPSPDEVVERS)pvUser; 43 | *(uint32_t *)pvVal = pThis->u32RegVersion; 44 | } 45 | 46 | 47 | static void pspDevVersMmioWrite(PSPADDR offMmio, size_t cbWrite, const void *pvVal, void *pvUser) 48 | { 49 | /* 50 | * This is written once by the on chip bootloader right at the beginning and 51 | * read later on to determine the L1 PSP directory to select. 52 | */ 53 | PPSPDEVVERS pThis = (PPSPDEVVERS)pvUser; 54 | pThis->u32RegVersion = *(uint32_t *)pvVal; 55 | } 56 | 57 | 58 | static int pspDevMmioVersInit(PPSPDEV pDev) 59 | { 60 | PPSPDEVVERS pThis = (PPSPDEVVERS)&pDev->abInstance[0]; 61 | 62 | pThis->pDev = pDev; 63 | return PSPEmuIoMgrMmioRegister(pDev->hIoMgr, pDev->pCfg->pPspProfile->PspAddrMmioVersion, 4, 64 | pspDevVersMmioRead, pspDevVersMmioWrite, pThis, 65 | "RegVersion", &pThis->hMmioVersion); 66 | } 67 | 68 | 69 | static void pspDevMmioVersDestruct(PPSPDEV pDev) 70 | { 71 | /* Nothing to do so far. */ 72 | } 73 | 74 | 75 | /** 76 | * Device registration structure. 77 | */ 78 | const PSPDEVREG g_DevRegMmioVersion = 79 | { 80 | /** pszName */ 81 | "version", 82 | /** pszDesc */ 83 | "Version register device", 84 | /** cbInstance */ 85 | sizeof(PSPDEVVERS), 86 | /** pfnInit */ 87 | pspDevMmioVersInit, 88 | /** pfnDestruct */ 89 | pspDevMmioVersDestruct, 90 | /** pfnReset */ 91 | NULL 92 | }; 93 | 94 | -------------------------------------------------------------------------------- /psp-dev-x86-mem.c: -------------------------------------------------------------------------------- 1 | /** @file 2 | * PSP Emulator - x86 memory regions present in the system (secure DRAM, etc.). 3 | */ 4 | 5 | /* 6 | * Copyright (C) 2020 Alexander Eichner 7 | * 8 | * This program is free software: you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License as published by 10 | * the Free Software Foundation, version 3. 11 | * 12 | * This program is distributed in the hope that it will be useful, but 13 | * WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 | * General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with this program. If not, see . 19 | */ 20 | 21 | #include 22 | 23 | #include 24 | 25 | 26 | /** 27 | * x86 memory device instance data. 28 | */ 29 | typedef struct PSPDEVX86MEM 30 | { 31 | /** Pointer to the owning device instance. */ 32 | PPSPDEV pDev; 33 | /** Secure DRAM region handle. */ 34 | PSPIOMREGIONHANDLE hMemSecureDram; 35 | } PSPDEVX86MEM; 36 | /** Pointer to the device instance data. */ 37 | typedef PSPDEVX86MEM *PPSPDEVX86MEM; 38 | 39 | 40 | static int pspDevX86MemInit(PPSPDEV pDev) 41 | { 42 | PPSPDEVX86MEM pThis = (PPSPDEVX86MEM)&pDev->abInstance[0]; 43 | 44 | pThis->pDev = pDev; 45 | 46 | /* Register secure DRAM ranges. */ 47 | int rc = PSPEmuIoMgrX86MemRegister(pDev->hIoMgr, 0xfffdf8000000, 64 * _1M, true /*fCanExec*/, 48 | NULL /*pfnFetch*/, NULL, 49 | "SecureDram", &pThis->hMemSecureDram); 50 | return rc; 51 | } 52 | 53 | 54 | static void pspDevX86MemDestruct(PPSPDEV pDev) 55 | { 56 | /* Nothing to do so far. */ 57 | } 58 | 59 | 60 | /** 61 | * Device registration structure. 62 | */ 63 | const PSPDEVREG g_DevRegX86Mem = 64 | { 65 | /** pszName */ 66 | "x86-mem", 67 | /** pszDesc */ 68 | "x86 memory", 69 | /** cbInstance */ 70 | sizeof(PSPDEVX86MEM), 71 | /** pfnInit */ 72 | pspDevX86MemInit, 73 | /** pfnDestruct */ 74 | pspDevX86MemDestruct, 75 | /** pfnReset */ 76 | NULL 77 | }; 78 | 79 | -------------------------------------------------------------------------------- /psp-dev-x86-unknown.c: -------------------------------------------------------------------------------- 1 | /** @file 2 | * PSP Emulator - Unknown device residing at 0x03200000. 3 | */ 4 | 5 | /* 6 | * Copyright (C) 2020 Alexander Eichner 7 | * 8 | * This program is free software: you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License as published by 10 | * the Free Software Foundation, version 3. 11 | * 12 | * This program is distributed in the hope that it will be useful, but 13 | * WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 | * General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with this program. If not, see . 19 | */ 20 | 21 | #include 22 | 23 | #include 24 | 25 | #include 26 | 27 | 28 | /** 29 | * Unknown device instance data. 30 | */ 31 | typedef struct PSPDEVUNK 32 | { 33 | /** MMIO region handle. */ 34 | PSPIOMREGIONHANDLE hMmio; 35 | } PSPDEVUNK; 36 | /** Pointer to the device instance data. */ 37 | typedef PSPDEVUNK *PPSPDEVUNK; 38 | 39 | static void pspDevX86UnkMmioRead(X86PADDR offMmio, size_t cbRead, void *pvVal, void *pvUser) 40 | { 41 | printf("%s: offMmio=%#llx cbRead=%zu\n", __FUNCTION__, offMmio, cbRead); 42 | 43 | if (cbRead != sizeof(uint8_t)) 44 | { 45 | printf("%s: Unsupported read size cbRead=%zu\n", __FUNCTION__, cbRead); 46 | return; 47 | } 48 | 49 | switch (offMmio) 50 | { 51 | case 0: 52 | /* The off chip bootloader waits for bits 0-2 to be set. */ 53 | *(uint8_t *)pvVal = 0x7; 54 | break; 55 | } 56 | } 57 | 58 | static int pspDevX86UnkInit(PPSPDEV pDev) 59 | { 60 | PPSPDEVUNK pThis = (PPSPDEVUNK)&pDev->abInstance[0]; 61 | 62 | /* Register MMIO ranges. */ 63 | int rc = PSPEmuIoMgrX86MmioRegister(pDev->hIoMgr, 0xfed81e77, 1, 64 | pspDevX86UnkMmioRead, NULL, NULL, 65 | NULL /*pszDesc*/, &pThis->hMmio); 66 | 67 | return rc; 68 | } 69 | 70 | static void pspDevX86UnkDestruct(PPSPDEV pDev) 71 | { 72 | /* Nothing to do so far. */ 73 | } 74 | 75 | 76 | /** 77 | * Device registration structure. 78 | */ 79 | const PSPDEVREG g_DevRegX86Unk = 80 | { 81 | /** pszName */ 82 | "x86-unknown", 83 | /** pszDesc */ 84 | "Unknown X86 MMIO registers device", 85 | /** cbInstance */ 86 | sizeof(PSPDEVUNK), 87 | /** pfnInit */ 88 | pspDevX86UnkInit, 89 | /** pfnDestruct */ 90 | pspDevX86UnkDestruct, 91 | /** pfnReset */ 92 | NULL 93 | }; 94 | 95 | -------------------------------------------------------------------------------- /psp-dev.c: -------------------------------------------------------------------------------- 1 | /** @file 2 | * PSP Emulator - Device interface. 3 | */ 4 | 5 | /* 6 | * Copyright (C) 2020 Alexander Eichner 7 | * 8 | * This program is free software: you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License as published by 10 | * the Free Software Foundation, version 3. 11 | * 12 | * This program is distributed in the hope that it will be useful, but 13 | * WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 | * General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with this program. If not, see . 19 | */ 20 | #include 21 | 22 | #include 23 | #include 24 | #include 25 | 26 | #include 27 | 28 | 29 | int PSPEmuDevCreate(PSPIOM hIoMgr, PCPSPDEVREG pDevReg, PCPSPDEVIF pDevIf, PCPSPEMUCFG pCfg, PPSPDEV *ppDev) 30 | { 31 | int rc = 0; 32 | PPSPDEV pDev = (PPSPDEV)calloc(1, sizeof(*pDev) + pDevReg->cbInstance); 33 | if (pDev) 34 | { 35 | pDev->pReg = pDevReg; 36 | pDev->pDevIf = pDevIf; 37 | pDev->hIoMgr = hIoMgr; 38 | pDev->pCfg = pCfg; 39 | 40 | /* Initialize the device instance and add to the list of known devices. */ 41 | rc = pDev->pReg->pfnInit(pDev); 42 | if (!rc) 43 | { 44 | *ppDev = pDev; 45 | return STS_INF_SUCCESS; 46 | } 47 | 48 | free(pDev); 49 | } 50 | else 51 | rc = STS_ERR_NO_MEMORY; 52 | 53 | return rc; 54 | } 55 | 56 | int PSPEmuDevDestroy(PPSPDEV pDev) 57 | { 58 | pDev->pReg->pfnDestruct(pDev); 59 | free(pDev); 60 | 61 | return STS_INF_SUCCESS; 62 | } 63 | 64 | -------------------------------------------------------------------------------- /psp-disasm.c: -------------------------------------------------------------------------------- 1 | /** @file 2 | * PSP Emulator - Core API (interfacing with unicorn engine). 3 | */ 4 | 5 | /* 6 | * Copyright (C) 2020 Alexander Eichner 7 | * 8 | * This program is free software: you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License as published by 10 | * the Free Software Foundation, version 3. 11 | * 12 | * This program is distributed in the hope that it will be useful, but 13 | * WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 | * General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with this program. If not, see . 19 | */ 20 | #include 21 | #include 22 | 23 | #include 24 | #include 25 | 26 | #include 27 | 28 | int PSPEmuDisasm(char *pchDst, size_t cch, uint32_t cInsnsDisasm, uint8_t *pbCode, size_t cbCode, PSPADDR uAddrStart, bool fThumb) 29 | { 30 | int rc = 0; 31 | csh hCapStone; 32 | cs_insn *paInsn; 33 | 34 | /** @todo Thumb */ 35 | if (cs_open(CS_ARCH_ARM, fThumb ? CS_MODE_THUMB : CS_MODE_ARM, &hCapStone) != CS_ERR_OK) 36 | return -1; 37 | 38 | size_t cInsn = cs_disasm(hCapStone, pbCode, cbCode, uAddrStart, 0, &paInsn); 39 | if (cInsn) 40 | { 41 | size_t cchLeft = cch; 42 | char *pszDst = pchDst; 43 | uint32_t i = 0; 44 | 45 | if (cInsnsDisasm) 46 | cInsn = MIN(cInsn, cInsnsDisasm); 47 | 48 | pchDst[0] = 0; 49 | 50 | while (i < cInsn) 51 | { 52 | size_t cchWritten = snprintf(pszDst, cchLeft, "%#08llx: %s\t\t%s\n", 53 | paInsn[i].address, paInsn[i].mnemonic, 54 | paInsn[i].op_str); 55 | if (cchWritten >= cchLeft) 56 | break; 57 | 58 | cchLeft -= cchWritten; 59 | pszDst += cchWritten; 60 | i++; 61 | } 62 | 63 | cs_free(paInsn, cInsn); 64 | } 65 | else 66 | rc = -1; 67 | 68 | cs_close(&hCapStone); 69 | 70 | return rc; 71 | } 72 | 73 | -------------------------------------------------------------------------------- /psp-emu.c: -------------------------------------------------------------------------------- 1 | /** @file 2 | * PSP Emulator - Entry point. 3 | */ 4 | 5 | /* 6 | * Copyright (C) 2020 Alexander Eichner 7 | * 8 | * This program is free software: you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License as published by 10 | * the Free Software Foundation, version 3. 11 | * 12 | * This program is distributed in the hope that it will be useful, but 13 | * WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 | * General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with this program. If not, see . 19 | */ 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | 27 | #include 28 | 29 | #include 30 | #include 31 | #include 32 | 33 | #include 34 | #include 35 | #include 36 | #include 37 | #include 38 | #include 39 | 40 | 41 | /** 42 | * Executes the given CCD under debugger control. 43 | * 44 | * @returns Status code. 45 | * @param hCcd The CCD instance to run in a debugger. 46 | * @param pCfg The configuration. 47 | */ 48 | static int pspEmuDbgRun(PSPCCD hCcd, PCPSPEMUCFG pCfg) 49 | { 50 | PSPCORE hPspCore = NULL; 51 | 52 | int rc = PSPEmuCcdQueryCore(hCcd, &hPspCore); 53 | if (!rc) 54 | { 55 | /* 56 | * Execute one instruction to initialize the CPU state properly 57 | * so the debugger has valid values to work with. 58 | */ 59 | int rc = PSPEmuCoreExecRun(hPspCore, PSPEMU_CORE_EXEC_F_DEFAULT, 1, PSPEMU_CORE_EXEC_INDEFINITE); 60 | if (!rc) 61 | { 62 | PSPDBG hDbg = NULL; 63 | 64 | rc = PSPEmuDbgCreate(&hDbg, pCfg->uDbgPort, pCfg->cDbgInsnStep, pCfg->PspAddrDbgRunUpTo, 65 | &hCcd, 1, pCfg->hDbgHlp); 66 | if (!rc) 67 | { 68 | printf("Debugger is listening on port %u...\n", pCfg->uDbgPort); 69 | rc = PSPEmuDbgRunloop(hDbg); 70 | } 71 | } 72 | } 73 | 74 | return rc; 75 | } 76 | 77 | 78 | int main(int argc, char *argv[]) 79 | { 80 | PSPEMUCFG Cfg; 81 | 82 | PSPCfgInit(&Cfg); 83 | 84 | /* Parse the config first. */ 85 | int rc = PSPCfgParse(&Cfg, argc, (const char * const *)&argv[0]); 86 | if (STS_SUCCESS(rc)) 87 | { 88 | /* Create a debug helper module if the debugger is going to be used. */ 89 | if (Cfg.uDbgPort) 90 | rc = PSPEmuDbgHlpCreate(&Cfg.hDbgHlp); 91 | 92 | if (STS_SUCCESS(rc)) 93 | { 94 | PSPCCD hCcd = NULL; 95 | if ( Cfg.idSocketSingle != UINT32_MAX 96 | && Cfg.idCcdSingle != UINT32_MAX) 97 | rc = PSPEmuCcdCreate(&hCcd, Cfg.idSocketSingle, Cfg.idCcdSingle, &Cfg); 98 | else 99 | rc = PSPEmuCcdCreate(&hCcd, 0, 0, &Cfg); 100 | 101 | if (!rc) 102 | { 103 | PSPPROXY hProxy = NULL; 104 | PSPX86ICE hX86Ice = NULL; 105 | PSPIOLOGREPLAY hIoLogReplay = NULL; 106 | 107 | /* Setup the proxy if configured. */ 108 | if (Cfg.pszPspProxyAddr) 109 | { 110 | rc = PSPProxyCreate(&hProxy, &Cfg); 111 | if (!rc) 112 | rc = PSPProxyCcdRegister(hProxy, hCcd); 113 | 114 | if ( STS_SUCCESS(rc) 115 | && Cfg.uX86IcePort) 116 | { 117 | rc = PSPX86IceCreate(&hX86Ice, Cfg.uX86IcePort); 118 | if (STS_SUCCESS(rc)) 119 | { 120 | /* Register the ICE bridge with the proxy. */ 121 | rc = PSPProxyX86IceRegister(hProxy, hX86Ice); 122 | } 123 | } 124 | } 125 | else if (Cfg.pszIoLogReplay) 126 | { 127 | rc = PSPIoLogReplayCreate(&hIoLogReplay, Cfg.pszIoLogReplay); 128 | if (STS_SUCCESS(rc)) 129 | rc = PSPIoLogReplayCcdRegister(hIoLogReplay, hCcd); 130 | } 131 | 132 | if (!rc) 133 | { 134 | if (Cfg.uDbgPort) 135 | rc = pspEmuDbgRun(hCcd, &Cfg); 136 | else 137 | rc = PSPEmuCcdRun(hCcd); 138 | } 139 | 140 | if (hProxy) 141 | { 142 | PSPProxyCcdDeregister(hProxy, hCcd); 143 | PSPProxyDestroy(hProxy); 144 | } 145 | 146 | if (hIoLogReplay) 147 | { 148 | PSPIoLogReplayCcdDeregister(hIoLogReplay, hCcd); 149 | PSPIoLogReplayDestroy(hIoLogReplay); 150 | } 151 | 152 | PSPEmuCcdDestroy(hCcd); 153 | } 154 | } 155 | 156 | PSPCfgFree(&Cfg); 157 | } 158 | else 159 | fprintf(stderr, "Parsing arguments failed with %d\n", rc); 160 | 161 | return 0; 162 | } 163 | 164 | -------------------------------------------------------------------------------- /psp-irq.c: -------------------------------------------------------------------------------- 1 | /** @file 2 | * PSP Emulator - Interrupt controller. 3 | */ 4 | 5 | /* 6 | * Copyright (C) 2020 Alexander Eichner 7 | * 8 | * This program is free software: you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License as published by 10 | * the Free Software Foundation, version 3. 11 | * 12 | * This program is distributed in the hope that it will be useful, but 13 | * WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 | * General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with this program. If not, see . 19 | */ 20 | /********************************************************************************************************************************* 21 | * Header Files * 22 | *********************************************************************************************************************************/ 23 | 24 | #include 25 | 26 | #include 27 | #include 28 | #include 29 | 30 | #include 31 | 32 | #include 33 | #include 34 | 35 | 36 | /********************************************************************************************************************************* 37 | * Structures and Typedefs * 38 | *********************************************************************************************************************************/ 39 | 40 | /** 41 | * Interrupt controller instance data. 42 | */ 43 | typedef struct PSPIRQINT 44 | { 45 | /** The PSP core to forward interrupt requests to. */ 46 | PSPCORE hPspCore; 47 | /** I/O manager for the MMIO register interface. */ 48 | PSPIOM hIoMgr; 49 | /** The MMIO region handle for the register interface. */ 50 | PSPIOMREGIONHANDLE hMmio; 51 | /** Interrupt request groups pending. */ 52 | uint32_t cGrpPending; 53 | /** The individual groups. */ 54 | uint32_t abmGrpDev[4]; 55 | /** Hidden individual groups to trigger an IRQ only on a rising edge. */ 56 | uint32_t abmGrpDevLast[4]; 57 | } PSPIRQINT; 58 | /** Pointer to the internal interrupt controller instance data. */ 59 | typedef PSPIRQINT *PPSPIRQINT; 60 | 61 | 62 | /********************************************************************************************************************************* 63 | * Internal Functions * 64 | *********************************************************************************************************************************/ 65 | 66 | 67 | /** 68 | * @copydoc{PFNPSPIOMMMIOREAD, IRQ controller read handler} 69 | */ 70 | static void pspIrqMmioRead(PSPADDR offMmio, size_t cbRead, void *pvDst, void *pvUser) 71 | { 72 | PPSPIRQINT pThis = (PPSPIRQINT)pvUser; 73 | 74 | if (cbRead != sizeof(uint32_t)) 75 | { 76 | PSPEmuTraceEvtAddString(NULL, PSPTRACEEVTSEVERITY_ERROR, PSPTRACEEVTORIGIN_IRQ, 77 | "%s: offMmio=%#x cbRead=%zu -> Unsupported access width\n", __FUNCTION__, offMmio, cbRead); 78 | return; 79 | } 80 | 81 | uint32_t *pu32Dst = (uint32_t *)pvDst; 82 | *pu32Dst = 0; 83 | switch (offMmio) 84 | { 85 | case PSP_IRQ_REG_ACK_PRIO0_OFF: 86 | case PSP_IRQ_REG_ACK_PRIO1_OFF: 87 | case PSP_IRQ_REG_ACK_PRIO2_OFF: 88 | case PSP_IRQ_REG_ACK_PRIO3_OFF: 89 | { 90 | uint32_t idPrio = (offMmio - PSP_IRQ_REG_ACK_PRIO0_OFF) / sizeof(uint32_t); 91 | *pu32Dst = pThis->abmGrpDev[idPrio]; 92 | break; 93 | } 94 | case PSP_IRQ_REG_PEN_OFF: 95 | { 96 | if (pThis->cGrpPending) 97 | *pu32Dst = PSP_IRQ_REG_PEN_PENDING; 98 | else 99 | *pu32Dst = PSP_IRQ_REG_PEN_NOT_PENDING; 100 | break; 101 | } 102 | case PSP_IRQ_REG_ID_OFF: 103 | { 104 | /* 105 | * How it is decided which interrupt source to return on real hardware is not 106 | * known actually at the moment. 107 | * 108 | * We just start from the lowest priority/group and device ID (highest priority) for now. 109 | */ 110 | for (uint32_t i = 0; i < ELEMENTS(pThis->abmGrpDev); i++) 111 | { 112 | if (pThis->abmGrpDev[i] != 0) 113 | { 114 | /** @todo Optimize. */ 115 | uint32_t uPrio = pThis->abmGrpDev[i]; 116 | uint32_t idDev = 0; 117 | while (uPrio) 118 | { 119 | if (uPrio & 1) 120 | break; /* Found the device. */ 121 | uPrio >>= 1; 122 | idDev++; 123 | } 124 | 125 | *pu32Dst = PSP_IRQ_REG_ID_MAKE(i, idDev); 126 | break; 127 | } 128 | } 129 | break; 130 | } 131 | default: 132 | break; 133 | } 134 | } 135 | 136 | 137 | /** 138 | * @copydoc{PFNPSPIOMMMIOWRITE, IRQ controller write handler} 139 | */ 140 | static void pspIrqMmioWrite(PSPADDR offMmio, size_t cbWrite, const void *pvVal, void *pvUser) 141 | { 142 | PPSPIRQINT pThis = (PPSPIRQINT)pvUser; 143 | 144 | if (cbWrite != sizeof(uint32_t)) 145 | { 146 | PSPEmuTraceEvtAddString(NULL, PSPTRACEEVTSEVERITY_ERROR, PSPTRACEEVTORIGIN_IRQ, 147 | "%s: offMmio=%#x cbWrite=%zu -> Unsupported access width\n", __FUNCTION__, offMmio, cbWrite); 148 | return; 149 | } 150 | 151 | uint32_t uVal = *(uint32_t *)pvVal; 152 | switch (offMmio) 153 | { 154 | case PSP_IRQ_REG_ACK_PRIO0_OFF: 155 | case PSP_IRQ_REG_ACK_PRIO1_OFF: 156 | case PSP_IRQ_REG_ACK_PRIO2_OFF: 157 | case PSP_IRQ_REG_ACK_PRIO3_OFF: 158 | { 159 | uint32_t idPrio = (offMmio - PSP_IRQ_REG_ACK_PRIO0_OFF) / sizeof(uint32_t); 160 | 161 | pThis->abmGrpDev[idPrio] &= ~uVal; 162 | if (!pThis->abmGrpDev[idPrio]) 163 | pThis->cGrpPending--; 164 | 165 | if (!pThis->cGrpPending) /* Reset the interrupt line. */ 166 | { 167 | PSPEmuTraceEvtAddString(NULL, PSPTRACEEVTSEVERITY_INFO, PSPTRACEEVTORIGIN_IRQ, "De-Asserting IRQ\n"); 168 | PSPEmuCoreIrqSet(pThis->hPspCore, false /*fAssert*/); 169 | } 170 | break; 171 | } 172 | case PSP_IRQ_REG_PEN_OFF: 173 | case PSP_IRQ_REG_ID_OFF: 174 | default: 175 | break; /* Ignore. */ 176 | } 177 | } 178 | 179 | 180 | int PSPIrqCreate(PPSPIRQ phIrq, PSPCORE hPspCore, PSPIOM hIoMgr) 181 | { 182 | int rc = STS_INF_SUCCESS; 183 | PPSPIRQINT pThis = (PPSPIRQINT)calloc(1, sizeof(*pThis)); 184 | if (pThis) 185 | { 186 | pThis->hPspCore = hPspCore; 187 | pThis->hIoMgr = hIoMgr; 188 | 189 | rc = PSPEmuIoMgrMmioRegister(hIoMgr, PSP_IRQ_MMIO_ADDR_BASE, PSP_IRQ_MMIO_SZ, 190 | pspIrqMmioRead, pspIrqMmioWrite, pThis, 191 | "IRQ Ctrl", &pThis->hMmio); 192 | if (STS_SUCCESS(rc)) 193 | { 194 | *phIrq = pThis; 195 | PSPIrqReset(pThis); 196 | return STS_INF_SUCCESS; 197 | } 198 | 199 | free(pThis); 200 | } 201 | else 202 | rc = STS_ERR_NO_MEMORY; 203 | 204 | return rc; 205 | } 206 | 207 | 208 | void PSPIrqDestroy(PSPIRQ hIrq) 209 | { 210 | PPSPIRQINT pThis = hIrq; 211 | 212 | PSPEmuIoMgrDeregister(pThis->hMmio); 213 | free(pThis); 214 | } 215 | 216 | 217 | void PSPIrqReset(PSPIRQ hIrq) 218 | { 219 | PPSPIRQINT pThis = hIrq; 220 | 221 | pThis->cGrpPending = 0; 222 | for (uint32_t i = 0; i < ELEMENTS(pThis->abmGrpDev); i++) 223 | { 224 | pThis->abmGrpDev[i] = 0; 225 | pThis->abmGrpDevLast[i] = 0; 226 | } 227 | } 228 | 229 | 230 | int PSPIrqSet(PSPIRQ hIrq, uint32_t uPrioGrp, uint8_t uIrq, bool fAssert) 231 | { 232 | PPSPIRQINT pThis = hIrq; 233 | 234 | if ( uPrioGrp < ELEMENTS(pThis->abmGrpDev) 235 | && uIrq < sizeof(uint32_t) * 8) 236 | { 237 | /** @todo Check somehow whether interrupts are level or rising edge triggered. 238 | * For now we assume that interrupts are triggered on the rising edge as this 239 | * makes the most sense with how the interrupt handlers we've seen process interrupts so far. 240 | */ 241 | if ( !(pThis->abmGrpDevLast[uPrioGrp] & BIT(uIrq)) 242 | && fAssert) 243 | { 244 | if (!pThis->abmGrpDev[uPrioGrp]) 245 | pThis->cGrpPending++; 246 | 247 | pThis->abmGrpDevLast[uPrioGrp] |= BIT(uIrq); 248 | pThis->abmGrpDev[uPrioGrp] |= BIT(uIrq); 249 | if (pThis->cGrpPending == 1) 250 | { 251 | PSPEmuTraceEvtAddString(NULL, PSPTRACEEVTSEVERITY_INFO, PSPTRACEEVTORIGIN_IRQ, 252 | "Asserting IRQ caused by idPrio=%u idDev=%u\n", uPrioGrp, uIrq); 253 | PSPEmuCoreIrqSet(pThis->hPspCore, true /*fAssert*/); 254 | } 255 | } 256 | else if (!fAssert) 257 | pThis->abmGrpDevLast[uPrioGrp] &= ~BIT(uIrq); 258 | 259 | return STS_INF_SUCCESS; 260 | } 261 | 262 | return STS_ERR_INVALID_PARAMETER; 263 | } 264 | -------------------------------------------------------------------------------- /psp-profile.c: -------------------------------------------------------------------------------- 1 | /** @file 2 | * PSP Emulator - PSP profile management. 3 | */ 4 | 5 | /* 6 | * Copyright (C) 2020 Alexander Eichner 7 | * 8 | * This program is free software: you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License as published by 10 | * the Free Software Foundation, version 3. 11 | * 12 | * This program is distributed in the hope that it will be useful, but 13 | * WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 | * General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with this program. If not, see . 19 | */ 20 | /********************************************************************************************************************************* 21 | * Header Files * 22 | *********************************************************************************************************************************/ 23 | 24 | #include 25 | 26 | #include 27 | 28 | #include 29 | 30 | 31 | /********************************************************************************************************************************* 32 | * Structures and Typedefs * 33 | *********************************************************************************************************************************/ 34 | 35 | /** Ranges block in proxy mode get included here. */ 36 | #include "profiles/proxy-blocked-range-std.h" 37 | 38 | 39 | /* PSP profiles get included here first. */ 40 | #include "profiles/amd-psp-zen.h" 41 | #include "profiles/amd-psp-zen-plus.h" 42 | #include "profiles/amd-psp-zen-2.h" 43 | #include "profiles/amd-psp-zen-3.h" 44 | 45 | 46 | /* CPU profiles get included here.*/ 47 | #include "profiles/amd-cpu-zen-synthetic.h" 48 | #include "profiles/amd-cpu-ryzen7-1800x.h" 49 | #include "profiles/amd-cpu-ryzen5-5600x.h" 50 | 51 | 52 | /********************************************************************************************************************************* 53 | * Global Variables * 54 | *********************************************************************************************************************************/ 55 | 56 | /** 57 | * Supported PSP profiles. 58 | */ 59 | static PCPSPPROFILE g_aPspProfiles[] = 60 | { 61 | &g_PspProfileZen, 62 | &g_PspProfileZenPlus, 63 | &g_PspProfileZen2, 64 | &g_PspProfileZen3 65 | }; 66 | 67 | 68 | /** 69 | * Supported CPU profiles. 70 | */ 71 | static PCPSPAMDCPUPROFILE g_aCpuProfiles[] = 72 | { 73 | &g_AmdCpu_Zen_Synthetic, 74 | &g_AmdCpu_Ryzen7_1800X, 75 | &g_AmdCpu_Ryzen5_5600X 76 | }; 77 | 78 | 79 | /********************************************************************************************************************************* 80 | * Internal Functions * 81 | *********************************************************************************************************************************/ 82 | 83 | PCPSPPROFILE PSPProfilePspGetById(const char *pszId) 84 | { 85 | for (uint32_t i = 0; i < ELEMENTS(g_aPspProfiles); i++) 86 | { 87 | if (!strcmp(g_aPspProfiles[i]->pszId, pszId)) 88 | return g_aPspProfiles[i]; 89 | } 90 | 91 | return NULL; 92 | } 93 | 94 | 95 | PCPSPAMDCPUPROFILE PSPProfileAmdCpuGetById(const char *pszId) 96 | { 97 | for (uint32_t i = 0; i < ELEMENTS(g_aCpuProfiles); i++) 98 | { 99 | if (!strcmp(g_aCpuProfiles[i]->pszId, pszId)) 100 | return g_aCpuProfiles[i]; 101 | } 102 | 103 | return NULL; 104 | } 105 | 106 | 107 | PCPSPAMDCPUPROFILE PSPProfileAmdCpuGetDefault(void) 108 | { 109 | return &g_AmdCpu_Zen_Synthetic; 110 | } 111 | 112 | --------------------------------------------------------------------------------