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, &current_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