1 /*
2 * Copyright (C) 2018 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include <chrono>
18 #include <iomanip>
19 #include <iostream>
20 #include <random>
21
22 #include <android-base/endian.h>
23 #include <android-base/logging.h>
24 #include <android-base/parseint.h>
25 #include <binder/IServiceManager.h>
26 #include <binder/ProcessState.h>
27
28 #include <android/hardware/citadel/ICitadeld.h>
29
30 #include <application.h>
31 #include <app_nugget.h>
32 #include <nos/debug.h>
33 #include <nos/CitadeldProxyClient.h>
34
35 using ::android::defaultServiceManager;
36 using ::android::sp;
37 using ::android::ProcessState;
38 using ::android::base::ParseUint;
39
40 using ::android::hardware::citadel::ICitadeld;
41
42 using ::nos::CitadeldProxyClient;
43 using ::nos::NuggetClientInterface;
44 using ::nos::StatusCodeString;
45
46 namespace {
47
ToHexString(uint32_t value)48 std::string ToHexString(uint32_t value) {
49 std::stringstream ss;
50 ss << "0x" << std::hex << std::setfill('0') << std::setw(8) << value;
51 return ss.str();
52 }
53
ToDecString(uint32_t value)54 std::string ToDecString(uint32_t value) {
55 std::stringstream ss;
56 ss << std::dec << value;
57 return ss.str();
58 }
59
60 /* Read a value from a Citadel register */
ReadRegister(NuggetClientInterface & client,uint32_t address,uint32_t * value)61 bool ReadRegister(NuggetClientInterface& client, uint32_t address, uint32_t* value) {
62 // Build request
63 std::vector<uint8_t> buffer(sizeof(uint32_t));
64 *reinterpret_cast<uint32_t*>(buffer.data()) = address;
65
66 // Send request
67 const uint32_t status = client.CallApp(APP_ID_NUGGET, NUGGET_PARAM_READ32, buffer, &buffer);
68 if (status != APP_SUCCESS) {
69 std::cerr << " Failed to read register: " << StatusCodeString(status)
70 << "(" << status << ")\n";
71 return false;
72 }
73
74 // Process response
75 if (buffer.size() != sizeof(*value)) {
76 std::cerr << "Nugget gave us " << buffer.size() << " bytes instead of 4\n";
77 return false;
78 }
79 *value = *reinterpret_cast<uint32_t*>(buffer.data());
80 return true;
81 }
82
83 /* Write a value to a Citadel register */
WriteRegister(NuggetClientInterface & client,uint32_t address,uint32_t value)84 bool WriteRegister(NuggetClientInterface& client, uint32_t address, uint32_t value) {
85 // Build request
86 std::vector<uint8_t> buffer(sizeof(nugget_app_write32));
87 nugget_app_write32* w32 = reinterpret_cast<nugget_app_write32*>(buffer.data());
88 w32->address = address;
89 w32->value = value;
90
91 // Send request
92 const uint32_t status = client.CallApp(APP_ID_NUGGET, NUGGET_PARAM_WRITE32, buffer, nullptr);
93 if (status != APP_SUCCESS) {
94 std::cerr << " Failed to write register: " << StatusCodeString(status)
95 << "(" << status << ")\n";
96 return false;
97 }
98
99 return true;
100 }
101
102 /*
103 * Read a register and check the value is in the specified bounds. The bounds
104 * are inclusive.
105 */
CheckRegisterInRange(NuggetClientInterface & client,uint32_t address,uint32_t min,uint32_t max)106 bool CheckRegisterInRange(NuggetClientInterface& client, uint32_t address,
107 uint32_t min, uint32_t max){
108 uint32_t value;
109 if (!ReadRegister(client, address, &value)) {
110 std::cerr << "Failed to read " << ToHexString(address) << "\n";
111 return false;
112 }
113 if (value < min || value > max) {
114 std::cerr << ToHexString(address) << " out of range: " << ToHexString(value) << "\n";
115 return false;
116 }
117 return true;
118 }
119
120 /*
121 * Read a register and check the value is ouside the specified bounds. The
122 * bounds are inclusive.
123 */
CheckRegisterNotInRange(NuggetClientInterface & client,uint32_t address,uint32_t min,uint32_t max)124 bool CheckRegisterNotInRange(NuggetClientInterface& client, uint32_t address,
125 uint32_t min, uint32_t max){
126 uint32_t value;
127 if (!ReadRegister(client, address, &value)) {
128 std::cerr << "Failed to read " << ToHexString(address) << "\n";
129 return false;
130 }
131 if (value >= min && value <= max) {
132 std::cerr << ToHexString(address) << " in illegal range: " << ToHexString(value) << "\n";
133 return false;
134 }
135 return true;
136 }
137
138 /* Have Nugget report the number of cycles it has been running for. */
CyclesSinceBoot(NuggetClientInterface & client,uint32_t * cycles)139 bool CyclesSinceBoot(NuggetClientInterface & client, uint32_t* cycles) {
140 std::vector<uint8_t> buffer;
141 buffer.reserve(sizeof(uint32_t));
142 if (client.CallApp(APP_ID_NUGGET, NUGGET_PARAM_CYCLES_SINCE_BOOT,
143 buffer, &buffer) != app_status::APP_SUCCESS) {
144 std::cerr << "Failed to get cycles since boot\n";
145 return false;
146 }
147 if (buffer.size() != sizeof(uint32_t)) {
148 std::cerr << "Unexpected size of cycle count!\n";
149 return false;
150 }
151 *cycles = le32toh(*reinterpret_cast<uint32_t *>(buffer.data()));
152 return true;
153 }
154
155 /*
156 * The current implementation of the test writes random vales to registers and
157 * reads them back. This lets us check the correct values were sent across the
158 * channel.
159 * TODO(b/65067435): Replace with less intrusive calls.
160 */
CmdStressSpi(NuggetClientInterface & client,char ** params)161 int CmdStressSpi(NuggetClientInterface& client, char** params) {
162 std::random_device rd;
163 std::mt19937 gen(rd());
164 std::uniform_int_distribution<uint16_t> dis;
165
166 // Parse transaction count
167 uint32_t count;
168 if (!ParseUint(params[0], &count)) {
169 std::cerr << "Invalid count: \"" << params[0] << "\"\n";
170 return EXIT_FAILURE;
171 }
172 if (count % 2 != 0) {
173 // Make sure it is even to allow set then check tests
174 std::cerr << "Count must be even\n";
175 return EXIT_FAILURE;
176 }
177
178 // Each iteration does 2 transactions
179 count /= 2;
180 for (uint32_t i = 0; i < count; ++i) {
181 constexpr uint32_t PMU_PWRDN_SCRATCH16 = 0x400000d4; // Scratch 16
182
183 // Write a random value (SPI transaction 1)
184 const uint32_t value = dis(gen);
185 if (!WriteRegister(client, PMU_PWRDN_SCRATCH16, value)) {
186 std::cerr << "Failed to write " << ToHexString(value) << " to scratch register 16\n";
187 return EXIT_FAILURE;
188 }
189
190 // Read back the value (SPI transaction 2)
191 uint32_t check_value;
192 if (!ReadRegister(client, PMU_PWRDN_SCRATCH16, &check_value)) {
193 std::cerr << "Failed to read scratch register 16\n";
194 return EXIT_FAILURE;
195 }
196
197 // Check the value wasn't corrupted
198 if (check_value != value) {
199 std::cerr << "Fail: expected to read " << ToHexString(value) << " but got "
200 << ToHexString(check_value);
201 return EXIT_FAILURE;
202 }
203 }
204
205 // If we got here, we know that the test passed
206 std::cout << "stress-spi passed!\n";
207
208 return EXIT_SUCCESS;
209 }
210
211 /*
212 * The current implementation directly reads some registers and checks they
213 * contain valid values.
214 * TODO(b/65067435): Replace with less intrusive calls.
215 */
CmdHealthCheck(NuggetClientInterface & client)216 int CmdHealthCheck(NuggetClientInterface& client) {
217 int ret = EXIT_SUCCESS;
218
219 constexpr uint32_t TRNG_FSM_STATE = 0x4041002c;
220 if (!CheckRegisterNotInRange(client, TRNG_FSM_STATE, 0x1, 0x1)) {
221 std::cerr << "TRNG_FSM_STATE is not healthy\n";
222 ret = EXIT_FAILURE;
223 }
224
225 constexpr uint32_t TRNG_MAX_VALUE = 0x40410040;
226 if (!CheckRegisterInRange(client, TRNG_MAX_VALUE, 0x0, 0xfffe)) {
227 std::cerr << "TRNG_MAX_VALUE is not healthy\n";
228 ret = EXIT_FAILURE;
229 }
230
231 constexpr uint32_t TRNG_MIN_VALUE = 0x40410044;
232 if (!CheckRegisterInRange(client, TRNG_MIN_VALUE, 0x10, 0x200)) {
233 std::cerr << "TRNG_MIN_VALUE is not healthy\n";
234 ret = EXIT_FAILURE;
235 }
236
237 constexpr uint32_t TRNG_CUR_NUM_ONES = 0x4041008c;
238 if (!CheckRegisterInRange(client, TRNG_CUR_NUM_ONES, 0x334, 0x4cc)) {
239 std::cerr << "TRNG_CUR_NUM_ONES is not healthy\n";
240 ret = EXIT_FAILURE;
241 }
242
243 constexpr uint32_t PMU_RSTSRC = 0x40000000;
244 if (!CheckRegisterInRange(client, PMU_RSTSRC, 0x0, 0x3)) {
245 std::cerr << "PMU_RSTSRC is not healthy\n";
246 ret = EXIT_FAILURE;
247 }
248
249 constexpr uint32_t GLOBALSEC_ALERT_INTR_STS0 = 0x40104004;
250 if (!CheckRegisterInRange(client, GLOBALSEC_ALERT_INTR_STS0, 0x0, 0x0)) {
251 std::cerr << "GLOBALSEC_ALERT_INTR_STS0 is not healthy\n";
252 ret = EXIT_FAILURE;
253 }
254
255 constexpr uint32_t GLOBALSEC_ALERT_INTR_STS1 = 0x40104008;
256 if (!CheckRegisterInRange(client, GLOBALSEC_ALERT_INTR_STS1, 0x0, 0x0)) {
257 std::cerr << "GLOBALSEC_ALERT_INTR_STS1 is not healthy\n";
258 ret = EXIT_FAILURE;
259 }
260
261 if (ret == EXIT_SUCCESS) {
262 // If we got here, we know that the test passed
263 std::cout << "health-check passed!\n";
264 }
265
266 return ret;
267 }
268
CmdReset(CitadeldProxyClient & client)269 int CmdReset(CitadeldProxyClient& client) {
270 // Request a hard reset of the device
271 bool success = false;
272 if (!client.Citadeld().reset(&success).isOk()) {
273 std::cerr << "Failed to talk to citadeld\n";
274 return EXIT_FAILURE;
275 }
276 if (!success) {
277 std::cerr << "Failed to reset Citadel\n";
278 return EXIT_FAILURE;
279 }
280
281 // Check the cycle count which should have been reset by the reset. It
282 // should be equivalent to around the time we just waited for but give it a
283 // 5% margin.
284 uint32_t cycles;
285 if (!CyclesSinceBoot(client, &cycles)) {
286 std::cerr << "Citadel did not boot! No indication of cycles since boot\n";
287 return EXIT_FAILURE;
288 }
289 const auto uptime = std::chrono::microseconds(cycles);
290 const auto bringup = std::chrono::milliseconds(100);
291 const auto limit = std::chrono::duration_cast<std::chrono::microseconds>(bringup) * 105 / 100;
292 if (uptime > limit) {
293 LOG(ERROR) << "Uptime is " << uptime.count()
294 << "us but is expected to be less than " << limit.count() << "us\n";
295 std::cerr << "Citadel appears to have not reset, cycles since boot is too high\n";
296 return EXIT_FAILURE;
297 }
298
299 std::cout << "Citadel booted successully after reset\n";
300 return EXIT_SUCCESS;
301 }
302
303 /**
304 * Enable battery monitors, TRNG stats, TRNG camo blocks for coex testing
305 */
CmdEnableAlerts(CitadeldProxyClient & client)306 int CmdEnableAlerts(CitadeldProxyClient& client) {
307
308 constexpr uint32_t TRNG_MONITOR_STATS = 0x40410010;
309 // Enable NIST monobit statistical check
310 if (!WriteRegister(client, TRNG_MONITOR_STATS, 0x3)) {
311 std::cerr << "Failed to write to TRNG_MONITOR_STATS\n";
312 return EXIT_FAILURE;
313 }
314
315 constexpr uint32_t TRNG_CAMO_EN = 0x40410068;
316 // Turn on active camo shield over TRNG analog core
317 if (!WriteRegister(client, TRNG_CAMO_EN, 0x1)) {
318 std::cerr << "Failed to write to TRNG_CAMO_EN\n";
319 return EXIT_FAILURE;
320 }
321
322 constexpr uint32_t PMU_SW_PDB_SECURE = 0x4000002c;
323 // Turn on battery monitors: VDDIOM, VDDAON and VDDL
324 if (!WriteRegister(client, PMU_SW_PDB_SECURE, 0x15)) {
325 std::cerr << "Failed to write to PMU_SW_PDB_SECURE\n";
326 return EXIT_FAILURE;
327 }
328
329 // Wait for battery monitors to settle
330 usleep(1000);
331
332 // Turn on battery monitor alerts: VDDIOM, VDDAON and VDDL
333 if (!WriteRegister(client, PMU_SW_PDB_SECURE, 0x3f)) {
334 std::cerr << "Failed to write to PMU_SW_PDB_SECURE\n";
335 return EXIT_FAILURE;
336 }
337
338 std::cout << "Analog alerts enabled\n";
339
340 return EXIT_SUCCESS;
341
342 }
343
CmdDisableAlerts(CitadeldProxyClient & client)344 int CmdDisableAlerts(CitadeldProxyClient& client) {
345
346 constexpr uint32_t TRNG_MONITOR_STATS = 0x40410010;
347 // Disable NIST monobit statistical check
348 if (!WriteRegister(client, TRNG_MONITOR_STATS, 0x1)) {
349 std::cerr << "Failed to write to TRNG_MONITOR_STATS\n";
350 return EXIT_FAILURE;
351 }
352
353 constexpr uint32_t TRNG_CAMO_EN = 0x40410068;
354 // Turn off active camo shield over TRNG analog core
355 if (!WriteRegister(client, TRNG_CAMO_EN, 0x0)) {
356 std::cerr << "Failed to write to TRNG_CAMO_EN\n";
357 return EXIT_FAILURE;
358 }
359
360 constexpr uint32_t PMU_SW_PDB_SECURE = 0x4000002c;
361 // Turn off battery monitors: VDDIOM, VDDAON and VDDL
362 if (!WriteRegister(client, PMU_SW_PDB_SECURE, 0x0)) {
363 std::cerr << "Failed to write to PMU_SW_PDB_SECURE\n";
364 return EXIT_FAILURE;
365 }
366
367 std::cout << "Analog alerts disabled\n";
368
369 return EXIT_SUCCESS;
370
371 }
372
373 /* Turn on Citadel's temperature sensor and read value */
CmdGetTemp(CitadeldProxyClient & client)374 int CmdGetTemp(CitadeldProxyClient& client) {
375
376 constexpr uint32_t TEMP_ADC_OPERATION = 0x40400028;
377 // Disable temperature sensor
378 if (!WriteRegister(client, TEMP_ADC_OPERATION, 0x0)) {
379 std::cerr << "Failed to write to TEMP_ADC_OPERATION\n";
380 return EXIT_FAILURE;
381 }
382
383 constexpr uint32_t TEMP_ADC_POWER_DOWN_B = 0x40400024;
384 // Disable temperature sensor analog core
385 if (!WriteRegister(client, TEMP_ADC_POWER_DOWN_B, 0x0)) {
386 std::cerr << "Failed to write to TEMP_ADC_POWER_DOWN_B\n";
387 return EXIT_FAILURE;
388 }
389
390 constexpr uint32_t TEMP_ADC_CLKDIV2_ENABLE = 0x4040001c;
391 // Divide clock into temperature sensor
392 if (!WriteRegister(client, TEMP_ADC_CLKDIV2_ENABLE, 0x1)) {
393 std::cerr << "Failed to write to TEMP_ADC_CLKDIV2_ENABLE\n";
394 return EXIT_FAILURE;
395 }
396
397 constexpr uint32_t TEMP_ADC_ANALOG_CTRL = 0x40400014;
398 // Configure temperature sensor analog controls
399 if (!WriteRegister(client, TEMP_ADC_ANALOG_CTRL, 0x33)) {
400 std::cerr << "Failed to write to TEMP_ADC_ANALOG_CTRL\n";
401 return EXIT_FAILURE;
402 }
403
404 constexpr uint32_t TEMP_ADC_FSM_CTRL = 0x40400018;
405 // Configure temperature sensor FSM
406 if (!WriteRegister(client, TEMP_ADC_FSM_CTRL, 0x3986e)) {
407 std::cerr << "Failed to write to TEMP_ADC_FSM_CTRL\n";
408 return EXIT_FAILURE;
409 }
410
411 // Enable temperature sensor analog core
412 if (!WriteRegister(client, TEMP_ADC_POWER_DOWN_B, 0x1)) {
413 std::cerr << "Failed to write to TEMP_ADC_POWER_DOWN_B\n";
414 return EXIT_FAILURE;
415 }
416
417 // Enable temperature sensor
418 if (!WriteRegister(client, TEMP_ADC_OPERATION, 0x1)) {
419 std::cerr << "Failed to write to TEMP_ADC_OPERATION\n";
420 return EXIT_FAILURE;
421 }
422 if (!WriteRegister(client, TEMP_ADC_OPERATION, 0x3)) {
423 std::cerr << "Failed to write to TEMP_ADC_OPERATION\n";
424 return EXIT_FAILURE;
425 }
426
427 /* temperature sensor is on, now get an actual averaged
428 reading */
429
430 constexpr uint32_t TEMP_ADC_ONESHOT_ACQ = 0x40400020;
431 constexpr uint32_t TEMP_ADC_SUM8 = 0x40400038;
432 uint32_t current_temp;
433 // Configure temperature sensor FSM
434 if (!WriteRegister(client, TEMP_ADC_ONESHOT_ACQ, 0x0)) {
435 std::cerr << "Failed to write to TEMP_ADC_ONESHOT_ACQ\n";
436 return EXIT_FAILURE;
437 }
438
439 for (uint32_t i = 0; i < 16; ++i) {
440 // trigger acquisition
441 if (!WriteRegister(client, TEMP_ADC_ONESHOT_ACQ, 0x0)) {
442 std::cerr << "Failed to write to TEMP_ADC_ONESHOT_ACQ\n";
443 return EXIT_FAILURE;
444 }
445 if (!WriteRegister(client, TEMP_ADC_ONESHOT_ACQ, 0x1)) {
446 std::cerr << "Failed to write to TEMP_ADC_ONESHOT_ACQ\n";
447 return EXIT_FAILURE;
448 }
449
450 // wait for acquisition
451 usleep(50000);
452
453 // grab value
454 if (!ReadRegister(client, TEMP_ADC_SUM8, ¤t_temp)) {
455 std::cerr << "Failed to read TEMP_ADC_SUM8\n";
456 return EXIT_FAILURE;
457 }
458 //std::cout << "Current tempval = " << ToHexString(current_temp) << "\n";
459 }
460
461 std::cout << "Current tempval = " << ToHexString(current_temp) << "\n";
462
463 constexpr uint32_t FUSE_TEMP_OFFSET_CAL = 0x404800b4;
464 uint32_t temp_offset, slope, temp_degc;
465 // Configure temperature sensor FSM
466 if (!ReadRegister(client, FUSE_TEMP_OFFSET_CAL, &temp_offset)) {
467 std::cerr << "Failed to read FUSE_TEMP_OFFSET_CAL\n";
468 return EXIT_FAILURE;
469 }
470
471 // Now convert to degC
472 temp_offset = temp_offset & 0xfff; //only 12b value
473 slope = (875<<3)/1000; // TEMP_ADC_SUM8 is 9.3b fixed point
474 temp_degc = (((current_temp - temp_offset) << 3)/slope) >> 3; // just grab integer value
475
476 std::cout << "Current temperature = " << ToDecString(temp_degc) << "C\n";
477
478 return EXIT_SUCCESS;
479
480 }
481
482 } // namespace
483
484 /**
485 * This utility invokes the citadeld device checks and reports the results.
486 */
main(int argc,char ** argv)487 int main(int argc, char** argv) {
488 // Connect to citadeld
489 CitadeldProxyClient citadeldProxy;
490 citadeldProxy.Open();
491 if (!citadeldProxy.IsOpen()) {
492 std::cerr << "Failed to open citadeld client\n";
493 }
494
495 if (argc >= 2) {
496 const std::string command(argv[1]);
497 char** params = &argv[2];
498 const int param_count = argc - 2;
499
500 if (command == "stress-spi" && param_count == 1) {
501 return CmdStressSpi(citadeldProxy, params);
502 }
503 if (command == "health-check" && param_count == 0) {
504 return CmdHealthCheck(citadeldProxy);
505 }
506 if (command == "reset" && param_count == 0) {
507 return CmdReset(citadeldProxy);
508 }
509 if (command == "enable-alerts" && param_count == 0) {
510 return CmdEnableAlerts(citadeldProxy);
511 }
512 if (command == "disable-alerts" && param_count == 0) {
513 return CmdDisableAlerts(citadeldProxy);
514 }
515 if (command == "get-temp" && param_count == 0) {
516 return CmdGetTemp(citadeldProxy);
517 }
518 }
519
520 // Print usage if all else failed
521 std::cerr << "Usage:\n";
522 std::cerr << " " << argv[0] << " stress-spi [count] -- perform count SPI transactions\n";
523 std::cerr << " " << argv[0] << " health-check -- check Citadel's vital signs\n";
524 std::cerr << " " << argv[0] << " reset -- pull Citadel's reset line\n";
525 std::cerr << " " << argv[0] << " enable-alerts -- enable analog alert blocks\n";
526 std::cerr << " " << argv[0] << " disable-alerts -- disable analog alert blocks\n";
527 std::cerr << " " << argv[0] << " get-temp -- get temperature from temp sensor\n";
528 std::cerr << "\n";
529 std::cerr << "Returns 0 on success and non-0 if any failure were detected.\n";
530 return EXIT_FAILURE;
531 }
532