mirror of
https://github.com/Pharaoh2k/ps5debug-NG.git
synced 2026-10-23 04:12:42 -05:00
v1.2.8: bulk write CMD 0xBDAACC04 + branding capability level "1.0"
- New 0xBDAACC04 bulk-write command (proc.c proc_write_multi_handle), dispatched
raw (no name macro). Collapses N CMD_PROC_WRITE round-trips into one: header
{pid,count,flags} then count streamed {u64 addr,u32 len,bytes} entries; two
CMD_SUCCESS words. Interleaved streaming keeps server memory bounded to one
64KiB scratch. Not auth-gated (mirrors single write). Caps: count<=0xFFFF,
entry<=0x100000 -> CMD_ERROR + abort. Opt-in per-entry status byte array via
flags bit 0 (PROC_WRITE_MULTI_F_STATUS), using a returning proc_write_mem
variant (ptwalk ret + mdbg bytes-written); single write + breakpoint callers
untouched.
- CMD_BRANDING (meta.c) now returns brand + NUL + capability level "1.0" so
capability-aware clients gate features without probing. Split literal
"\0" "1.0" (not octal \01).
- version.h 1.2.7 -> 1.2.8. PROTOCOL.md documents both.
HW-validated (wire test). Sources not yet comment-stripped (pre-push step).
This commit is contained in:
1 parent
f8456241fc
commit
fedbd4f6d7
6 files changed
+159
-7
No files matched your search
+34
-4
@@ -20,7 +20,7 @@ This document reflects `ps5debug-NG v1.2.6` (`common/include/version.h`,
|
||||
| Symbol | Value | Source |
|
||||
|--------------------|----------------------------------|----------------------------------------------------------|
|
||||
| protocol version | `"1.3"` | `meta.c` `handle_version` (local `char ver[]="1.3"`) |
|
||||
| branding string | `"ps5debug-NG by OSR v1.2.6"` | `version.h` `PS5DEBUG_NG_BRAND_STR` via `meta.c` `handle_branding` |
|
||||
| branding string | `"ps5debug-NG by OSR v1.2.8\01.0"` | `version.h` `PS5DEBUG_NG_BRAND_STR` via `meta.c` `handle_branding` (NUL-separated capability level appended - see 2.1) |
|
||||
| `PACKET_MAGIC` | `0xFFAABBCC` | `main.c:50` (local `#define`) |
|
||||
| broadcast magic | `0xFFFFAAAA` | `main.c` `broadcast_thread` (raw literal) |
|
||||
| auth magic | `0xBB40E64D` | `protocol.h:249` (`CMD_PROC_AUTH_MAGIC`) |
|
||||
@@ -223,9 +223,17 @@ per-namespace `switch` statements. Three opcodes have no symbolic name at all:
|
||||
|
||||
#### `CMD_BRANDING = 0xBD000501`
|
||||
- **Request body:** none.
|
||||
- **Response:** `uint32_t length`, then `length` bytes of the branding string
|
||||
("ps5debug-NG by OSR v1.2.6"). No status word precedes it. (The client calls
|
||||
this `CMD_EXT_VERSION`.)
|
||||
- **Response:** `uint32_t length`, then `length` bytes: the human branding string
|
||||
(`"ps5debug-NG by OSR v1.2.8"`), a single `NUL`, then a **capability level**
|
||||
string (`"1.0"`), with no trailing NUL. No status word precedes it. (The client
|
||||
calls this `CMD_EXT_VERSION`.)
|
||||
- **Capability level:** C-string clients read up to the first `NUL` and see only
|
||||
the unchanged brand; capability-aware clients read the bytes past the `NUL` to
|
||||
get the level. The level is bumped as the server gains negotiable features (so a
|
||||
client can gate a feature on the server advertising at least a given level).
|
||||
Built from `PS5DEBUG_NG_BRAND_STR "\0" "1.0"` in `meta.c` `handle_branding` -
|
||||
the literals are split (`"\0" "1.0"`) so `\0` is a NUL byte, not the octal
|
||||
escape `\01`.
|
||||
|
||||
#### `CMD_PLATFORM_ID = 0xBD000502`
|
||||
- **Request body:** none.
|
||||
@@ -260,6 +268,28 @@ data" is read from the socket by the handler after a leading `CMD_SUCCESS`.
|
||||
`length` bytes in 64 KiB chunks, then `CMD_SUCCESS` again. **Two** status
|
||||
words (see 8).
|
||||
|
||||
#### `0xBDAACC04` (`proc_write_multi_handle`)
|
||||
Bulk write - the write counterpart to `0xBDAACC03` (bulk read). Collapses a
|
||||
freeze / multi-poke loop of N single `CMD_PROC_WRITE`s into one exchange. Dispatched
|
||||
by `proc_handle`; **not** auth-gated (mirrors single write).
|
||||
- **Request body:** `struct cmd_proc_write_multi_packet` (12 bytes,
|
||||
`{ uint32_t pid; uint32_t count; uint32_t flags; }`). `flags` bit 0
|
||||
(`PROC_WRITE_MULTI_F_STATUS`) requests a per-entry status array in the response.
|
||||
- **Trailing data:** after the server's first `CMD_SUCCESS`, the client streams
|
||||
`count` entries, each `{ uint64_t address; uint32_t length; <length> bytes data }`
|
||||
concatenated. Per-entry `length` is capped at `0x100000`; `count` at `0xFFFF`.
|
||||
- **Response:** `CMD_SUCCESS` (ack), then the server reads and applies each entry
|
||||
(writing via the same DMAP / mdbg path as `CMD_PROC_WRITE`, in 64 KiB chunks).
|
||||
If `flags` bit 0 was set, it then sends a `count`-byte status array (one byte per
|
||||
entry, `0` = ok, `1` = write failed). Finally a trailing `CMD_SUCCESS`. **Two**
|
||||
status words, plus the optional status array between them.
|
||||
- **Semantics:** best-effort and non-atomic - entries are applied in order and a
|
||||
failed entry does not stop the rest. Without the status flag, individual write
|
||||
failures are not reported (same as single `CMD_PROC_WRITE`, whose underlying
|
||||
`proc_write_mem` is `void`). A `count`/`length` cap violation makes the server
|
||||
reply `CMD_ERROR` and abort the command (the connection's stream is then
|
||||
untrustworthy; well-behaved clients stay within the caps).
|
||||
|
||||
#### `CMD_PROC_MAPS = 0xBDAA0004` (`proc.c:597`)
|
||||
- **Request body:** `struct cmd_proc_maps_packet` (4 bytes, `pid`).
|
||||
- **Response:** `CMD_SUCCESS`, `uint32_t num`, then `num` x
|
||||
|
||||
@@ -13,6 +13,7 @@ int proc_list_handle(int fd, struct cmd_packet *packet);
|
||||
int proc_read_handle(int fd, struct cmd_packet *packet);
|
||||
int proc_read_stack_handle(int fd, struct cmd_packet *packet);
|
||||
int proc_write_handle(int fd, struct cmd_packet *packet);
|
||||
int proc_write_multi_handle(int fd, struct cmd_packet *packet);
|
||||
int proc_maps_handle(int fd, struct cmd_packet *packet);
|
||||
int proc_info_handle(int fd, struct cmd_packet *packet);
|
||||
int proc_protect_handle(int fd, struct cmd_packet *packet);
|
||||
|
||||
@@ -112,6 +112,19 @@ struct cmd_proc_write_packet {
|
||||
uint32_t length;
|
||||
} __attribute__((packed));
|
||||
|
||||
/* Bulk write / freeze batching (opcode 0xBDAACC04). Header body below is
|
||||
followed by `count` streamed entries, each { uint64 address; uint32 length;
|
||||
<length> bytes }. flags bit 0 asks the server for a per-entry status byte
|
||||
array (0 = ok) sent just before the trailing CMD_SUCCESS. */
|
||||
struct cmd_proc_write_multi_packet {
|
||||
uint32_t pid;
|
||||
uint32_t count;
|
||||
uint32_t flags;
|
||||
} __attribute__((packed));
|
||||
#define PROC_WRITE_MULTI_F_STATUS 0x1u
|
||||
#define PROC_WRITE_MULTI_MAX_COUNT 0xFFFFu
|
||||
#define PROC_WRITE_MULTI_MAX_ENTRY 0x100000u
|
||||
|
||||
struct cmd_proc_maps_packet {
|
||||
uint32_t pid;
|
||||
} __attribute__((packed));
|
||||
|
||||
@@ -2,5 +2,5 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#define PS5DEBUG_NG_VERSION_STR "1.2.7"
|
||||
#define PS5DEBUG_NG_VERSION_STR "1.2.8"
|
||||
#define PS5DEBUG_NG_BRAND_STR "ps5debug-NG by OSR v" PS5DEBUG_NG_VERSION_STR
|
||||
@@ -25,8 +25,13 @@ int handle_version(int fd, struct cmd_packet *packet) {
|
||||
|
||||
int handle_branding(int fd, struct cmd_packet *packet) {
|
||||
(void)packet;
|
||||
char brand[] = PS5DEBUG_NG_BRAND_STR;
|
||||
uint32_t len = (uint32_t)(sizeof(brand) - 1);
|
||||
/* Human brand, a NUL, then the capability LEVEL. C-string clients stop at the
|
||||
NUL so the displayed brand is unchanged; capability-aware clients read the
|
||||
level past it. NOTE: the literals are split ("\0" "1.0") on purpose - "\01.0"
|
||||
would be parsed as the octal escape \01, not a NUL followed by "1.0". Bump the
|
||||
level (and add the feature on the client) as new capabilities are added. */
|
||||
static const char brand[] = PS5DEBUG_NG_BRAND_STR "\0" "1.0";
|
||||
uint32_t len = (uint32_t)(sizeof(brand) - 1);
|
||||
net_send_all(fd, &len, sizeof(uint32_t));
|
||||
net_send_all(fd, brand, (int)len);
|
||||
return 0;
|
||||
|
||||
@@ -595,6 +595,108 @@ int proc_write_handle(int fd, struct cmd_packet *packet) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Like proc_write_mem but reports 0 on success / 1 on failure. Used only by
|
||||
the bulk-write handler so it can fill an optional per-entry status array;
|
||||
proc_write_mem and its breakpoint callers stay void. The signal is real:
|
||||
proc_ptwalk_write returns 0/1, and the mdbg fallback exposes bytes-written
|
||||
through its arg5 out-param (sys_proc_rw_inner sets it to length on success). */
|
||||
static int proc_write_mem_status(uint32_t pid, uint64_t addr, uint64_t len, const void *buf) {
|
||||
static int s_fw_needs_dmap = -1;
|
||||
if (s_fw_needs_dmap < 0)
|
||||
s_fw_needs_dmap = ((kernel_get_fw_version() & 0xffff0000u) >= 0x08400000u) ? 1 : 0;
|
||||
|
||||
if (s_fw_needs_dmap && proc_ptwalk_write(pid, addr, len, buf) == 0)
|
||||
return 0;
|
||||
|
||||
uint64_t wrote = 0;
|
||||
sys_proc_rw_w1((uint64_t)pid, addr, len, (void *)buf, (uint64_t)(uintptr_t)&wrote);
|
||||
return (wrote == len) ? 0 : 1;
|
||||
}
|
||||
|
||||
int proc_write_multi_handle(int fd, struct cmd_packet *packet) {
|
||||
struct cmd_proc_write_multi_packet *mp =
|
||||
(struct cmd_proc_write_multi_packet *)packet->data;
|
||||
if (!mp) {
|
||||
net_send_int32(fd, CMD_DATA_NULL);
|
||||
return 1;
|
||||
}
|
||||
|
||||
uint32_t pid = mp->pid;
|
||||
uint32_t count = mp->count;
|
||||
int want_status = (mp->flags & PROC_WRITE_MULTI_F_STATUS) ? 1 : 0;
|
||||
|
||||
if (count > PROC_WRITE_MULTI_MAX_COUNT) {
|
||||
net_send_int32(fd, CMD_ERROR);
|
||||
return 1;
|
||||
}
|
||||
|
||||
uint8_t *buf = (uint8_t *)net_alloc_buffer(0x10000);
|
||||
if (!buf) {
|
||||
net_send_int32(fd, CMD_DATA_NULL);
|
||||
return 1;
|
||||
}
|
||||
|
||||
uint8_t *status = NULL;
|
||||
if (want_status && count > 0) {
|
||||
status = (uint8_t *)net_alloc_buffer(count);
|
||||
if (!status) {
|
||||
free(buf);
|
||||
net_send_int32(fd, CMD_DATA_NULL);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
net_send_int32(fd, CMD_SUCCESS);
|
||||
|
||||
for (uint32_t i = 0; i < count; i++) {
|
||||
uint8_t hdr[12];
|
||||
if (net_recv_all(fd, hdr, 12, 1) < 0) {
|
||||
/* socket broken mid-stream; bail without further sends */
|
||||
if (status) free(status);
|
||||
free(buf);
|
||||
return 1;
|
||||
}
|
||||
uint64_t addr;
|
||||
uint32_t len32;
|
||||
memcpy(&addr, hdr, 8);
|
||||
memcpy(&len32, hdr + 8, 4);
|
||||
|
||||
if (len32 > PROC_WRITE_MULTI_MAX_ENTRY) {
|
||||
/* protocol violation: we can't know how many data bytes follow,
|
||||
so the stream is no longer trustworthy - abort the command. */
|
||||
if (status) free(status);
|
||||
free(buf);
|
||||
net_send_int32(fd, CMD_ERROR);
|
||||
return 1;
|
||||
}
|
||||
|
||||
uint64_t length = len32;
|
||||
uint64_t a = addr;
|
||||
uint8_t failed = 0;
|
||||
while (length > 0) {
|
||||
uint64_t to_recv = (length > 0x10000ULL) ? 0x10000ULL : length;
|
||||
if (net_recv_all(fd, buf, (int)to_recv, 1) < 0) {
|
||||
if (status) free(status);
|
||||
free(buf);
|
||||
return 1;
|
||||
}
|
||||
if (proc_write_mem_status(pid, a, to_recv, buf) != 0)
|
||||
failed = 1;
|
||||
a += to_recv;
|
||||
length -= to_recv;
|
||||
}
|
||||
if (status) status[i] = failed;
|
||||
}
|
||||
|
||||
if (status) {
|
||||
net_send_all(fd, status, (int)count);
|
||||
free(status);
|
||||
}
|
||||
net_send_int32(fd, CMD_SUCCESS);
|
||||
free(buf);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int proc_maps_handle(int fd, struct cmd_packet *packet) {
|
||||
|
||||
struct cmd_proc_maps_packet *mp = (struct cmd_proc_maps_packet *)packet->data;
|
||||
@@ -966,6 +1068,7 @@ int proc_handle(int fd, struct cmd_packet *packet, unsigned char client_idx) {
|
||||
case 0xBDAA0023u: return proc_read_stack_handle(fd, packet);
|
||||
case 0xBDAA0024u: return proc_assemble_handle(fd, packet);
|
||||
case 0xBDAA0003u: return proc_write_handle(fd, packet);
|
||||
case 0xBDAACC04u: return proc_write_multi_handle(fd, packet);
|
||||
case 0xBDAA0004u: return proc_maps_handle(fd, packet);
|
||||
case 0xBDAA0005u: return proc_install_handle(fd, packet);
|
||||
case 0xBDAA0006u: return proc_call_handle(fd, packet);
|
||||
|
||||
Reference in new issue
Block a user