psptool 3.2.dev1__tar.gz → 3.4__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {psptool-3.2.dev1 → psptool-3.4}/.github/workflows/gha-metrics.yml +1 -0
- {psptool-3.2.dev1 → psptool-3.4}/.github/workflows/publish.yml +0 -23
- {psptool-3.2.dev1 → psptool-3.4}/.github/workflows/python-tests.yml +2 -1
- {psptool-3.2.dev1 → psptool-3.4}/PKG-INFO +1 -1
- {psptool-3.2.dev1 → psptool-3.4}/psptool/__main__.py +2 -2
- {psptool-3.2.dev1 → psptool-3.4}/psptool/blob.py +3 -10
- {psptool-3.2.dev1 → psptool-3.4}/psptool/directory.py +33 -0
- {psptool-3.2.dev1 → psptool-3.4}/psptool/fet.py +4 -10
- {psptool-3.2.dev1 → psptool-3.4}/psptool/file.py +2 -1
- {psptool-3.2.dev1 → psptool-3.4}/psptool/header_file.py +1 -1
- {psptool-3.2.dev1 → psptool-3.4}/.gitignore +0 -0
- {psptool-3.2.dev1 → psptool-3.4}/.gitmodules +0 -0
- {psptool-3.2.dev1 → psptool-3.4}/LICENSE +0 -0
- {psptool-3.2.dev1 → psptool-3.4}/README.md +0 -0
- {psptool-3.2.dev1 → psptool-3.4}/psptool/__init__.py +0 -0
- {psptool-3.2.dev1 → psptool-3.4}/psptool/cert_tree.py +0 -0
- {psptool-3.2.dev1 → psptool-3.4}/psptool/crypto.py +0 -0
- {psptool-3.2.dev1 → psptool-3.4}/psptool/entry.py +0 -0
- {psptool-3.2.dev1 → psptool-3.4}/psptool/errors.py +0 -0
- {psptool-3.2.dev1 → psptool-3.4}/psptool/firmware.py +0 -0
- {psptool-3.2.dev1 → psptool-3.4}/psptool/key_store_file.py +0 -0
- {psptool-3.2.dev1 → psptool-3.4}/psptool/microcode_file.py +0 -0
- {psptool-3.2.dev1 → psptool-3.4}/psptool/psptool.py +0 -0
- {psptool-3.2.dev1 → psptool-3.4}/psptool/pubkey_file.py +0 -0
- {psptool-3.2.dev1 → psptool-3.4}/psptool/rom.py +0 -0
- {psptool-3.2.dev1 → psptool-3.4}/psptool/utils.py +0 -0
- {psptool-3.2.dev1 → psptool-3.4}/pyproject.toml +0 -0
- {psptool-3.2.dev1 → psptool-3.4}/tests/__init__.py +0 -0
- {psptool-3.2.dev1 → psptool-3.4}/tests/create_metrics.sh +0 -0
- {psptool-3.2.dev1 → psptool-3.4}/tests/gha_metrics.py +0 -0
- {psptool-3.2.dev1 → psptool-3.4}/tests/integration/__init__.py +0 -0
- {psptool-3.2.dev1 → psptool-3.4}/tests/integration/test_psptrace.py +0 -0
- {psptool-3.2.dev1 → psptool-3.4}/tests/integration/test_rom_files.py +0 -0
- {psptool-3.2.dev1 → psptool-3.4}/tests/metrics.txt +0 -0
- {psptool-3.2.dev1 → psptool-3.4}/tests/unit/__init__.py +0 -0
- {psptool-3.2.dev1 → psptool-3.4}/tests/unit/test_cli.py +0 -0
|
@@ -49,26 +49,3 @@ jobs:
|
|
|
49
49
|
path: dist/
|
|
50
50
|
- name: Publish distribution to PyPI
|
|
51
51
|
uses: pypa/gh-action-pypi-publish@release/v1
|
|
52
|
-
|
|
53
|
-
publish-to-testpypi:
|
|
54
|
-
name: >-
|
|
55
|
-
Publish Python distribution to TestPyPI
|
|
56
|
-
needs:
|
|
57
|
-
- build
|
|
58
|
-
runs-on: ubuntu-latest
|
|
59
|
-
environment:
|
|
60
|
-
name: testpypi
|
|
61
|
-
url: https://test.pypi.org/p/psptool/
|
|
62
|
-
permissions:
|
|
63
|
-
id-token: write # important for trusted publishing
|
|
64
|
-
steps:
|
|
65
|
-
- name: Download all the dists
|
|
66
|
-
uses: actions/download-artifact@v4
|
|
67
|
-
with:
|
|
68
|
-
name: python-package-distributions
|
|
69
|
-
path: dist/
|
|
70
|
-
- name: Publish distribution to TestPyPI
|
|
71
|
-
uses: pypa/gh-action-pypi-publish@release/v1
|
|
72
|
-
with:
|
|
73
|
-
repository-url: https://test.pypi.org/legacy/
|
|
74
|
-
verbose: true
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
name: Python tests
|
|
2
2
|
|
|
3
|
-
on: [push]
|
|
3
|
+
on: [push, pull_request_target]
|
|
4
4
|
|
|
5
5
|
jobs:
|
|
6
6
|
test:
|
|
@@ -13,6 +13,7 @@ jobs:
|
|
|
13
13
|
steps:
|
|
14
14
|
- uses: actions/checkout@v3
|
|
15
15
|
with:
|
|
16
|
+
ref: ${{ github.event_name == 'pull_request_target' && github.event.pull_request.head.sha || github.sha }}
|
|
16
17
|
submodules: recursive
|
|
17
18
|
ssh-key: ${{ secrets.PSPTOOL_FIXTURES_NEW_PRIVATE_KEY }}
|
|
18
19
|
- name: Set up Python ${{ matrix.python-version }}
|
|
@@ -193,7 +193,7 @@ def main():
|
|
|
193
193
|
if args.decompress and type(file) is HeaderFile:
|
|
194
194
|
out_bytes = file.get_signed_bytes()
|
|
195
195
|
elif args.decrypt and type(file) is HeaderFile:
|
|
196
|
-
out_bytes = file.
|
|
196
|
+
out_bytes = file.get_decrypted_body()
|
|
197
197
|
elif args.pem_key and type(file) is PubkeyFile:
|
|
198
198
|
out_bytes = file.get_pem_encoded()
|
|
199
199
|
else:
|
|
@@ -216,7 +216,7 @@ def main():
|
|
|
216
216
|
if args.decompress and type(file) is HeaderFile:
|
|
217
217
|
out_bytes = file.get_signed_bytes()
|
|
218
218
|
elif args.decrypt and type(file) is HeaderFile:
|
|
219
|
-
out_bytes = file.
|
|
219
|
+
out_bytes = file.get_decrypted_body()
|
|
220
220
|
elif args.pem_key and type(file) is PubkeyFile:
|
|
221
221
|
out_bytes = file.get_pem_encoded()
|
|
222
222
|
else:
|
|
@@ -179,13 +179,6 @@ class Blob(NestedBuffer):
|
|
|
179
179
|
found_pkes += self._find_inline_pubkeys(key_id)
|
|
180
180
|
return found_pkes
|
|
181
181
|
|
|
182
|
-
def
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
for rom in self.roms:
|
|
186
|
-
for _dir in rom.directories:
|
|
187
|
-
for entry in _dir.entries:
|
|
188
|
-
if entry.type == type_:
|
|
189
|
-
entries.append(entry)
|
|
190
|
-
|
|
191
|
-
return entries
|
|
182
|
+
def get_files_by_type(self, type_) -> List[File]:
|
|
183
|
+
all_files = self.unique_files()
|
|
184
|
+
return list(filter(lambda f: f.type == type_, all_files))
|
|
@@ -31,6 +31,22 @@ class Directory(NestedBuffer):
|
|
|
31
31
|
ENTRY_SIZE = DirectoryEntry.ENTRY_SIZE
|
|
32
32
|
FILE_CLASS = File
|
|
33
33
|
|
|
34
|
+
ZEN_GENERATION_IDS = {'Zen 1' : [b'\x00\x09\xBC', b'\x00\x0A\xBC'],
|
|
35
|
+
'Zen 2' : [b'\x05\x0B\xBC', b'\x01\x0A\xBC'],
|
|
36
|
+
'Zen 3' : [b'\x01\x0C\xBC', b'\x00\x0C\xBC'],
|
|
37
|
+
'Zen 4' : [b'\x04\x0D\xBC', b'\x0B\x0D\xBC'],
|
|
38
|
+
'Zen 4/5': [b'\x03\x0D\xBC']
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
@classmethod
|
|
42
|
+
def get_possible_zen_generation(cls, zen_generation_id):
|
|
43
|
+
zen_generation = 'unknown'
|
|
44
|
+
for possible_zen_generation in cls.ZEN_GENERATION_IDS:
|
|
45
|
+
if zen_generation_id in cls.ZEN_GENERATION_IDS[possible_zen_generation]:
|
|
46
|
+
zen_generation = possible_zen_generation
|
|
47
|
+
|
|
48
|
+
return zen_generation
|
|
49
|
+
|
|
34
50
|
class ParseError(Exception):
|
|
35
51
|
pass
|
|
36
52
|
|
|
@@ -43,6 +59,7 @@ class Directory(NestedBuffer):
|
|
|
43
59
|
# Recursively return or create and return found directories
|
|
44
60
|
|
|
45
61
|
if offset in fet.psptool.directories_by_offset:
|
|
62
|
+
fet.psptool.directories_by_offset[offset].update_zen_generation(fet, zen_generation)
|
|
46
63
|
return [fet.psptool.directories_by_offset[offset]]
|
|
47
64
|
else:
|
|
48
65
|
# 1. Create the immediate directory in front of us
|
|
@@ -69,6 +86,14 @@ class Directory(NestedBuffer):
|
|
|
69
86
|
for tertiary_directory_offset in directory.tertiary_directory_offsets:
|
|
70
87
|
directory_body = fet.rom.get_bytes(tertiary_directory_offset, 32)
|
|
71
88
|
actual_tertiary_offset = int.from_bytes(directory_body[16:20], 'little')
|
|
89
|
+
zen_generation_id = directory_body[21:24]
|
|
90
|
+
zen_generation = cls.get_possible_zen_generation(zen_generation_id)
|
|
91
|
+
if zen_generation == 'unknown':
|
|
92
|
+
fet.psptool.ph.print_warning(f"Unknown {zen_generation_id=}")
|
|
93
|
+
|
|
94
|
+
zen_generation_id = hex(int.from_bytes(directory_body[20:24], 'little'))
|
|
95
|
+
zen_generation += f' (PSP ID {zen_generation_id})'
|
|
96
|
+
|
|
72
97
|
# Resolve one more indirection
|
|
73
98
|
tertiary_directories = cls.create_directories_if_not_exist(actual_tertiary_offset, fet, zen_generation)
|
|
74
99
|
created_directories += tertiary_directories
|
|
@@ -198,6 +223,14 @@ class Directory(NestedBuffer):
|
|
|
198
223
|
# 3. Update checksum
|
|
199
224
|
self.update_checksum()
|
|
200
225
|
|
|
226
|
+
def update_zen_generation(self, fet, zen_generation):
|
|
227
|
+
if zen_generation is not None:
|
|
228
|
+
if zen_generation not in self.zen_generation:
|
|
229
|
+
self.zen_generation += '\n' + zen_generation
|
|
230
|
+
for offset in self.secondary_directory_offsets:
|
|
231
|
+
dir = fet.psptool.directories_by_offset[offset]
|
|
232
|
+
dir.update_zen_generation(fet, zen_generation)
|
|
233
|
+
|
|
201
234
|
|
|
202
235
|
class BiosDirectory(Directory):
|
|
203
236
|
DIRECTORY_MAGICS = [b'$BHD', b'$BL2']
|
|
@@ -19,12 +19,6 @@ from .directory import Directory
|
|
|
19
19
|
|
|
20
20
|
from typing import List
|
|
21
21
|
|
|
22
|
-
|
|
23
|
-
ZEN_GENERATION_IDS = {'Zen 1': [b'\x00\x09\xBC', b'\x00\x0A\xBC'],
|
|
24
|
-
'Zen 2': [b'\x05\x0B\xBC', b'\x01\x0A\xBC'],
|
|
25
|
-
'Zen 3': [b'\x01\x0C\xBC', b'\x00\x0C\xBC']}
|
|
26
|
-
|
|
27
|
-
|
|
28
22
|
class EmptyFet(Exception):
|
|
29
23
|
pass
|
|
30
24
|
|
|
@@ -121,13 +115,13 @@ class Fet(NestedBuffer):
|
|
|
121
115
|
|
|
122
116
|
# entry_addr += self.blob_offset
|
|
123
117
|
zen_generation_id = combo_dir[i*16+5:i*16+8]
|
|
124
|
-
zen_generation =
|
|
125
|
-
for possible_zen_generation in ZEN_GENERATION_IDS:
|
|
126
|
-
if zen_generation_id in ZEN_GENERATION_IDS[possible_zen_generation]:
|
|
127
|
-
zen_generation = possible_zen_generation
|
|
118
|
+
zen_generation = Directory.get_possible_zen_generation(zen_generation_id)
|
|
128
119
|
if zen_generation == 'unknown':
|
|
129
120
|
self.psptool.ph.print_warning(f"Unknown {zen_generation_id=}")
|
|
130
121
|
|
|
122
|
+
zen_generation_id = hex(int.from_bytes(combo_dir[i*16+4:i*16+8], byteorder='little'))
|
|
123
|
+
zen_generation += f' (PSP ID {zen_generation_id})'
|
|
124
|
+
|
|
131
125
|
results.append((entry_addr, zen_generation))
|
|
132
126
|
|
|
133
127
|
return results
|
|
@@ -229,6 +229,7 @@ class File(NestedBuffer):
|
|
|
229
229
|
0x6F: 'OEM_LOGO_IMAGE',
|
|
230
230
|
0x77: 'DDRPHY_PCU_FW',
|
|
231
231
|
0x7B: 'MPRAS_TRUSTRED_APP_IMG',
|
|
232
|
+
0x7C: 'OC_SWEET_SPOT_PROFILE',
|
|
232
233
|
}
|
|
233
234
|
|
|
234
235
|
PUBKEY_ENTRY_TYPES = [0x0, 0x9, 0xa, 0x5, 0xd, 0x43, 0x4e, 0x53, 0x81, 0x97, 0xad ]
|
|
@@ -237,7 +238,7 @@ class File(NestedBuffer):
|
|
|
237
238
|
# TODO: Find a better way to identify those entries
|
|
238
239
|
NO_HDR_ENTRY_TYPES = [0x4, 0xb, 0x21, 0x40, 0x48, 0x49, 0x4a, 0x70, 0x6, 0x61, 0x60, 0x68, 0x5f,
|
|
239
240
|
0x1a, 0x22, 0x63, 0x67, 0x66, 0x6d, 0x62, 0x61, 0x7, 0x38, 0x46, 0x54,
|
|
240
|
-
0x82, 0x84, 0x8d, 0x69 ]
|
|
241
|
+
0x82, 0x84, 0x8d, 0x69, 0x7c, 0x98 ]
|
|
241
242
|
|
|
242
243
|
NO_SIZE_ENTRY_TYPES = [0xb]
|
|
243
244
|
KEY_STORE_TYPES = [0x50, 0x51]
|
|
@@ -132,7 +132,7 @@ class HeaderFile(File):
|
|
|
132
132
|
return '.'.join([hex(b)[2:].upper() for b in self.version])
|
|
133
133
|
|
|
134
134
|
def get_ikek_md5sum(self) -> bytes:
|
|
135
|
-
ikek = self.parent_buffer.
|
|
135
|
+
ikek = self.parent_buffer.get_files_by_type(0x21)[0]
|
|
136
136
|
m = md5()
|
|
137
137
|
m.update(ikek.get_bytes())
|
|
138
138
|
return m.digest()
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|