Skip to content

Commit 2afee1d

Browse files
committed
[Feature] Implementation for runtime access communication method with firmware to support firmware configuration access and modification on-the-fly
1 parent 8e0c3c2 commit 2afee1d

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

43 files changed

+8655
-6
lines changed

MANIFEST.in

+5-2
Original file line numberDiff line numberDiff line change
@@ -12,15 +12,17 @@ include start_xmlcli.sh
1212

1313
recursive-include src/xmlcli/cfg *
1414

15-
include src/xmlcli/modules/*
16-
recursive-include src/xmlcli/modules/winContextMenu *
15+
include examples/*
16+
17+
recursive-include src/xmlcli/modules *
1718

1819
include src/xmlcli/out/.gitignore
1920

2021
include src/xmlcli/messages.json
2122
include src/xmlcli/xmlcli.config
2223
recursive-include src/xmlcli/common *
2324
recursive-include src/xmlcli/access/base *
25+
recursive-include src/xmlcli/access/generic *
2426
recursive-include src/xmlcli/access/linux *
2527
recursive-include src/xmlcli/access/stub *
2628
recursive-include src/xmlcli/access/winrwe *
@@ -31,6 +33,7 @@ include tests/CommonTests.py
3133
include tests/tests.config
3234
include tests/UefiParserTest.py
3335
include tests/UnitTestHelper.py
36+
include tests/XmlCliTest.py
3437

3538
include src/xmlcli/tools/*
3639
include docs/user_guide/*

Makefile

+23
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,29 @@ clean-test: ## remove test and coverage artifacts
5050
rm -fr htmlcov/
5151
rm -fr .pytest_cache
5252

53+
lint: ## check style with flake8
54+
flake8 xmlcli tests
55+
56+
test: ## run tests quickly with the default Python
57+
python setup.py test
58+
59+
test-all: ## run tests on every Python version with tox
60+
tox
61+
62+
coverage: ## check code coverage quickly with the default Python
63+
coverage run --source xmlcli setup.py test
64+
coverage report -m
65+
coverage html
66+
$(BROWSER) htmlcov/index.html
67+
68+
docs: ## generate Sphinx HTML documentation, including API docs
69+
rm -f docs/xmlcli.rst
70+
rm -f docs/modules.rst
71+
sphinx-apidoc -o docs/ xmlcli
72+
$(MAKE) -C docs clean
73+
$(MAKE) -C docs html
74+
$(BROWSER) docs/_build/html/index.html
75+
5376
dist: clean ## builds source and wheel package
5477
mkdir bld
5578
python setup.py egg_info --egg-base=bld build --build-base=bld bdist_wheel --universal

README.md

+185
Original file line numberDiff line numberDiff line change
@@ -6,16 +6,27 @@ UFFAF allows firmware modification as an efficient operation with scriptable app
66

77
These reference scripts provides several capabilities including but not limited to:
88
>- Parsing Information of UEFI BIOS Firmware as per [Platform Initialization Specification](https://uefi.org/specs/PI/1.8/)
9+
>- Programming/Reading BIOS knobs with CLI and GUI
10+
>- Fetching Platform XML from target
11+
>- System information
12+
>- CommandLine and web based GUI support for get and set NVAR (UEFI NVRAM variable)
913
>- Context Menu Integration for Windows
1014
15+
These scripts are generic and platform/program independent (as long as BIOS on SUT BIOS supports XML CLI interface).
1116

1217
---
1318

1419
## User Guidelines for usage
1520

21+
These scripts are provided as reference scripts and requires to have bios driver enabled in order to use the functionality.
22+
23+
As scripts require to read/write memory of the target device/system, valid access interface would be required which can be configured at [config file](src/xmlcli/xmlcli.config).
24+
1625
For Offline Binary modification, these scripts provide easier way to interpret and update the data bytes of binary.
1726
Irrespective of these scripts, changing undesired data in binary could be result to unexpected behavior hence, it is individual's responsibility to make sure to use valid configuration.
1827

28+
As Accessing target SUT is only possible at **Elevated Privilege**, we recommend proceeding with caution if service API of these scripts are exposed over network.
29+
1930
## Supported Interface Types
2031

2132
Interface means the way to access memory and I/O of target system.
@@ -24,13 +35,15 @@ These interface works only when running with elevated privileges are available.
2435
It is responsibility of user to make sure to act with caution before making modification to avoid
2536
corrupting memory/registers with unwanted data.
2637

38+
2739
- Windows
2840
- LINUX
2941
- Offline mode (or stub mode, to enable BIOS/IFWI Editing)
3042

3143
## Prerequisites
3244

3345
- [Python](https://www.python.org/downloads/) software version 3.6 or above
46+
- If running on Online mode; **elevated privileges** are required to execute commands as it involves accessing hardware memory resource.
3447
- For Interface setup please refer README document within interface folder itself.
3548

3649
## Installation
@@ -49,6 +62,178 @@ python -m pip install <xmlcli-x.x.x.whl> --proxy <proxy-url>
4962

5063
Refer [Installation-Steps](docs/user_guide/installation.md) for more alternate installation instruction.
5164

65+
66+
## Setting Interface Type
67+
68+
Need to select the interface to indicate the scripts on which access method to use (depending on which environment we expect the script to operate in).
69+
70+
```python
71+
from xmlcli import XmlCli as cli
72+
cli.clb._setCliAccess("<access-method>")
73+
```
74+
75+
Below are listed valid `<access-method>`:
76+
77+
| Access Method | Remarks |
78+
| --- | --- |
79+
| `linux` | For using linux as interface, need to open Python Prompt in root permissions. |
80+
| `winrwe` | For using `RW.exe` as Windows interface (**slow**, least recommended). For more details refer [winrwe/README.md](src/xmlcli/access/winrwe/README.md) |
81+
82+
83+
## Running popular commands
84+
85+
After initializing the desired interface, the use may run following commands.
86+
87+
If the commands `return 0`, it means the operation was `successful`, else there was an error.
88+
89+
### Standard import steps
90+
91+
```python
92+
from xmlcli import XmlCli as cli
93+
cli.clb._setCliAccess("linux") # Set desired Interface (for example `linux` if using on `linux` SUT)
94+
```
95+
96+
### Step to check XmlCli capability on current System
97+
98+
```python
99+
from xmlcli import XmlCli as cli
100+
cli.clb.ConfXmlCli() # Check if XmlCli is supported &/ Enabled on the current system.
101+
```
102+
103+
| Return value of `cli.clb.ConfXmlCli` | Meaning |
104+
| --- | --- |
105+
| 0 | XmlCli is already **supported & enabled**. |
106+
| 1 | XmlCli is **not supported** on the current BIOS or the System BIOS has not completed Boot. |
107+
| 2 | XmlCli is **supported** but was **not enabled**, the script has now enabled it and **SUT needs reboot** to make use of XmlCli. |
108+
109+
### To Save Target XML file
110+
111+
```python
112+
from xmlcli import XmlCli as cli
113+
# For Online
114+
# Run common import steps and make sure `cli.clb.ConfXmlCli()` returns `0`
115+
cli.savexml() # Save Target XML as `<Path_To_XmlCliRefScripts>/out/PlatformConfig.xml` file.
116+
cli.savexml(r"path/to/file.xml") # Save Target XML as absolute file location for `path/to/file.xml`.
117+
118+
# For Offline
119+
cli.savexml(0, r"path/to/ifwi-or-bios.bin") # Extract the XML data from desired BIOS or IFWI binary. Will Save Target XML in `<Path_To_XmlCliRefScripts>/out/` folder.
120+
cli.savexml(r"path/to/file.xml", r"path/to/ifwi-or-bios.bin") # Extract the XML data from desired BIOS or IFWI binary. Will Save Target XML as `path/to/file.xml`.
121+
```
122+
123+
### To Read BIOS settings
124+
125+
> For **Online** command to run successfully, the target must complete BIOS boot.
126+
> For **Offline** mode, you need to pass the link to BIOS or IFWI binary.
127+
128+
- `Knob_A` & `Knob_B` in the below examples are the knob names taken from the `name` attribute from the `<biosknobs>` section in the XML, it is **case sensitive**.
129+
130+
```python
131+
from xmlcli import XmlCli as cli
132+
cli.CvReadKnobs("Knob_A=Val_1, Knobs_B=Val_2") # Reads the desired Knob_A & Knob_B settings from the SUT and verifies them against Val_1 & Val_2 respectively.
133+
cli.CvReadKnobs() # same as above, just that the Knob entries will be read from the default cfg file (`<Path_To_XmlCliRefScripts>/cfg/BiosKnobs.ini`).
134+
# For Offline
135+
cli.CvReadKnobs("Knob_A=Val_1, Knobs_B=Val_2", r"path/to/ifwi-or-bios.bin") # Reads & verifies the desired knob settings from the given BIOS or IFWI binary.
136+
cli.CvReadKnobs(0, r"path/to/ifwi-or-bios.bin") # same as above, just that the Knob entries will be read from the `cli.clb.KnobsIniFile` cfg file instead.
137+
138+
# the default cfg file pointer can be programed to desired cfg file via following command.
139+
cli.clb.KnobsIniFile = r"path/to/bios-config.ini"
140+
```
141+
142+
### To Program BIOS settings
143+
144+
> For **Online** command to run successfully, the target must complete BIOS boot.
145+
> For **Offline** mode, you need to pass the link to BIOS or IFWI binary.
146+
147+
- `Knob_A` & `Knob_B` in the below examples are the knob names taken from the `name` attribute from the `<biosknobs>` section in the XML, it is **case sensitive**.
148+
149+
```python
150+
from xmlcli import XmlCli as cli
151+
cli.CvProgKnobs("Knob_A=Val_1, Knobs_B=Val_2") # Programs the desired Knob_A & Knob_B settings on the SUT and verifies them against Val_1 & Val_2 respectively.
152+
cli.CvProgKnobs() # same as above, just that the Knob entries will be Programed from the default cfg file (<Path_To_XmlCliRefScripts>\cfg\BiosKnobs.ini).
153+
# For Offline
154+
cli.CvProgKnobs("Knob_A=Val_1, Knobs_B=Val_2", r"path/to/ifwi-or-bios.bin") # Program the desired knob settings as new default value, operates on BIOS or IFWI binary, new BIOS or IFWI binary will be generated with desired settings.
155+
cli.CvProgKnobs(0, r"path/to/ifwi-or-bios.bin") # same as above, just that the Knob entries will be Programed from the cli.clb.KnobsIniFile cfg file instead.
156+
157+
# the default cfg file pointer can be programed to desired cfg file via following command.
158+
cli.clb.KnobsIniFile = r"path/to/bios-config.ini"
159+
160+
# To Load Default BIOS settings on the SUT. Offline mode not supported or not Applicable.
161+
cli.CvLoadDefaults() # Loads/Restores the default value back on the system, also shows which values were restored back to its default Value.
162+
```
163+
164+
### To Program only desired BIOS settings and reverting rest all settings back to its default value
165+
166+
> **Offline** mode not supported or not Applicable.
167+
168+
- `Knob_A` & `Knob_B` in the below examples are the knob names taken from the `name` attribute from the `<biosknobs>` section in the XML, it is **case sensitive**.
169+
170+
```python
171+
from xmlcli import XmlCli as cli
172+
cli.CvRestoreModifyKnobs("Knob_A=Val_1, Knobs_B=Val_2") # Programs the desired Knob_A & Knob_B settings and restores everything else back to its default value.
173+
cli.CvRestoreModifyKnobs() # same as above, just that the Knob entries will be Programed from the cli.clb.KnobsIniFile cfg file instead.
174+
# the default cfg file pointer can be programed to desired cfg file via following command.
175+
cli.clb.KnobsIniFile = r"path/to/bios-config.ini"
176+
```
177+
178+
> Offline editing of BIOS will update FV_BB section of BIOS.
179+
> This is an expected to produce boot issue with Secure Boot profiles (i.e. Secure Profile images)
180+
181+
To make sure offline Edited BIOSes for Knob changes boot fine with Secure Profile IFWI's,
182+
user need to supply the re-signing script/pkg. This is user's full responsibility to manage an executable script
183+
which syntax should follow as:
184+
185+
```shell
186+
file/to/executable/signing-resigning.bat input.bin output/path.bin
187+
```
188+
189+
```python
190+
from xmlcli import XmlCli as cli
191+
192+
cli.fwp.SecureProfileEditing = True # if not set to True, Re-Signing Process will be skipped
193+
cli.fwp.ReSigningFile = r'path/to/resigning/executable/ResignIbbForBtG.bat' # by default this variable is empty, please populate this variable with Re-Signing Script File Ptr
194+
cli.CvProgKnobs('BootFirstToShell=1, EfiNetworkSupport=3', r'path/to/ifwi-or-bios.bin')
195+
```
196+
197+
> **Note** - Providing Secure Profile resigning script/executable is out of scope of XmlCli,
198+
> User need to gather required executable in order to utilize this functionality on SecureProfile.
199+
200+
201+
### Add MSR & IO Read/Write CLI functions (`Only for DCG`)
202+
203+
#### Usage Syntax
204+
205+
```python
206+
from xmlcli import XmlCli as cli
207+
208+
cli.IoAccess("<operation>", "<IoPort>", "<Size>", "<IoValue>")
209+
cli.MsrAccess("<operation>", "<MsrNumber>", "<ApicId>", "<MsrValue>")
210+
```
211+
212+
#### Example
213+
214+
```python
215+
from xmlcli import XmlCli as cli
216+
217+
cli.IoAccess(cli.clb.IO_WRITE_OPCODE, 0x84, 1, 0xFA)
218+
cli.IoAccess(cli.clb.IO_READ_OPCODE, 0x84, 1)
219+
cli.MsrAccess(cli.clb.READ_MSR_OPCODE, 0x53, 0)
220+
cli.MsrAccess(cli.clb.WRITE_MSR_OPCODE, 0x1A0, 0, 0x1)
221+
```
222+
223+
## Execution under EFI Shell
224+
225+
### Using XmlCli EFI App
226+
227+
EFI App is located under `tools/XmlCliKnobs.efi`, below commands can be executed on UEFI Shell:
228+
229+
| Command | Description |
230+
| ------- | ----------- |
231+
| `XmlCliKnobs.efi CX` | Ensure XmlCli is enabled, if it's not enable, this command helps to enable XmlCli, Reboot SUT if XmlCli was not enabled. |
232+
| `XmlCliKnobs.efi -v` | Get version information of the efi App |
233+
| `XmlCliKnobs.efi GX` | Generate Bios Knobs xml dump |
234+
| `XmlCliKnobs.efi` | List out all possible available commands |
235+
236+
52237
## Additional Feature and Modules
53238

54239
These modules are extension of core XmlCli API also shows example of how it can be consumed in any independent modules.
+22
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
If you have two different Xml from `cli.savexml()` command you could use below method:
2+
3+
4+
Syntax:
5+
```python
6+
from xmlcli import XmlCli as cli
7+
8+
cli.helpers.generate_knobs_delta(
9+
ref_xml="path/to/reference.xml",
10+
new_xml="path/to/new.xml",
11+
out_file="path/to/difference-delta.txt",
12+
compare_tag="default" # xml attribute to be compared against (default|CurrentVal|size|prompt|depex|...)
13+
)
14+
```
15+
16+
17+
If you have BIOS/IFWI image, instead of doing `cli.savexml` for both image, you could directly use below command syntax:
18+
```python
19+
from xmlcli import XmlCli as cli
20+
21+
cli.helpers.compare_bios_knobs("<path-to-reference-bios-or-ifwi>", "<path-to-bios-or-ifwi>", result_log_file="<path-to-difference-delta>")
22+
```

docs/user_guide/uefi_binary_parsing.md

+11
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,17 @@ Key features:
66
- JSON representation, lightweight database with keys and values with ease of readability
77
- Works with both SUT and offline image
88

9+
Working with SUT:
10+
11+
Below command to be executed only after enabling applicable access method:
12+
13+
```python
14+
from xmlcli import XmlCli as cli
15+
16+
max_bios_size = 12 * (1024**2) # 12 MB - configure based on the platform used
17+
# If max_bios_size argument is not specified then by default it uses 32 MB dump to lookup for BIOS image
18+
bios_image = cli.clb.get_bin_file("linux", max_bios_size=max_bios_size) # variable will have location of bios image dump stored from memory
19+
```
920

1021
Initiate the Parsing with below commands:
1122

examples/BiosKnobs.ini

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
[BiosKnobs]
2+
CvfSupport=1
3+
MipiCam_ControlLogic0=1
4+
MipiCam_ControlLogic1=1
5+
MipiCam_Link0=1
6+
MipiCam_Link1=1
7+
MipiCam_Link1_SensorModel=1
8+
MipiCam_Link1_DriverData_CrdVersion=0x20

examples/__init__.py

+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
# -*- coding: utf-8 -*-
2+
__author__ = "Gahan Saraiya"
3+
4+
# Built-in imports
5+
6+
# Custom imports
7+
8+
9+
if __name__ == "__main__":
10+
pass

examples/automate_program_knobs.py

+48
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
# -*- coding: utf-8 -*-
2+
__author__ = "Gahan Saraiya"
3+
4+
# Built-in imports
5+
import os
6+
import sys
7+
import glob
8+
import shutil
9+
10+
# Custom imports
11+
from xmlcli import XmlCli as cli
12+
from xmlcli import XmlCliLib as clb
13+
from xmlcli.common.logger import log
14+
from xmlcli import UefiFwParser as fwp
15+
16+
17+
def automate_program_knobs(input_bios, config_dir, output_dir, new_major_ver="", new_minor_ver=""):
18+
"""Function to perform the CvProgKnobs for multiple bios images using configuration file
19+
20+
:param input_bios: absolute path to the folder contains bios images or absolute path to the bios file
21+
:param config_dir: absolute path to the folder contains bios knobs configuration file(.ini)
22+
:param output_dir: absolute path of the directory to store the output files
23+
:param new_major_ver: new major version for the file
24+
:param new_minor_ver: new minor version for the file
25+
"""
26+
bios_knob_config_files = glob.glob(os.path.join(config_dir, "*.ini"))
27+
original_knobs_config = clb.KnobsIniFile
28+
input_bios_files = []
29+
if os.path.isdir(input_bios):
30+
input_bios_files = glob.glob(os.path.join(input_bios, "*.bin"))
31+
elif os.path.isfile(input_bios):
32+
input_bios_files = [input_bios]
33+
for KnobsIni in bios_knob_config_files:
34+
clb.KnobsIniFile = KnobsIni
35+
suffix_text = os.path.splitext(os.path.basename(KnobsIni))[0]
36+
for BiosBinFile in input_bios_files:
37+
log.info(f"Processing BIOS file = {BiosBinFile}")
38+
cli.CvProgKnobs(0, BiosBinFile, suffix_text, True)
39+
temp_file = clb.OutBinFile
40+
fwp.UpdateBiosId(clb.OutBinFile, new_major_ver, new_minor_ver)
41+
if clb.OutBinFile != "":
42+
shutil.move(clb.OutBinFile, output_dir)
43+
clb.RemoveFile(temp_file)
44+
clb.KnobsIniFile = original_knobs_config
45+
46+
47+
if __name__ == "__main__":
48+
pass

0 commit comments

Comments
 (0)