2 # SPDX-License-Identifier: GPL-2.0
9 import ioctl_opt
as ioctl
15 # Artificial delay between set commands
19 class invalid_param(ctypes
.Structure
):
21 ("data", ctypes
.c_uint8
),
25 def system_is_secured() -> bool:
26 fused_part
= glob
.glob("/sys/bus/pci/drivers/ccp/**/fused_part")[0]
27 if os
.path
.exists(fused_part
):
28 with
open(fused_part
, "r") as r
:
29 return int(r
.read()) == 1
33 class DynamicBoostControlTest(unittest
.TestCase
):
34 def __init__(self
, data
) -> None:
36 self
.signature
= b
"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"
37 self
.uid
= b
"1111111111111111"
38 super().__init
__(data
)
40 def setUp(self
) -> None:
41 self
.d
= open(DEVICE_NODE
)
42 return super().setUp()
44 def tearDown(self
) -> None:
47 return super().tearDown()
50 class TestUnsupportedSystem(DynamicBoostControlTest
):
51 def setUp(self
) -> None:
52 if os
.path
.exists(DEVICE_NODE
):
53 self
.skipTest("system is supported")
54 with self
.assertRaises(FileNotFoundError
) as error
:
56 self
.assertEqual(error
.exception
.errno
, 2)
58 def test_unauthenticated_nonce(self
) -> None:
59 """fetch unauthenticated nonce"""
60 with self
.assertRaises(ValueError) as error
:
61 get_nonce(self
.d
, None)
64 class TestInvalidIoctls(DynamicBoostControlTest
):
65 def __init__(self
, data
) -> None:
66 self
.data
= invalid_param()
68 super().__init
__(data
)
70 def setUp(self
) -> None:
71 if not os
.path
.exists(DEVICE_NODE
):
72 self
.skipTest("system is unsupported")
74 self
.skipTest("unable to test IOCTLs without ioctl_opt")
76 return super().setUp()
78 def test_invalid_nonce_ioctl(self
) -> None:
79 """tries to call get_nonce ioctl with invalid data structures"""
81 # 0x1 (get nonce), and invalid data
82 INVALID1
= ioctl
.IOWR(ord("D"), 0x01, invalid_param
)
83 with self
.assertRaises(OSError) as error
:
84 fcntl
.ioctl(self
.d
, INVALID1
, self
.data
, True)
85 self
.assertEqual(error
.exception
.errno
, 22)
87 def test_invalid_setuid_ioctl(self
) -> None:
88 """tries to call set_uid ioctl with invalid data structures"""
90 # 0x2 (set uid), and invalid data
91 INVALID2
= ioctl
.IOW(ord("D"), 0x02, invalid_param
)
92 with self
.assertRaises(OSError) as error
:
93 fcntl
.ioctl(self
.d
, INVALID2
, self
.data
, True)
94 self
.assertEqual(error
.exception
.errno
, 22)
96 def test_invalid_setuid_rw_ioctl(self
) -> None:
97 """tries to call set_uid ioctl with invalid data structures"""
99 # 0x2 as RW (set uid), and invalid data
100 INVALID3
= ioctl
.IOWR(ord("D"), 0x02, invalid_param
)
101 with self
.assertRaises(OSError) as error
:
102 fcntl
.ioctl(self
.d
, INVALID3
, self
.data
, True)
103 self
.assertEqual(error
.exception
.errno
, 22)
105 def test_invalid_param_ioctl(self
) -> None:
106 """tries to call param ioctl with invalid data structures"""
107 # 0x3 (param), and invalid data
108 INVALID4
= ioctl
.IOWR(ord("D"), 0x03, invalid_param
)
109 with self
.assertRaises(OSError) as error
:
110 fcntl
.ioctl(self
.d
, INVALID4
, self
.data
, True)
111 self
.assertEqual(error
.exception
.errno
, 22)
113 def test_invalid_call_ioctl(self
) -> None:
114 """tries to call the DBC ioctl with invalid data structures"""
115 # 0x4, and invalid data
116 INVALID5
= ioctl
.IOWR(ord("D"), 0x04, invalid_param
)
117 with self
.assertRaises(OSError) as error
:
118 fcntl
.ioctl(self
.d
, INVALID5
, self
.data
, True)
119 self
.assertEqual(error
.exception
.errno
, 22)
122 class TestInvalidSignature(DynamicBoostControlTest
):
123 def setUp(self
) -> None:
124 if not os
.path
.exists(DEVICE_NODE
):
125 self
.skipTest("system is unsupported")
126 if not system_is_secured():
127 self
.skipTest("system is unfused")
128 return super().setUp()
130 def test_unauthenticated_nonce(self
) -> None:
131 """fetch unauthenticated nonce"""
132 get_nonce(self
.d
, None)
134 def test_multiple_unauthenticated_nonce(self
) -> None:
135 """ensure state machine always returns nonce"""
136 for count
in range(0, 2):
137 get_nonce(self
.d
, None)
139 def test_authenticated_nonce(self
) -> None:
140 """fetch authenticated nonce"""
141 get_nonce(self
.d
, None)
142 with self
.assertRaises(OSError) as error
:
143 get_nonce(self
.d
, self
.signature
)
144 self
.assertEqual(error
.exception
.errno
, 22)
146 def test_set_uid(self
) -> None:
148 get_nonce(self
.d
, None)
149 with self
.assertRaises(OSError) as error
:
150 set_uid(self
.d
, self
.uid
, self
.signature
)
151 self
.assertEqual(error
.exception
.errno
, 1)
153 def test_get_param(self
) -> None:
154 """fetch a parameter"""
155 with self
.assertRaises(OSError) as error
:
156 process_param(self
.d
, PARAM_GET_SOC_PWR_CUR
, self
.signature
)
157 self
.assertEqual(error
.exception
.errno
, 11)
159 def test_set_param(self
) -> None:
160 """set a parameter"""
161 with self
.assertRaises(OSError) as error
:
162 process_param(self
.d
, PARAM_SET_PWR_CAP
, self
.signature
, 1000)
163 self
.assertEqual(error
.exception
.errno
, 11)
166 class TestUnFusedSystem(DynamicBoostControlTest
):
167 def setup_identity(self
) -> None:
168 """sets up the identity of the caller"""
169 # if already authenticated these may fail
171 get_nonce(self
.d
, None)
172 except PermissionError
:
175 set_uid(self
.d
, self
.uid
, self
.signature
)
176 except BlockingIOError
:
179 get_nonce(self
.d
, self
.signature
)
180 except PermissionError
:
183 def setUp(self
) -> None:
184 if not os
.path
.exists(DEVICE_NODE
):
185 self
.skipTest("system is unsupported")
186 if system_is_secured():
187 self
.skipTest("system is fused")
189 self
.setup_identity()
190 time
.sleep(SET_DELAY
)
192 def test_get_valid_param(self
) -> None:
193 """fetch all possible parameters"""
195 soc_power_max
= process_param(self
.d
, PARAM_GET_SOC_PWR_MAX
, self
.signature
)
196 soc_power_min
= process_param(self
.d
, PARAM_GET_SOC_PWR_MIN
, self
.signature
)
197 self
.assertGreater(soc_power_max
[0], soc_power_min
[0])
200 fmax_max
= process_param(self
.d
, PARAM_GET_FMAX_MAX
, self
.signature
)
201 fmax_min
= process_param(self
.d
, PARAM_GET_FMAX_MIN
, self
.signature
)
202 self
.assertGreater(fmax_max
[0], fmax_min
[0])
206 "fmax-cap": PARAM_GET_FMAX_CAP
,
207 "power-cap": PARAM_GET_PWR_CAP
,
208 "current-temp": PARAM_GET_CURR_TEMP
,
209 "soc-power-cur": PARAM_GET_SOC_PWR_CUR
,
212 result
= process_param(self
.d
, keys
[k
], self
.signature
)
213 self
.assertGreater(result
[0], 0)
215 def test_get_invalid_param(self
) -> None:
216 """fetch an invalid parameter"""
218 set_uid(self
.d
, self
.uid
, self
.signature
)
221 with self
.assertRaises(OSError) as error
:
222 process_param(self
.d
, (0xF,), self
.signature
)
223 self
.assertEqual(error
.exception
.errno
, 22)
225 def test_set_fmax(self
) -> None:
226 """get/set fmax limit"""
228 original
= process_param(self
.d
, PARAM_GET_FMAX_CAP
, self
.signature
)
231 target
= original
[0] - 100
232 process_param(self
.d
, PARAM_SET_FMAX_CAP
, self
.signature
, target
)
233 time
.sleep(SET_DELAY
)
234 new
= process_param(self
.d
, PARAM_GET_FMAX_CAP
, self
.signature
)
235 self
.assertEqual(new
[0], target
)
237 # revert back to current
238 process_param(self
.d
, PARAM_SET_FMAX_CAP
, self
.signature
, original
[0])
239 time
.sleep(SET_DELAY
)
240 cur
= process_param(self
.d
, PARAM_GET_FMAX_CAP
, self
.signature
)
241 self
.assertEqual(cur
[0], original
[0])
243 def test_set_power_cap(self
) -> None:
244 """get/set power cap limit"""
246 original
= process_param(self
.d
, PARAM_GET_PWR_CAP
, self
.signature
)
249 target
= original
[0] - 10
250 process_param(self
.d
, PARAM_SET_PWR_CAP
, self
.signature
, target
)
251 time
.sleep(SET_DELAY
)
252 new
= process_param(self
.d
, PARAM_GET_PWR_CAP
, self
.signature
)
253 self
.assertEqual(new
[0], target
)
255 # revert back to current
256 process_param(self
.d
, PARAM_SET_PWR_CAP
, self
.signature
, original
[0])
257 time
.sleep(SET_DELAY
)
258 cur
= process_param(self
.d
, PARAM_GET_PWR_CAP
, self
.signature
)
259 self
.assertEqual(cur
[0], original
[0])
261 def test_set_3d_graphics_mode(self
) -> None:
262 """set/get 3d graphics mode"""
263 # these aren't currently implemented but may be some day
264 # they are *expected* to fail
265 with self
.assertRaises(OSError) as error
:
266 process_param(self
.d
, PARAM_GET_GFX_MODE
, self
.signature
)
267 self
.assertEqual(error
.exception
.errno
, 2)
269 time
.sleep(SET_DELAY
)
271 with self
.assertRaises(OSError) as error
:
272 process_param(self
.d
, PARAM_SET_GFX_MODE
, self
.signature
, 1)
273 self
.assertEqual(error
.exception
.errno
, 2)
276 if __name__
== "__main__":