psptool 3.1__tar.gz → 3.2.dev0__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.dev0/.github/workflows/gha-metrics.yml +33 -0
- psptool-3.2.dev0/.github/workflows/publish.yml +74 -0
- {psptool-3.1 → psptool-3.2.dev0}/PKG-INFO +7 -12
- {psptool-3.1 → psptool-3.2.dev0}/psptool/__main__.py +5 -0
- {psptool-3.1 → psptool-3.2.dev0}/psptool/blob.py +5 -1
- {psptool-3.1 → psptool-3.2.dev0}/psptool/directory.py +18 -16
- psptool-3.2.dev0/psptool/entry.py +180 -0
- {psptool-3.1 → psptool-3.2.dev0}/psptool/fet.py +16 -3
- {psptool-3.1 → psptool-3.2.dev0}/psptool/file.py +162 -42
- psptool-3.2.dev0/psptool/microcode_file.py +60 -0
- {psptool-3.1 → psptool-3.2.dev0}/psptool/psptool.py +30 -3
- psptool-3.2.dev0/pyproject.toml +21 -0
- psptool-3.2.dev0/tests/gha_metrics.py +80 -0
- {psptool-3.1 → psptool-3.2.dev0}/tests/metrics.txt +70 -70
- psptool-3.1/psptool/entry.py +0 -96
- psptool-3.1/psptool.egg-info/PKG-INFO +0 -877
- psptool-3.1/psptool.egg-info/SOURCES.txt +0 -38
- psptool-3.1/psptool.egg-info/dependency_links.txt +0 -1
- psptool-3.1/psptool.egg-info/entry_points.txt +0 -2
- psptool-3.1/psptool.egg-info/requires.txt +0 -2
- psptool-3.1/psptool.egg-info/top_level.txt +0 -1
- psptool-3.1/setup.cfg +0 -26
- psptool-3.1/setup.py +0 -13
- {psptool-3.1 → psptool-3.2.dev0}/.github/workflows/python-tests.yml +0 -0
- {psptool-3.1 → psptool-3.2.dev0}/.gitignore +0 -0
- {psptool-3.1 → psptool-3.2.dev0}/.gitmodules +0 -0
- {psptool-3.1 → psptool-3.2.dev0}/LICENSE +0 -0
- {psptool-3.1 → psptool-3.2.dev0}/README.md +0 -0
- {psptool-3.1 → psptool-3.2.dev0}/psptool/__init__.py +0 -0
- {psptool-3.1 → psptool-3.2.dev0}/psptool/cert_tree.py +0 -0
- {psptool-3.1 → psptool-3.2.dev0}/psptool/crypto.py +0 -0
- {psptool-3.1 → psptool-3.2.dev0}/psptool/errors.py +0 -0
- {psptool-3.1 → psptool-3.2.dev0}/psptool/firmware.py +0 -0
- {psptool-3.1 → psptool-3.2.dev0}/psptool/header_file.py +0 -0
- {psptool-3.1 → psptool-3.2.dev0}/psptool/key_store_file.py +0 -0
- {psptool-3.1 → psptool-3.2.dev0}/psptool/pubkey_file.py +0 -0
- {psptool-3.1 → psptool-3.2.dev0}/psptool/rom.py +0 -0
- {psptool-3.1 → psptool-3.2.dev0}/psptool/utils.py +0 -0
- {psptool-3.1 → psptool-3.2.dev0}/tests/__init__.py +0 -0
- {psptool-3.1 → psptool-3.2.dev0}/tests/create_metrics.sh +0 -0
- {psptool-3.1 → psptool-3.2.dev0}/tests/integration/__init__.py +0 -0
- {psptool-3.1 → psptool-3.2.dev0}/tests/integration/test_psptrace.py +0 -0
- {psptool-3.1 → psptool-3.2.dev0}/tests/integration/test_rom_files.py +0 -0
- {psptool-3.1 → psptool-3.2.dev0}/tests/unit/__init__.py +0 -0
- {psptool-3.1 → psptool-3.2.dev0}/tests/unit/test_cli.py +0 -0
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
name: Post metrics comment
|
|
2
|
+
|
|
3
|
+
on: [pull_request_target]
|
|
4
|
+
|
|
5
|
+
jobs:
|
|
6
|
+
test:
|
|
7
|
+
|
|
8
|
+
runs-on: ubuntu-latest
|
|
9
|
+
strategy:
|
|
10
|
+
matrix:
|
|
11
|
+
python-version: ["3.9"]
|
|
12
|
+
|
|
13
|
+
steps:
|
|
14
|
+
- uses: actions/checkout@v3
|
|
15
|
+
with:
|
|
16
|
+
submodules: recursive
|
|
17
|
+
ssh-key: ${{ secrets.PSPTOOL_FIXTURES_NEW_PRIVATE_KEY }}
|
|
18
|
+
- name: Set up Python ${{ matrix.python-version }}
|
|
19
|
+
uses: actions/setup-python@v3
|
|
20
|
+
with:
|
|
21
|
+
python-version: ${{ matrix.python-version }}
|
|
22
|
+
- name: Install dependencies
|
|
23
|
+
run: |
|
|
24
|
+
python -m pip install --upgrade pip
|
|
25
|
+
pip install .
|
|
26
|
+
- name: Run metrics and post comment
|
|
27
|
+
run: |
|
|
28
|
+
python tests/gha_metrics.py > metrics.md
|
|
29
|
+
gh pr comment $PRNUM --body-file metrics.md
|
|
30
|
+
env:
|
|
31
|
+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
32
|
+
GH_REPO: ${{ github.repository }}
|
|
33
|
+
PRNUM: ${{ github.event.pull_request.number }}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
name: Publish Python distribution to PyPI and TestPyPI
|
|
2
|
+
|
|
3
|
+
on: push
|
|
4
|
+
|
|
5
|
+
jobs:
|
|
6
|
+
build:
|
|
7
|
+
name: Build distribution
|
|
8
|
+
runs-on: ubuntu-latest
|
|
9
|
+
|
|
10
|
+
steps:
|
|
11
|
+
- uses: actions/checkout@v4
|
|
12
|
+
with:
|
|
13
|
+
persist-credentials: false
|
|
14
|
+
- name: Set up Python
|
|
15
|
+
uses: actions/setup-python@v5
|
|
16
|
+
with:
|
|
17
|
+
python-version: "3.11"
|
|
18
|
+
- name: Install pypa/build
|
|
19
|
+
run: >-
|
|
20
|
+
python3 -m
|
|
21
|
+
pip install
|
|
22
|
+
build
|
|
23
|
+
--user
|
|
24
|
+
- name: Build a binary wheel and a source tarball
|
|
25
|
+
run: python3 -m build
|
|
26
|
+
- name: Store the distribution packages
|
|
27
|
+
uses: actions/upload-artifact@v4
|
|
28
|
+
with:
|
|
29
|
+
name: python-package-distributions
|
|
30
|
+
path: dist/
|
|
31
|
+
|
|
32
|
+
publish-to-pypi:
|
|
33
|
+
name: >-
|
|
34
|
+
Publish Python distribution to PyPI
|
|
35
|
+
if: startsWith(github.ref, 'refs/tags') # only publish on tag push
|
|
36
|
+
needs:
|
|
37
|
+
- build
|
|
38
|
+
runs-on: ubuntu-latest
|
|
39
|
+
environment:
|
|
40
|
+
name: pypi
|
|
41
|
+
url: https://pypi.org/p/psptool/
|
|
42
|
+
permissions:
|
|
43
|
+
id-token: write # important for trusted publishing
|
|
44
|
+
steps:
|
|
45
|
+
- name: Download all the dists
|
|
46
|
+
uses: actions/download-artifact@v4
|
|
47
|
+
with:
|
|
48
|
+
name: python-package-distributions
|
|
49
|
+
path: dist/
|
|
50
|
+
- name: Publish distribution to PyPI
|
|
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,18 +1,13 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
2
|
Name: psptool
|
|
3
|
-
Version: 3.
|
|
3
|
+
Version: 3.2.dev0
|
|
4
4
|
Summary: PSPTool is a tool for dealing with AMD binary blobs
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
Author-email: cwerling@posteo.de
|
|
8
|
-
Classifier: Development Status :: 4 - Beta
|
|
9
|
-
Classifier: Intended Audience :: Science/Research
|
|
10
|
-
Classifier: Topic :: Security
|
|
11
|
-
Classifier: License :: OSI Approved :: GNU General Public License v3 (GPLv3)
|
|
12
|
-
Classifier: Programming Language :: Python :: 3.8
|
|
5
|
+
Author-email: Christian Werling <cwerling@posteo.de>
|
|
6
|
+
License-File: LICENSE
|
|
13
7
|
Requires-Python: >=3.8
|
|
8
|
+
Requires-Dist: cryptography>=38.0.0
|
|
9
|
+
Requires-Dist: prettytable
|
|
14
10
|
Description-Content-Type: text/markdown
|
|
15
|
-
License-File: LICENSE
|
|
16
11
|
|
|
17
12
|
# PSPTool
|
|
18
13
|
|
|
@@ -874,4 +869,4 @@ b'\x01\x00\x00\x00\x1b\xb9\x87\xc3YIF\x06\xb1t\x94V\x01\xc9\xea[\x1b\xb9\x87\xc3
|
|
|
874
869
|
> psp.blob.roms[0].directories[0].files[1].move_buffer(0x60000, 0x1000)
|
|
875
870
|
> psp.blob.roms[0].set_bytes(0x60000, 0x1000, my_stuff)
|
|
876
871
|
> psp.to_file('my_modified_bios.bin')
|
|
877
|
-
```
|
|
872
|
+
```
|
|
@@ -200,6 +200,11 @@ def main():
|
|
|
200
200
|
out_bytes = file.get_bytes()
|
|
201
201
|
|
|
202
202
|
outpath = outdir + '/d%.2d_e%.2d_%s' % (dir_index, file_index, file.get_readable_type())
|
|
203
|
+
|
|
204
|
+
# We may have same file types but different subprograms, instances
|
|
205
|
+
# Account for it in the filenames
|
|
206
|
+
if file.entry.subprogram != 0 or file.entry.instance != 0:
|
|
207
|
+
outpath += f'_SUB_{hex(file.entry.subprogram)}_INS_{hex(file.entry.instance)}'
|
|
203
208
|
if type(file) is HeaderFile:
|
|
204
209
|
outpath += f'_{file.get_readable_version()}'
|
|
205
210
|
|
|
@@ -67,7 +67,11 @@ class Blob(NestedBuffer):
|
|
|
67
67
|
continue
|
|
68
68
|
try:
|
|
69
69
|
rom_offset = fet_location - fet_offset # e.g. 0x20800 - 0x20000 = 0x0800
|
|
70
|
-
|
|
70
|
+
# W/A for images with single ROMs that have entries crossing 16MB boundary
|
|
71
|
+
if rom_page == 0:
|
|
72
|
+
potential_rom = Rom(self, rom_size, rom_offset, fet_offset, psptool)
|
|
73
|
+
else:
|
|
74
|
+
potential_rom = Rom(self, min(rom_size, self._MAX_PAGE_SIZE), rom_offset, fet_offset, psptool)
|
|
71
75
|
self.roms.append(potential_rom)
|
|
72
76
|
fet_parsed = True
|
|
73
77
|
break # found correct fet_offset!
|
|
@@ -31,10 +31,6 @@ class Directory(NestedBuffer):
|
|
|
31
31
|
ENTRY_SIZE = DirectoryEntry.ENTRY_SIZE
|
|
32
32
|
FILE_CLASS = File
|
|
33
33
|
|
|
34
|
-
# all directories by offset in rom
|
|
35
|
-
# todo: what if we have multi-ROM? then two ROMs share this singleton!
|
|
36
|
-
directories_by_offset = {}
|
|
37
|
-
|
|
38
34
|
class ParseError(Exception):
|
|
39
35
|
pass
|
|
40
36
|
|
|
@@ -45,14 +41,15 @@ class Directory(NestedBuffer):
|
|
|
45
41
|
@classmethod
|
|
46
42
|
def create_directories_if_not_exist(cls, offset, fet, zen_generation=None) -> List['Directory']:
|
|
47
43
|
# Recursively return or create and return found directories
|
|
48
|
-
|
|
49
|
-
|
|
44
|
+
|
|
45
|
+
if offset in fet.psptool.directories_by_offset:
|
|
46
|
+
return [fet.psptool.directories_by_offset[offset]]
|
|
50
47
|
else:
|
|
51
48
|
# 1. Create the immediate directory in front of us
|
|
52
49
|
created_directories = []
|
|
53
50
|
try:
|
|
54
51
|
directory = cls.from_offset(fet, offset, zen_generation)
|
|
55
|
-
|
|
52
|
+
fet.psptool.directories_by_offset[offset] = directory
|
|
56
53
|
created_directories.append(directory)
|
|
57
54
|
except Directory.ParseError as e:
|
|
58
55
|
# Handle empty entries gracefully (like master branch)
|
|
@@ -70,8 +67,8 @@ class Directory(NestedBuffer):
|
|
|
70
67
|
|
|
71
68
|
# 3. Recursively add tertiary directories (double references introduced in Zen 4), if applicable
|
|
72
69
|
for tertiary_directory_offset in directory.tertiary_directory_offsets:
|
|
73
|
-
directory_body = fet.rom.get_bytes(tertiary_directory_offset
|
|
74
|
-
actual_tertiary_offset = int.from_bytes(directory_body[:
|
|
70
|
+
directory_body = fet.rom.get_bytes(tertiary_directory_offset, 32)
|
|
71
|
+
actual_tertiary_offset = int.from_bytes(directory_body[16:20], 'little')
|
|
75
72
|
# Resolve one more indirection
|
|
76
73
|
tertiary_directories = cls.create_directories_if_not_exist(actual_tertiary_offset, fet, zen_generation)
|
|
77
74
|
created_directories += tertiary_directories
|
|
@@ -83,7 +80,7 @@ class Directory(NestedBuffer):
|
|
|
83
80
|
rom_offset &= fet.rom.addr_mask
|
|
84
81
|
magic = fet.rom.get_bytes(rom_offset, 4)
|
|
85
82
|
|
|
86
|
-
if magic == b'\xff\xff\xff\xff':
|
|
83
|
+
if magic == b'\xff\xff\xff\xff' or magic == b'\x00\x00\x00\x00':
|
|
87
84
|
fet.psptool.ph.print_warning(f"Empty FET entry at ROM address 0x{rom_offset:x}")
|
|
88
85
|
raise Directory.ParseError("Empty entry")
|
|
89
86
|
if magic in cls.DIRECTORY_MAGICS:
|
|
@@ -106,7 +103,7 @@ class Directory(NestedBuffer):
|
|
|
106
103
|
self._count = int.from_bytes(self.rom[self.buffer_offset + 8: self.buffer_offset + 12], 'little')
|
|
107
104
|
self.magic = self.rom.get_bytes(self.buffer_offset, 4)
|
|
108
105
|
assert self.magic in self.DIRECTORY_MAGICS
|
|
109
|
-
self.
|
|
106
|
+
self.additional_info = self.rom.get_bytes(self.buffer_offset + 12, 4)
|
|
110
107
|
self.header = NestedBuffer(self, self.HEADER_SIZE)
|
|
111
108
|
self.body = NestedBuffer(self, self.ENTRY_SIZE * self.count, buffer_offset=self.HEADER_SIZE)
|
|
112
109
|
self.buffer_size = len(self.header) + len(self.body)
|
|
@@ -157,13 +154,18 @@ class Directory(NestedBuffer):
|
|
|
157
154
|
self.header[8:12] = struct.pack('<I', self.count)
|
|
158
155
|
self.update_checksum()
|
|
159
156
|
|
|
157
|
+
# 00b: x86 Physical address
|
|
158
|
+
# 01b: Offset from start of the BIOS (flash offset)
|
|
159
|
+
# 10b: Offset from start of directory header
|
|
160
|
+
# 11b: Offset from start of partition
|
|
160
161
|
@property
|
|
161
162
|
def address_mode(self):
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
163
|
+
info = struct.unpack('<L', self.additional_info)[0]
|
|
164
|
+
version = (info >> 31) & 1
|
|
165
|
+
if version == 1:
|
|
166
|
+
return (info >> 24) & 3
|
|
167
|
+
else:
|
|
168
|
+
return (info >> 29) & 3
|
|
167
169
|
|
|
168
170
|
def verify_checksum(self):
|
|
169
171
|
data = self[0x8:]
|
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
# PSPTool - Display, extract and manipulate PSP firmware inside UEFI images
|
|
2
|
+
# Copyright (C) 2021 Christian Werling, Robert Buhren, Hans Niklas Jacob
|
|
3
|
+
#
|
|
4
|
+
# This program is free software: you can redistribute it and/or modify
|
|
5
|
+
# it under the terms of the GNU General Public License as published by
|
|
6
|
+
# the Free Software Foundation, either version 3 of the License, or
|
|
7
|
+
# (at your option) any later version.
|
|
8
|
+
#
|
|
9
|
+
# This program is distributed in the hope that it will be useful,
|
|
10
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
11
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
12
|
+
# GNU General Public License for more details.
|
|
13
|
+
#
|
|
14
|
+
# You should have received a copy of the GNU General Public License
|
|
15
|
+
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
16
|
+
|
|
17
|
+
import struct
|
|
18
|
+
|
|
19
|
+
from typing import TYPE_CHECKING
|
|
20
|
+
if TYPE_CHECKING:
|
|
21
|
+
from directory import Directory
|
|
22
|
+
|
|
23
|
+
from .utils import NestedBuffer
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
class DirectoryEntry(NestedBuffer):
|
|
27
|
+
ENTRY_SIZE = 4 * 4
|
|
28
|
+
|
|
29
|
+
def __init__(self, parent_directory: 'Directory', entry_offset):
|
|
30
|
+
super().__init__(parent_directory.body, self.ENTRY_SIZE, entry_offset)
|
|
31
|
+
self.parent_directory = parent_directory
|
|
32
|
+
self.entry_offset = entry_offset
|
|
33
|
+
|
|
34
|
+
def __repr__(self):
|
|
35
|
+
return f'{self.__class__.__name__}({self.type=:#x}, {self.flags=:#x}, {self.size=:#x}, ' \
|
|
36
|
+
f'{self.offset=:#x}, {self.entry_offset=:#x}, {self.rsv0=:#x})'
|
|
37
|
+
|
|
38
|
+
def file_offset(self):
|
|
39
|
+
# Special case soft fuse chain, no offset or size
|
|
40
|
+
if self.type == 0xb:
|
|
41
|
+
dir_start = self.parent_directory.buffer_offset + self.parent_directory.HEADER_SIZE
|
|
42
|
+
return dir_start + self.entry_offset
|
|
43
|
+
|
|
44
|
+
addr_mode = self.parent_directory.address_mode
|
|
45
|
+
# If directory address mode is 2 or 3 (relative to dir or slot), the
|
|
46
|
+
# entry address mode must be taken into account, otherwise ignored.
|
|
47
|
+
if addr_mode == 2 or addr_mode == 3:
|
|
48
|
+
addr_mode = self.address_mode
|
|
49
|
+
|
|
50
|
+
if addr_mode == 0:
|
|
51
|
+
# x86 physical address, should be in range 0xff000000 - 0xffffffff
|
|
52
|
+
# But some images use flash offset in x86 physical address mode.
|
|
53
|
+
# If ROM is bigger than 16MB and the entry address is in the
|
|
54
|
+
# 0xff000000 - 0xffffffff range, we have to override the mask for
|
|
55
|
+
# physical address.
|
|
56
|
+
rom_size = self.parent_directory.rom.addr_mask + 1
|
|
57
|
+
if self.offset > 0xFF000000 and rom_size > 16 * 1024 * 1024:
|
|
58
|
+
return self.offset & 0x00FFFFFF
|
|
59
|
+
else:
|
|
60
|
+
return self.offset & self.parent_directory.rom.addr_mask
|
|
61
|
+
elif addr_mode == 1:
|
|
62
|
+
# Flash offset from start of BIOS, most common on modern systems
|
|
63
|
+
return self.offset
|
|
64
|
+
elif addr_mode == 2:
|
|
65
|
+
# Flash offset from start of directory header
|
|
66
|
+
return self.parent_directory.buffer_offset + self.offset
|
|
67
|
+
elif addr_mode == 3:
|
|
68
|
+
# Flash offset from start of the slot
|
|
69
|
+
# TODO: How to calculate the offset from slot? Is this correct?
|
|
70
|
+
return self.parent_directory.buffer_offset + self.offset
|
|
71
|
+
|
|
72
|
+
@property
|
|
73
|
+
def type(self):
|
|
74
|
+
return struct.unpack('<B', self[0:1])[0]
|
|
75
|
+
|
|
76
|
+
@type.setter
|
|
77
|
+
def type(self, value):
|
|
78
|
+
self.set_bytes(0, 1, struct.pack('<B', value))
|
|
79
|
+
|
|
80
|
+
@property
|
|
81
|
+
def subprogram(self):
|
|
82
|
+
return struct.unpack('<B', self[1:2])[0]
|
|
83
|
+
|
|
84
|
+
@subprogram.setter
|
|
85
|
+
def subprogram(self, value):
|
|
86
|
+
self.set_bytes(1, 1, struct.pack('<B', value))
|
|
87
|
+
|
|
88
|
+
@property
|
|
89
|
+
def flags(self):
|
|
90
|
+
return struct.unpack('<H', self[2:4])[0]
|
|
91
|
+
|
|
92
|
+
@flags.setter
|
|
93
|
+
def flags(self, value):
|
|
94
|
+
self.set_bytes(2, 2, struct.pack('<H', value))
|
|
95
|
+
|
|
96
|
+
@property
|
|
97
|
+
def instance(self):
|
|
98
|
+
return (self.flags >> 3) & 0xF
|
|
99
|
+
|
|
100
|
+
@instance.setter
|
|
101
|
+
def instance(self, value):
|
|
102
|
+
self.flags = self.flags | ((value & 0xF) << 3)
|
|
103
|
+
|
|
104
|
+
@property
|
|
105
|
+
def size(self):
|
|
106
|
+
return struct.unpack('<I', self[4:8])[0]
|
|
107
|
+
|
|
108
|
+
@size.setter
|
|
109
|
+
def size(self, value):
|
|
110
|
+
self.set_bytes(4, 4, struct.pack('<I', value))
|
|
111
|
+
|
|
112
|
+
@property
|
|
113
|
+
def offset(self):
|
|
114
|
+
return struct.unpack('<I', self[8:12])[0]
|
|
115
|
+
|
|
116
|
+
@offset.setter
|
|
117
|
+
def offset(self, value):
|
|
118
|
+
self.set_bytes(8, 4, struct.pack('<I', value))
|
|
119
|
+
|
|
120
|
+
@property
|
|
121
|
+
def rsv0(self):
|
|
122
|
+
return struct.unpack('<I', self[12:16])[0]
|
|
123
|
+
|
|
124
|
+
@rsv0.setter
|
|
125
|
+
def rsv0(self, value):
|
|
126
|
+
self.set_bytes(12, 4, struct.pack('<I', value))
|
|
127
|
+
|
|
128
|
+
# 00b: x86 Physical address
|
|
129
|
+
# 01b: Offset from start of the BIOS (flash offset)
|
|
130
|
+
# 10b: Offset from start of directory header
|
|
131
|
+
# 11b: Offset from start of partition
|
|
132
|
+
@property
|
|
133
|
+
def address_mode(self):
|
|
134
|
+
return (self.rsv0 >> 30) & 3
|
|
135
|
+
|
|
136
|
+
class BiosDirectoryEntry(DirectoryEntry):
|
|
137
|
+
ENTRY_SIZE = 4 * 6
|
|
138
|
+
|
|
139
|
+
def __repr__(self):
|
|
140
|
+
return super().__repr__()[:-1] + f', {self.destination=:#x})'
|
|
141
|
+
|
|
142
|
+
@property
|
|
143
|
+
def destination(self):
|
|
144
|
+
return struct.unpack('<Q', self[16:24])[0]
|
|
145
|
+
|
|
146
|
+
@destination.setter
|
|
147
|
+
def destination(self, value):
|
|
148
|
+
self.set_bytes(16, 8, struct.pack('<Q', value))
|
|
149
|
+
|
|
150
|
+
@property
|
|
151
|
+
def region_type(self):
|
|
152
|
+
return struct.unpack('<B', self[1:2])[0]
|
|
153
|
+
|
|
154
|
+
@region_type.setter
|
|
155
|
+
def region_type(self, value):
|
|
156
|
+
self.set_bytes(1, 1, struct.pack('<B', value))
|
|
157
|
+
|
|
158
|
+
@property
|
|
159
|
+
def flags(self):
|
|
160
|
+
return struct.unpack('<H', self[2:4])[0]
|
|
161
|
+
|
|
162
|
+
@flags.setter
|
|
163
|
+
def flags(self, value):
|
|
164
|
+
self.set_bytes(2, 2, struct.pack('<H', value))
|
|
165
|
+
|
|
166
|
+
@property
|
|
167
|
+
def subprogram(self):
|
|
168
|
+
return (self.flags >> 8) & 0x7
|
|
169
|
+
|
|
170
|
+
@subprogram.setter
|
|
171
|
+
def subprogram(self, value):
|
|
172
|
+
self.flags = self.flags | ((value & 0x7) << 8)
|
|
173
|
+
|
|
174
|
+
@property
|
|
175
|
+
def instance(self):
|
|
176
|
+
return (self.flags >> 4) & 0xF
|
|
177
|
+
|
|
178
|
+
@instance.setter
|
|
179
|
+
def instance(self, value):
|
|
180
|
+
self.flags = self.flags | ((value & 0xF) << 4)
|
|
@@ -69,10 +69,16 @@ class Fet(NestedBuffer):
|
|
|
69
69
|
# TODO: Why is 0xFFFFFFFe a possible value here?
|
|
70
70
|
if rom_addr in [0x0, 0xFFFFFFFF, 0xFFFFFFFe]:
|
|
71
71
|
continue
|
|
72
|
-
|
|
72
|
+
# if ROM is bigger than 16MB, we have to override the mask for
|
|
73
|
+
# physical address
|
|
74
|
+
if rom_addr > 0xFF000000 and self.rom.addr_mask + 1 > 16 * 1024 * 1024:
|
|
75
|
+
rom_addr &= 0x00FFFFFF
|
|
76
|
+
else:
|
|
77
|
+
rom_addr &= self.rom.addr_mask
|
|
78
|
+
|
|
73
79
|
try:
|
|
74
80
|
dir_magic = self.rom[rom_addr:rom_addr + 4]
|
|
75
|
-
except:
|
|
81
|
+
except AssertionError as e:
|
|
76
82
|
self.psptool.ph.print_warning(f"FET entry 0x{rom_addr:x} not found or invalid, skipping ...")
|
|
77
83
|
continue
|
|
78
84
|
if dir_magic == b'2PSP' or dir_magic == b'2BHD':
|
|
@@ -105,7 +111,14 @@ class Fet(NestedBuffer):
|
|
|
105
111
|
entry_addr = int.from_bytes(entry, 'little')
|
|
106
112
|
if entry_addr in [0, 0xFFFFFFFF]:
|
|
107
113
|
continue
|
|
108
|
-
|
|
114
|
+
# if ROM is bigger than 16MB, we have to override the mask for
|
|
115
|
+
# physical address
|
|
116
|
+
rom_size = self.rom.addr_mask + 1
|
|
117
|
+
if entry_addr > 0xFF000000 and rom_size > 16 * 1024 * 1024:
|
|
118
|
+
entry_addr &= 0x00FFFFFF
|
|
119
|
+
else:
|
|
120
|
+
entry_addr &= self.rom.addr_mask
|
|
121
|
+
|
|
109
122
|
# entry_addr += self.blob_offset
|
|
110
123
|
zen_generation_id = combo_dir[i*16+5:i*16+8]
|
|
111
124
|
zen_generation = 'unknown'
|