1 // Copyright 2016 The Fuchsia Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #pragma once
6 
7 #include <ddk/device.h>
8 #include <zircon/types.h>
9 #include <zircon/thread_annotations.h>
10 #include <stddef.h>
11 #include <stdint.h>
12 
13 #if __cplusplus
14 
15 #include <ddktl/device.h>
16 #include <ddktl/protocol/empty-protocol.h>
17 #include <fbl/mutex.h>
18 #include <fbl/unique_ptr.h>
19 
20 namespace tpm {
21 
22 typedef uint8_t Locality;
23 
24 // Abstraction over the hardware access mechanism.  The communication protocol
25 // relies on accessing certain hardware registers which have the same contents
26 // regardless of access mechanism.
27 class HardwareInterface {
28 public:
~HardwareInterface()29     virtual ~HardwareInterface() { }
30 
31     // Return ZX_OK if the device represented by this interface is valid under
32     // the interface's constraints.  This may perform IO to determine the
33     // answer, and will be called before the device is made visible to the rest
34     // of the system.
Validate()35     virtual zx_status_t Validate() { return ZX_OK; }
36 
37     // Read/write the ACCESS register for the given locality
38     virtual zx_status_t ReadAccess(Locality loc, uint8_t* access) = 0;
39     virtual zx_status_t WriteAccess(Locality loc, uint8_t access) = 0;
40 
41     // Read/write the STS register for the given locality
42     virtual zx_status_t ReadStatus(Locality loc, uint32_t* sts) = 0;
43     virtual zx_status_t WriteStatus(Locality loc, uint32_t sts) = 0;
44 
45     // Read the DID_VID register, if present
46     virtual zx_status_t ReadDidVid(uint16_t* vid, uint16_t* did) = 0;
47 
48     // Read/write from the DATA_FIFO register.  It is up to the caller to respect the
49     // protocol's burstCount.
50     virtual zx_status_t ReadDataFifo(Locality loc, uint8_t* buf, size_t len) = 0;
51     virtual zx_status_t WriteDataFifo(Locality loc, const uint8_t* buf, size_t len) = 0;
52 };
53 
54 class Device;
55 using DeviceType = ddk::Device<Device, ddk::Suspendable>;
56 
57 class Device : public DeviceType,
58                public ddk::EmptyProtocol<ZX_PROTOCOL_TPM> {
59 public:
60     Device(zx_device_t* parent, fbl::unique_ptr<HardwareInterface> iface);
61     ~Device();
62 
63     // Send the given command packet to the TPM and wait for a response.
64     // |actual| is the number of bytes written into |resp|.
65     zx_status_t ExecuteCmd(Locality loc, const uint8_t* cmd, size_t len,
66                            uint8_t* resp, size_t max_len, size_t* actual);
67 
68     // DDK methods
69     void DdkRelease();
70     zx_status_t DdkSuspend(uint32_t flags);
71 
72     // Register this instance with devmgr and launch the deferred
73     // initialization.
74     zx_status_t Bind();
75 private:
76     // Deferred initialization of the device via a thread.  Once complete, this
77     // marks the device as visible.
Init(void * device)78     static zx_status_t Init(void* device) {
79         return reinterpret_cast<Device*>(device)->Init();
80     }
81     zx_status_t Init();
82 
83     // Send the given command packet to the TPM and wait for a response.
84     // |actual| is the number of bytes written into |resp|.
85     zx_status_t ExecuteCmdLocked(Locality loc, const uint8_t* cmd, size_t len,
86                                  uint8_t* resp, size_t max_len, size_t* actual) TA_REQ(lock_);
87 
88     // Request use of the given locality
89     zx_status_t RequestLocalityLocked(Locality loc) TA_REQ(lock_);
90     // Wait for access to the requested locality
91     zx_status_t WaitForLocalityLocked(Locality loc) TA_REQ(lock_);
92     // Release the given locality
93     zx_status_t ReleaseLocalityLocked(Locality loc) TA_REQ(lock_);
94 
95     // Perform the transmit half of a command
96     zx_status_t SendCmdLocked(Locality loc, const uint8_t* cmd, size_t len) TA_REQ(lock_);
97     // Perform the receive half of a command.  |actual| will contain the total number of bytes in
98     // the response, may be less than max_len.
99     zx_status_t RecvRespLocked(Locality loc, uint8_t* resp, size_t max_len,
100                                size_t* actual) TA_REQ(lock_);
101 
102     // Issue a TPM_CC_SHUTDOWN with the given type
103     zx_status_t ShutdownLocked(uint16_t type) TA_REQ(lock_);
104 
105     fbl::Mutex lock_;
106     const fbl::unique_ptr<HardwareInterface> iface_;
107 };
108 
109 enum tpm_result {
110     TPM_SUCCESS = 0x0,
111     TPM_BAD_PARAMETER = 0x3,
112     TPM_DEACTIVATED = 0x6,
113     TPM_DISABLED = 0x7,
114     TPM_DISABLED_CMD = 0x8,
115     TPM_FAIL = 0x9,
116     TPM_BAD_ORDINAL = 0xa,
117     TPM_RETRY = 0x800,
118 };
119 
120 } // namespace tpm
121 
122 #endif // __cplusplus
123 
124 __BEGIN_CDECLS
125 zx_status_t tpm_bind(void* ctx, zx_device_t* parent);
126 __END_CDECLS
127