#include #include #include #include #include #include #include #include #include enum tis_access { TPM_ACCESS_VALID = 0x80, TPM_ACCESS_ACTIVE_LOCALITY = 0x20, TPM_ACCESS_REQUEST_PENDING = 0x04, TPM_ACCESS_REQUEST_USE = 0x02, }; enum tis_status { TPM_STS_VALID = 0x80, TPM_STS_COMMAND_READY = 0x40, TPM_STS_GO = 0x20, TPM_STS_DATA_AVAIL = 0x10, TPM_STS_DATA_EXPECT = 0x08, }; #define TPM_ACCESS(l) (0x0000 | ((l) << 12)) #define TPM_STS(l) (0x0018 | ((l) << 12)) int main(void) { int fd; void *map; volatile uint8_t *access; volatile uint8_t *sts; unsigned long long i; fd = open("/dev/mem", O_RDWR | O_DSYNC); if (fd == -1) { perror("open"); return EXIT_FAILURE; } map = mmap(NULL, 0x5000, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0xfed40000); if (map == MAP_FAILED) { perror("mmap"); return EXIT_FAILURE; } access = (uint8_t *)map + TPM_ACCESS(0); sts = (uint8_t *)map + TPM_STS(0); i = 0; for (;;) { struct timespec stop, now; uint32_t burstcnt; uint8_t sts_read; *access = TPM_ACCESS_REQUEST_USE; while ((*access & (TPM_ACCESS_ACTIVE_LOCALITY | TPM_ACCESS_VALID)) != (TPM_ACCESS_ACTIVE_LOCALITY | TPM_ACCESS_VALID)) ; sts_read = *sts; #if 0 if (sts_read == 0xff) sts_read = *sts; #endif if (!(sts_read & TPM_STS_COMMAND_READY)) { *sts = TPM_STS_COMMAND_READY; while (!(*sts & TPM_STS_COMMAND_READY)) ; } clock_gettime(CLOCK_MONOTONIC, &stop); stop.tv_sec += 1; for (;;) { burstcnt = ((*(volatile uint32_t *)sts) >> 8) & 0xffff; if (burstcnt) break; clock_gettime(CLOCK_MONOTONIC, &now); if (now.tv_sec > stop.tv_sec || (now.tv_sec == stop.tv_sec && now.tv_nsec >= stop.tv_nsec)) { fprintf(stderr, "Timed out after %llu iterations\n", i); i = 0; break; } } *access = TPM_ACCESS_ACTIVE_LOCALITY; while ((*access & (TPM_ACCESS_ACTIVE_LOCALITY | TPM_ACCESS_VALID)) != TPM_ACCESS_VALID) ; i++; } return EXIT_SUCCESS; }