xref: /aosp_15_r20/external/ms-tpm-20-ref/TPMCmd/tpm/src/subsystem/NvDynamic.c (revision 5c591343844d1f9da7da26467c4bf7efc8a7a413)
1*5c591343SA. Cody Schuffelen /* Microsoft Reference Implementation for TPM 2.0
2*5c591343SA. Cody Schuffelen  *
3*5c591343SA. Cody Schuffelen  *  The copyright in this software is being made available under the BSD License,
4*5c591343SA. Cody Schuffelen  *  included below. This software may be subject to other third party and
5*5c591343SA. Cody Schuffelen  *  contributor rights, including patent rights, and no such rights are granted
6*5c591343SA. Cody Schuffelen  *  under this license.
7*5c591343SA. Cody Schuffelen  *
8*5c591343SA. Cody Schuffelen  *  Copyright (c) Microsoft Corporation
9*5c591343SA. Cody Schuffelen  *
10*5c591343SA. Cody Schuffelen  *  All rights reserved.
11*5c591343SA. Cody Schuffelen  *
12*5c591343SA. Cody Schuffelen  *  BSD License
13*5c591343SA. Cody Schuffelen  *
14*5c591343SA. Cody Schuffelen  *  Redistribution and use in source and binary forms, with or without modification,
15*5c591343SA. Cody Schuffelen  *  are permitted provided that the following conditions are met:
16*5c591343SA. Cody Schuffelen  *
17*5c591343SA. Cody Schuffelen  *  Redistributions of source code must retain the above copyright notice, this list
18*5c591343SA. Cody Schuffelen  *  of conditions and the following disclaimer.
19*5c591343SA. Cody Schuffelen  *
20*5c591343SA. Cody Schuffelen  *  Redistributions in binary form must reproduce the above copyright notice, this
21*5c591343SA. Cody Schuffelen  *  list of conditions and the following disclaimer in the documentation and/or
22*5c591343SA. Cody Schuffelen  *  other materials provided with the distribution.
23*5c591343SA. Cody Schuffelen  *
24*5c591343SA. Cody Schuffelen  *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ""AS IS""
25*5c591343SA. Cody Schuffelen  *  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26*5c591343SA. Cody Schuffelen  *  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
27*5c591343SA. Cody Schuffelen  *  DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
28*5c591343SA. Cody Schuffelen  *  ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
29*5c591343SA. Cody Schuffelen  *  (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
30*5c591343SA. Cody Schuffelen  *  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
31*5c591343SA. Cody Schuffelen  *  ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
32*5c591343SA. Cody Schuffelen  *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
33*5c591343SA. Cody Schuffelen  *  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34*5c591343SA. Cody Schuffelen  */
35*5c591343SA. Cody Schuffelen //** Introduction
36*5c591343SA. Cody Schuffelen 
37*5c591343SA. Cody Schuffelen // The NV memory is divided into two areas: dynamic space for user defined NV
38*5c591343SA. Cody Schuffelen // indexes and evict objects, and reserved space for TPM persistent and state save
39*5c591343SA. Cody Schuffelen // data.
40*5c591343SA. Cody Schuffelen //
41*5c591343SA. Cody Schuffelen // The entries in dynamic space are a linked list of entries. Each entry has, as its
42*5c591343SA. Cody Schuffelen // first field, a size. If the size field is zero, it marks the end of the
43*5c591343SA. Cody Schuffelen // list.
44*5c591343SA. Cody Schuffelen //
45*5c591343SA. Cody Schuffelen // An Index allocation will contain an NV_INDEX structure. If the Index does not
46*5c591343SA. Cody Schuffelen // have the orderly attribute, the NV_INDEX is followed immediately by the NV data.
47*5c591343SA. Cody Schuffelen //
48*5c591343SA. Cody Schuffelen // An evict object entry contains a handle followed by an OBJECT structure. This
49*5c591343SA. Cody Schuffelen // results in both the Index and Evict Object having an identifying handle as the
50*5c591343SA. Cody Schuffelen // first field following the size field.
51*5c591343SA. Cody Schuffelen //
52*5c591343SA. Cody Schuffelen // When an Index has the orderly attribute, the data is kept in RAM. This RAM is
53*5c591343SA. Cody Schuffelen // saved to backing store in NV memory on any orderly shutdown. The entries in
54*5c591343SA. Cody Schuffelen // orderly memory are also a linked list using a size field as the first entry.
55*5c591343SA. Cody Schuffelen //
56*5c591343SA. Cody Schuffelen // The attributes of an orderly index are maintained in RAM memory in order to
57*5c591343SA. Cody Schuffelen // reduce the number of NV writes needed for orderly data. When an orderly index
58*5c591343SA. Cody Schuffelen // is created, an entry is made in the dynamic NV memory space that holds the Index
59*5c591343SA. Cody Schuffelen // authorizations (authPolicy and authValue) and the size of the data. This entry is
60*5c591343SA. Cody Schuffelen // only modified if the authValue  of the index is changed. The more volatile data
61*5c591343SA. Cody Schuffelen // of the index is kept in RAM. When an orderly Index is created or deleted, the
62*5c591343SA. Cody Schuffelen // RAM data is copied to NV backing store so that the image in the backing store
63*5c591343SA. Cody Schuffelen // matches the layout of RAM. In normal operation. The RAM data is also copied on
64*5c591343SA. Cody Schuffelen // any orderly shutdown. In normal operation, the only other reason for writing
65*5c591343SA. Cody Schuffelen // to the backing store for RAM is when a counter is first written (TPMA_NV_WRITTEN
66*5c591343SA. Cody Schuffelen // changes from CLEAR to SET) or when a counter ""rolls over"".
67*5c591343SA. Cody Schuffelen //
68*5c591343SA. Cody Schuffelen // Static space contains items that are individually modifiable. The values are in
69*5c591343SA. Cody Schuffelen // the 'gp' PERSISTENT_DATA structure in RAM and mapped to locations in NV.
70*5c591343SA. Cody Schuffelen //
71*5c591343SA. Cody Schuffelen 
72*5c591343SA. Cody Schuffelen //** Includes, Defines and Data Definitions
73*5c591343SA. Cody Schuffelen #define NV_C
74*5c591343SA. Cody Schuffelen #include "Tpm.h"
75*5c591343SA. Cody Schuffelen 
76*5c591343SA. Cody Schuffelen //** Local Functions
77*5c591343SA. Cody Schuffelen 
78*5c591343SA. Cody Schuffelen 
79*5c591343SA. Cody Schuffelen //*** NvNext()
80*5c591343SA. Cody Schuffelen //  This function provides a method to traverse every data entry in NV dynamic
81*5c591343SA. Cody Schuffelen //  area.
82*5c591343SA. Cody Schuffelen //
83*5c591343SA. Cody Schuffelen //  To begin with, parameter 'iter' should be initialized to NV_REF_INIT
84*5c591343SA. Cody Schuffelen //  indicating the first element.  Every time this function is called, the
85*5c591343SA. Cody Schuffelen //  value in 'iter' would be adjusted pointing to the next element in
86*5c591343SA. Cody Schuffelen //  traversal.  If there is no next element, 'iter' value would be 0.
87*5c591343SA. Cody Schuffelen //  This function returns the address of the 'data entry' pointed by the
88*5c591343SA. Cody Schuffelen //  'iter'.  If there are no more elements in the set, a 0 value is returned
89*5c591343SA. Cody Schuffelen //  indicating the end of traversal.
90*5c591343SA. Cody Schuffelen //
91*5c591343SA. Cody Schuffelen static NV_REF
NvNext(NV_REF * iter,TPM_HANDLE * handle)92*5c591343SA. Cody Schuffelen NvNext(
93*5c591343SA. Cody Schuffelen     NV_REF          *iter,          // IN/OUT: the list iterator
94*5c591343SA. Cody Schuffelen     TPM_HANDLE      *handle         // OUT: the handle of the next item.
95*5c591343SA. Cody Schuffelen     )
96*5c591343SA. Cody Schuffelen {
97*5c591343SA. Cody Schuffelen     NV_REF               currentAddr;
98*5c591343SA. Cody Schuffelen     NV_ENTRY_HEADER      header;
99*5c591343SA. Cody Schuffelen //
100*5c591343SA. Cody Schuffelen     // If iterator is at the beginning of list
101*5c591343SA. Cody Schuffelen     if(*iter == NV_REF_INIT)
102*5c591343SA. Cody Schuffelen     {
103*5c591343SA. Cody Schuffelen         // Initialize iterator
104*5c591343SA. Cody Schuffelen         *iter = NV_USER_DYNAMIC;
105*5c591343SA. Cody Schuffelen     }
106*5c591343SA. Cody Schuffelen     // Step over the size field and point to the handle
107*5c591343SA. Cody Schuffelen     currentAddr = *iter + sizeof(UINT32);
108*5c591343SA. Cody Schuffelen 
109*5c591343SA. Cody Schuffelen     // read the header of the next entry
110*5c591343SA. Cody Schuffelen     NvRead(&header, *iter, sizeof(NV_ENTRY_HEADER));
111*5c591343SA. Cody Schuffelen 
112*5c591343SA. Cody Schuffelen     // if the size field is zero, then we have hit the end of the list
113*5c591343SA. Cody Schuffelen     if(header.size == 0)
114*5c591343SA. Cody Schuffelen         // leave the *iter pointing at the end of the list
115*5c591343SA. Cody Schuffelen         return 0;
116*5c591343SA. Cody Schuffelen     // advance the header by the size of the entry
117*5c591343SA. Cody Schuffelen     *iter += header.size;
118*5c591343SA. Cody Schuffelen 
119*5c591343SA. Cody Schuffelen     if(handle != NULL)
120*5c591343SA. Cody Schuffelen         *handle = header.handle;
121*5c591343SA. Cody Schuffelen     return currentAddr;
122*5c591343SA. Cody Schuffelen }
123*5c591343SA. Cody Schuffelen 
124*5c591343SA. Cody Schuffelen 
125*5c591343SA. Cody Schuffelen //*** NvNextByType()
126*5c591343SA. Cody Schuffelen // This function returns a reference to the next NV entry of the desired type
127*5c591343SA. Cody Schuffelen //  Return Type: NV_REF
128*5c591343SA. Cody Schuffelen //      0               end of list
129*5c591343SA. Cody Schuffelen //      != 0            the next entry of the indicated type
130*5c591343SA. Cody Schuffelen static NV_REF
NvNextByType(TPM_HANDLE * handle,NV_REF * iter,TPM_HT type)131*5c591343SA. Cody Schuffelen NvNextByType(
132*5c591343SA. Cody Schuffelen     TPM_HANDLE      *handle,        // OUT: the handle of the found type or 0
133*5c591343SA. Cody Schuffelen     NV_REF          *iter,          // IN: the iterator
134*5c591343SA. Cody Schuffelen     TPM_HT           type           // IN: the handle type to look for
135*5c591343SA. Cody Schuffelen     )
136*5c591343SA. Cody Schuffelen {
137*5c591343SA. Cody Schuffelen     NV_REF           addr;
138*5c591343SA. Cody Schuffelen     TPM_HANDLE       nvHandle = 0;
139*5c591343SA. Cody Schuffelen //
140*5c591343SA. Cody Schuffelen     while((addr = NvNext(iter, &nvHandle)) != 0)
141*5c591343SA. Cody Schuffelen     {
142*5c591343SA. Cody Schuffelen         // addr: the address of the location containing the handle of the value
143*5c591343SA. Cody Schuffelen         // iter: the next location.
144*5c591343SA. Cody Schuffelen         if(HandleGetType(nvHandle) == type)
145*5c591343SA. Cody Schuffelen             break;
146*5c591343SA. Cody Schuffelen     }
147*5c591343SA. Cody Schuffelen     if(handle != NULL)
148*5c591343SA. Cody Schuffelen         *handle = nvHandle;
149*5c591343SA. Cody Schuffelen     return addr;
150*5c591343SA. Cody Schuffelen }
151*5c591343SA. Cody Schuffelen 
152*5c591343SA. Cody Schuffelen //*** NvNextIndex()
153*5c591343SA. Cody Schuffelen // This function returns the reference to the next NV Index entry.  A value
154*5c591343SA. Cody Schuffelen // of 0 indicates the end of the list.
155*5c591343SA. Cody Schuffelen //  Return Type: NV_REF
156*5c591343SA. Cody Schuffelen //      0               end of list
157*5c591343SA. Cody Schuffelen //      != 0            the next reference
158*5c591343SA. Cody Schuffelen #define NvNextIndex(handle, iter)                   \
159*5c591343SA. Cody Schuffelen     NvNextByType(handle, iter, TPM_HT_NV_INDEX)
160*5c591343SA. Cody Schuffelen 
161*5c591343SA. Cody Schuffelen //*** NvNextEvict()
162*5c591343SA. Cody Schuffelen // This function returns the offset in NV of the next evict object entry.  A value
163*5c591343SA. Cody Schuffelen // of 0 indicates the end of the list.
164*5c591343SA. Cody Schuffelen #define NvNextEvict(handle, iter)                   \
165*5c591343SA. Cody Schuffelen     NvNextByType(handle, iter, TPM_HT_PERSISTENT)
166*5c591343SA. Cody Schuffelen 
167*5c591343SA. Cody Schuffelen //*** NvGetEnd()
168*5c591343SA. Cody Schuffelen // Function to find the end of the NV dynamic data list
169*5c591343SA. Cody Schuffelen static NV_REF
NvGetEnd(void)170*5c591343SA. Cody Schuffelen NvGetEnd(
171*5c591343SA. Cody Schuffelen     void
172*5c591343SA. Cody Schuffelen     )
173*5c591343SA. Cody Schuffelen {
174*5c591343SA. Cody Schuffelen     NV_REF          iter = NV_REF_INIT;
175*5c591343SA. Cody Schuffelen     NV_REF          currentAddr;
176*5c591343SA. Cody Schuffelen //
177*5c591343SA. Cody Schuffelen     // Scan until the next address is 0
178*5c591343SA. Cody Schuffelen     while((currentAddr = NvNext(&iter, NULL)) != 0);
179*5c591343SA. Cody Schuffelen     return iter;
180*5c591343SA. Cody Schuffelen }
181*5c591343SA. Cody Schuffelen 
182*5c591343SA. Cody Schuffelen //*** NvGetFreeBytes
183*5c591343SA. Cody Schuffelen // This function returns the number of free octets in NV space.
184*5c591343SA. Cody Schuffelen static UINT32
NvGetFreeBytes(void)185*5c591343SA. Cody Schuffelen NvGetFreeBytes(
186*5c591343SA. Cody Schuffelen     void
187*5c591343SA. Cody Schuffelen     )
188*5c591343SA. Cody Schuffelen {
189*5c591343SA. Cody Schuffelen     // This does not have an overflow issue because NvGetEnd() cannot return a value
190*5c591343SA. Cody Schuffelen     // that is larger than s_evictNvEnd. This is because there is always a 'stop'
191*5c591343SA. Cody Schuffelen     // word in the NV memory that terminates the search for the end before the
192*5c591343SA. Cody Schuffelen     // value can go past s_evictNvEnd.
193*5c591343SA. Cody Schuffelen     return s_evictNvEnd - NvGetEnd();
194*5c591343SA. Cody Schuffelen }
195*5c591343SA. Cody Schuffelen 
196*5c591343SA. Cody Schuffelen //*** NvTestSpace()
197*5c591343SA. Cody Schuffelen // This function will test if there is enough space to add a new entity.
198*5c591343SA. Cody Schuffelen //  Return Type: BOOL
199*5c591343SA. Cody Schuffelen //      TRUE(1)         space available
200*5c591343SA. Cody Schuffelen //      FALSE(0)        no enough space
201*5c591343SA. Cody Schuffelen static BOOL
NvTestSpace(UINT32 size,BOOL isIndex,BOOL isCounter)202*5c591343SA. Cody Schuffelen NvTestSpace(
203*5c591343SA. Cody Schuffelen     UINT32           size,          // IN: size of the entity to be added
204*5c591343SA. Cody Schuffelen     BOOL             isIndex,       // IN: TRUE if the entity is an index
205*5c591343SA. Cody Schuffelen     BOOL             isCounter      // IN: TRUE if the index is a counter
206*5c591343SA. Cody Schuffelen     )
207*5c591343SA. Cody Schuffelen {
208*5c591343SA. Cody Schuffelen     UINT32      remainBytes = NvGetFreeBytes();
209*5c591343SA. Cody Schuffelen     UINT32      reserved = sizeof(UINT32)       // size of the forward pointer
210*5c591343SA. Cody Schuffelen         + sizeof(NV_LIST_TERMINATOR);
211*5c591343SA. Cody Schuffelen //
212*5c591343SA. Cody Schuffelen     // Do a compile time sanity check on the setting for NV_MEMORY_SIZE
213*5c591343SA. Cody Schuffelen #if NV_MEMORY_SIZE < 1024
214*5c591343SA. Cody Schuffelen #error "NV_MEMORY_SIZE probably isn't large enough"
215*5c591343SA. Cody Schuffelen #endif
216*5c591343SA. Cody Schuffelen 
217*5c591343SA. Cody Schuffelen     // For NV Index, need to make sure that we do not allocate an Index if this
218*5c591343SA. Cody Schuffelen     // would mean that the TPM cannot allocate the minimum number of evict
219*5c591343SA. Cody Schuffelen     // objects.
220*5c591343SA. Cody Schuffelen     if(isIndex)
221*5c591343SA. Cody Schuffelen     {
222*5c591343SA. Cody Schuffelen         // Get the number of persistent objects allocated
223*5c591343SA. Cody Schuffelen         UINT32      persistentNum = NvCapGetPersistentNumber();
224*5c591343SA. Cody Schuffelen 
225*5c591343SA. Cody Schuffelen         // If we have not allocated the requisite number of evict objects, then we
226*5c591343SA. Cody Schuffelen         // need to reserve space for them.
227*5c591343SA. Cody Schuffelen         // NOTE: some of this is not written as simply as it might seem because
228*5c591343SA. Cody Schuffelen         // the values are all unsigned and subtracting needs to be done carefully
229*5c591343SA. Cody Schuffelen         // so that an underflow doesn't cause problems.
230*5c591343SA. Cody Schuffelen         if(persistentNum < MIN_EVICT_OBJECTS)
231*5c591343SA. Cody Schuffelen             reserved += (MIN_EVICT_OBJECTS - persistentNum) * NV_EVICT_OBJECT_SIZE;
232*5c591343SA. Cody Schuffelen     }
233*5c591343SA. Cody Schuffelen     // If this is not an index or is not a counter, reserve space for the
234*5c591343SA. Cody Schuffelen     // required number of counter indexes
235*5c591343SA. Cody Schuffelen     if(!isIndex || !isCounter)
236*5c591343SA. Cody Schuffelen     {
237*5c591343SA. Cody Schuffelen         // Get the number of counters
238*5c591343SA. Cody Schuffelen         UINT32      counterNum = NvCapGetCounterNumber();
239*5c591343SA. Cody Schuffelen 
240*5c591343SA. Cody Schuffelen         // If the required number of counters have not been allocated, reserved
241*5c591343SA. Cody Schuffelen         // space for the extra needed counters
242*5c591343SA. Cody Schuffelen         if(counterNum < MIN_COUNTER_INDICES)
243*5c591343SA. Cody Schuffelen             reserved += (MIN_COUNTER_INDICES - counterNum) * NV_INDEX_COUNTER_SIZE;
244*5c591343SA. Cody Schuffelen     }
245*5c591343SA. Cody Schuffelen     // Check that the requested allocation will fit after making sure that there
246*5c591343SA. Cody Schuffelen     // will be no chance of overflow
247*5c591343SA. Cody Schuffelen     return ((reserved < remainBytes)
248*5c591343SA. Cody Schuffelen             && (size <= remainBytes)
249*5c591343SA. Cody Schuffelen             && (size + reserved <= remainBytes));
250*5c591343SA. Cody Schuffelen }
251*5c591343SA. Cody Schuffelen 
252*5c591343SA. Cody Schuffelen //*** NvWriteNvListEnd()
253*5c591343SA. Cody Schuffelen // Function to write the list terminator.
254*5c591343SA. Cody Schuffelen NV_REF
NvWriteNvListEnd(NV_REF end)255*5c591343SA. Cody Schuffelen NvWriteNvListEnd(
256*5c591343SA. Cody Schuffelen     NV_REF           end
257*5c591343SA. Cody Schuffelen     )
258*5c591343SA. Cody Schuffelen {
259*5c591343SA. Cody Schuffelen     // Marker is initialized with zeros
260*5c591343SA. Cody Schuffelen     BYTE        listEndMarker[sizeof(NV_LIST_TERMINATOR)] = {0};
261*5c591343SA. Cody Schuffelen     UINT64      maxCount = NvReadMaxCount();
262*5c591343SA. Cody Schuffelen //
263*5c591343SA. Cody Schuffelen     // This is a constant check that can be resolved at compile time.
264*5c591343SA. Cody Schuffelen     cAssert(sizeof(UINT64) <= sizeof(NV_LIST_TERMINATOR) - sizeof(UINT32));
265*5c591343SA. Cody Schuffelen 
266*5c591343SA. Cody Schuffelen     // Copy the maxCount value to the marker buffer
267*5c591343SA. Cody Schuffelen     MemoryCopy(&listEndMarker[sizeof(UINT32)], &maxCount, sizeof(UINT64));
268*5c591343SA. Cody Schuffelen     pAssert(end + sizeof(NV_LIST_TERMINATOR) <= s_evictNvEnd);
269*5c591343SA. Cody Schuffelen 
270*5c591343SA. Cody Schuffelen     // Write it to memory
271*5c591343SA. Cody Schuffelen     NvWrite(end, sizeof(NV_LIST_TERMINATOR), &listEndMarker);
272*5c591343SA. Cody Schuffelen     return end + sizeof(NV_LIST_TERMINATOR);
273*5c591343SA. Cody Schuffelen }
274*5c591343SA. Cody Schuffelen 
275*5c591343SA. Cody Schuffelen 
276*5c591343SA. Cody Schuffelen //*** NvAdd()
277*5c591343SA. Cody Schuffelen // This function adds a new entity to NV.
278*5c591343SA. Cody Schuffelen //
279*5c591343SA. Cody Schuffelen // This function requires that there is enough space to add a new entity (i.e.,
280*5c591343SA. Cody Schuffelen // that NvTestSpace() has been called and the available space is at least as
281*5c591343SA. Cody Schuffelen // large as the required space).
282*5c591343SA. Cody Schuffelen //
283*5c591343SA. Cody Schuffelen // The 'totalSize' will be the size of 'entity'. If a handle is added, this
284*5c591343SA. Cody Schuffelen // function will increase the size accordingly.
285*5c591343SA. Cody Schuffelen static TPM_RC
NvAdd(UINT32 totalSize,UINT32 bufferSize,TPM_HANDLE handle,BYTE * entity)286*5c591343SA. Cody Schuffelen NvAdd(
287*5c591343SA. Cody Schuffelen     UINT32           totalSize,     // IN: total size needed for this entity For
288*5c591343SA. Cody Schuffelen                                     //     evict object, totalSize is the same as
289*5c591343SA. Cody Schuffelen                                     //     bufferSize.  For NV Index, totalSize is
290*5c591343SA. Cody Schuffelen                                     //     bufferSize plus index data size
291*5c591343SA. Cody Schuffelen     UINT32           bufferSize,    // IN: size of initial buffer
292*5c591343SA. Cody Schuffelen     TPM_HANDLE       handle,        // IN: optional handle
293*5c591343SA. Cody Schuffelen     BYTE            *entity         // IN: initial buffer
294*5c591343SA. Cody Schuffelen     )
295*5c591343SA. Cody Schuffelen {
296*5c591343SA. Cody Schuffelen     NV_REF          newAddr;        // IN: where the new entity will start
297*5c591343SA. Cody Schuffelen     NV_REF          nextAddr;
298*5c591343SA. Cody Schuffelen //
299*5c591343SA. Cody Schuffelen     RETURN_IF_NV_IS_NOT_AVAILABLE;
300*5c591343SA. Cody Schuffelen 
301*5c591343SA. Cody Schuffelen     // Get the end of data list
302*5c591343SA. Cody Schuffelen     newAddr = NvGetEnd();
303*5c591343SA. Cody Schuffelen 
304*5c591343SA. Cody Schuffelen     // Step over the forward pointer
305*5c591343SA. Cody Schuffelen     nextAddr = newAddr + sizeof(UINT32);
306*5c591343SA. Cody Schuffelen 
307*5c591343SA. Cody Schuffelen     // Optionally write the handle. For indexes, the handle is TPM_RH_UNASSIGNED
308*5c591343SA. Cody Schuffelen     // so that the handle in the nvIndex is used instead of writing this value
309*5c591343SA. Cody Schuffelen     if(handle != TPM_RH_UNASSIGNED)
310*5c591343SA. Cody Schuffelen     {
311*5c591343SA. Cody Schuffelen         NvWrite((UINT32)nextAddr, sizeof(TPM_HANDLE), &handle);
312*5c591343SA. Cody Schuffelen         nextAddr += sizeof(TPM_HANDLE);
313*5c591343SA. Cody Schuffelen     }
314*5c591343SA. Cody Schuffelen     // Write entity data
315*5c591343SA. Cody Schuffelen     NvWrite((UINT32)nextAddr, bufferSize, entity);
316*5c591343SA. Cody Schuffelen 
317*5c591343SA. Cody Schuffelen     // Advance the pointer by the amount of the total
318*5c591343SA. Cody Schuffelen     nextAddr += totalSize;
319*5c591343SA. Cody Schuffelen 
320*5c591343SA. Cody Schuffelen     // Finish by writing the link value
321*5c591343SA. Cody Schuffelen 
322*5c591343SA. Cody Schuffelen     // Write the next offset (relative addressing)
323*5c591343SA. Cody Schuffelen     totalSize = nextAddr - newAddr;
324*5c591343SA. Cody Schuffelen 
325*5c591343SA. Cody Schuffelen     // Write link value
326*5c591343SA. Cody Schuffelen     NvWrite((UINT32)newAddr, sizeof(UINT32), &totalSize);
327*5c591343SA. Cody Schuffelen 
328*5c591343SA. Cody Schuffelen     // Write the list terminator
329*5c591343SA. Cody Schuffelen     NvWriteNvListEnd(nextAddr);
330*5c591343SA. Cody Schuffelen 
331*5c591343SA. Cody Schuffelen     return TPM_RC_SUCCESS;
332*5c591343SA. Cody Schuffelen }
333*5c591343SA. Cody Schuffelen 
334*5c591343SA. Cody Schuffelen //*** NvDelete()
335*5c591343SA. Cody Schuffelen // This function is used to delete an NV Index or persistent object from NV memory.
336*5c591343SA. Cody Schuffelen static TPM_RC
NvDelete(NV_REF entityRef)337*5c591343SA. Cody Schuffelen NvDelete(
338*5c591343SA. Cody Schuffelen     NV_REF           entityRef      // IN: reference to entity to be deleted
339*5c591343SA. Cody Schuffelen     )
340*5c591343SA. Cody Schuffelen {
341*5c591343SA. Cody Schuffelen     UINT32          entrySize;
342*5c591343SA. Cody Schuffelen     // adjust entityAddr to back up and point to the forward pointer
343*5c591343SA. Cody Schuffelen     NV_REF          entryRef = entityRef - sizeof(UINT32);
344*5c591343SA. Cody Schuffelen     NV_REF          endRef = NvGetEnd();
345*5c591343SA. Cody Schuffelen     NV_REF          nextAddr; // address of the next entry
346*5c591343SA. Cody Schuffelen //
347*5c591343SA. Cody Schuffelen     RETURN_IF_NV_IS_NOT_AVAILABLE;
348*5c591343SA. Cody Schuffelen 
349*5c591343SA. Cody Schuffelen     // Get the offset of the next entry. That is, back up and point to the size
350*5c591343SA. Cody Schuffelen     // field of the entry
351*5c591343SA. Cody Schuffelen     NvRead(&entrySize, entryRef, sizeof(UINT32));
352*5c591343SA. Cody Schuffelen 
353*5c591343SA. Cody Schuffelen     // The next entry after the one being deleted is at a relative offset
354*5c591343SA. Cody Schuffelen     // from the current entry
355*5c591343SA. Cody Schuffelen     nextAddr = entryRef + entrySize;
356*5c591343SA. Cody Schuffelen 
357*5c591343SA. Cody Schuffelen     // If this is not the last entry, move everything up
358*5c591343SA. Cody Schuffelen     if(nextAddr < endRef)
359*5c591343SA. Cody Schuffelen     {
360*5c591343SA. Cody Schuffelen         pAssert(nextAddr > entryRef);
361*5c591343SA. Cody Schuffelen         _plat__NvMemoryMove(nextAddr,
362*5c591343SA. Cody Schuffelen                             entryRef,
363*5c591343SA. Cody Schuffelen                             (endRef - nextAddr));
364*5c591343SA. Cody Schuffelen     }
365*5c591343SA. Cody Schuffelen     // The end of the used space is now moved up by the amount of space we just
366*5c591343SA. Cody Schuffelen     // reclaimed
367*5c591343SA. Cody Schuffelen     endRef -= entrySize;
368*5c591343SA. Cody Schuffelen 
369*5c591343SA. Cody Schuffelen     // Write the end marker, and make the new end equal to the first byte after
370*5c591343SA. Cody Schuffelen     // the just added end value. This will automatically update the NV value for
371*5c591343SA. Cody Schuffelen     // maxCounter.
372*5c591343SA. Cody Schuffelen     // NOTE: This is the call that sets flag to cause NV to be updated
373*5c591343SA. Cody Schuffelen     endRef = NvWriteNvListEnd(endRef);
374*5c591343SA. Cody Schuffelen 
375*5c591343SA. Cody Schuffelen     // Clear the reclaimed memory
376*5c591343SA. Cody Schuffelen     _plat__NvMemoryClear(endRef, entrySize);
377*5c591343SA. Cody Schuffelen 
378*5c591343SA. Cody Schuffelen     return TPM_RC_SUCCESS;
379*5c591343SA. Cody Schuffelen }
380*5c591343SA. Cody Schuffelen 
381*5c591343SA. Cody Schuffelen //************************************************
382*5c591343SA. Cody Schuffelen //** RAM-based NV Index Data Access Functions
383*5c591343SA. Cody Schuffelen //************************************************
384*5c591343SA. Cody Schuffelen //*** Introduction
385*5c591343SA. Cody Schuffelen // The data layout in ram buffer is {size of(NV_handle + attributes + data
386*5c591343SA. Cody Schuffelen // NV_handle, attributes, data}
387*5c591343SA. Cody Schuffelen // for each NV Index data stored in RAM.
388*5c591343SA. Cody Schuffelen //
389*5c591343SA. Cody Schuffelen // NV storage associated with orderly data is updated when a NV Index is added
390*5c591343SA. Cody Schuffelen // but NOT when the data or attributes are changed. Orderly data is only updated
391*5c591343SA. Cody Schuffelen // to NV on an orderly shutdown (TPM2_Shutdown())
392*5c591343SA. Cody Schuffelen 
393*5c591343SA. Cody Schuffelen //*** NvRamNext()
394*5c591343SA. Cody Schuffelen // This function is used to iterate trough the list of Ram Index values. *iter needs
395*5c591343SA. Cody Schuffelen // to be initialized by calling
396*5c591343SA. Cody Schuffelen static NV_RAM_REF
NvRamNext(NV_RAM_REF * iter,TPM_HANDLE * handle)397*5c591343SA. Cody Schuffelen NvRamNext(
398*5c591343SA. Cody Schuffelen     NV_RAM_REF      *iter,          // IN/OUT: the list iterator
399*5c591343SA. Cody Schuffelen     TPM_HANDLE      *handle         // OUT: the handle of the next item.
400*5c591343SA. Cody Schuffelen     )
401*5c591343SA. Cody Schuffelen {
402*5c591343SA. Cody Schuffelen     NV_RAM_REF           currentAddr;
403*5c591343SA. Cody Schuffelen     NV_RAM_HEADER        header;
404*5c591343SA. Cody Schuffelen //
405*5c591343SA. Cody Schuffelen     // If iterator is at the beginning of list
406*5c591343SA. Cody Schuffelen     if(*iter == NV_RAM_REF_INIT)
407*5c591343SA. Cody Schuffelen     {
408*5c591343SA. Cody Schuffelen         // Initialize iterator
409*5c591343SA. Cody Schuffelen         *iter = &s_indexOrderlyRam[0];
410*5c591343SA. Cody Schuffelen     }
411*5c591343SA. Cody Schuffelen     // if we are going to return what the iter is currently pointing to...
412*5c591343SA. Cody Schuffelen     currentAddr = *iter;
413*5c591343SA. Cody Schuffelen 
414*5c591343SA. Cody Schuffelen     // If iterator reaches the end of NV space, then don't advance and return
415*5c591343SA. Cody Schuffelen     // that we are at the end of the list. The end of the list occurs when
416*5c591343SA. Cody Schuffelen     // we don't have space for a size and a handle
417*5c591343SA. Cody Schuffelen     if(currentAddr + sizeof(NV_RAM_HEADER) > RAM_ORDERLY_END)
418*5c591343SA. Cody Schuffelen         return NULL;
419*5c591343SA. Cody Schuffelen     // read the header of the next entry
420*5c591343SA. Cody Schuffelen     MemoryCopy(&header, currentAddr, sizeof(NV_RAM_HEADER));
421*5c591343SA. Cody Schuffelen 
422*5c591343SA. Cody Schuffelen     // if the size field is zero, then we have hit the end of the list
423*5c591343SA. Cody Schuffelen     if(header.size == 0)
424*5c591343SA. Cody Schuffelen         // leave the *iter pointing at the end of the list
425*5c591343SA. Cody Schuffelen         return NULL;
426*5c591343SA. Cody Schuffelen     // advance the header by the size of the entry
427*5c591343SA. Cody Schuffelen     *iter = currentAddr + header.size;
428*5c591343SA. Cody Schuffelen 
429*5c591343SA. Cody Schuffelen //    pAssert(*iter <= RAM_ORDERLY_END);
430*5c591343SA. Cody Schuffelen     if(handle != NULL)
431*5c591343SA. Cody Schuffelen         *handle = header.handle;
432*5c591343SA. Cody Schuffelen     return currentAddr;
433*5c591343SA. Cody Schuffelen }
434*5c591343SA. Cody Schuffelen 
435*5c591343SA. Cody Schuffelen //*** NvRamGetEnd()
436*5c591343SA. Cody Schuffelen // This routine performs the same function as NvGetEnd() but for the RAM data.
437*5c591343SA. Cody Schuffelen static NV_RAM_REF
NvRamGetEnd(void)438*5c591343SA. Cody Schuffelen NvRamGetEnd(
439*5c591343SA. Cody Schuffelen     void
440*5c591343SA. Cody Schuffelen     )
441*5c591343SA. Cody Schuffelen {
442*5c591343SA. Cody Schuffelen     NV_RAM_REF           iter = NV_RAM_REF_INIT;
443*5c591343SA. Cody Schuffelen     NV_RAM_REF           currentAddr;
444*5c591343SA. Cody Schuffelen //
445*5c591343SA. Cody Schuffelen     // Scan until the next address is 0
446*5c591343SA. Cody Schuffelen     while((currentAddr = NvRamNext(&iter, NULL)) != 0);
447*5c591343SA. Cody Schuffelen     return iter;
448*5c591343SA. Cody Schuffelen }
449*5c591343SA. Cody Schuffelen 
450*5c591343SA. Cody Schuffelen //*** NvRamTestSpaceIndex()
451*5c591343SA. Cody Schuffelen // This function indicates if there is enough RAM space to add a data for a
452*5c591343SA. Cody Schuffelen // new NV Index.
453*5c591343SA. Cody Schuffelen //  Return Type: BOOL
454*5c591343SA. Cody Schuffelen //      TRUE(1)         space available
455*5c591343SA. Cody Schuffelen //      FALSE(0)        no enough space
456*5c591343SA. Cody Schuffelen static BOOL
NvRamTestSpaceIndex(UINT32 size)457*5c591343SA. Cody Schuffelen NvRamTestSpaceIndex(
458*5c591343SA. Cody Schuffelen     UINT32           size           // IN: size of the data to be added to RAM
459*5c591343SA. Cody Schuffelen     )
460*5c591343SA. Cody Schuffelen {
461*5c591343SA. Cody Schuffelen     UINT32          remaining = (UINT32)(RAM_ORDERLY_END - NvRamGetEnd());
462*5c591343SA. Cody Schuffelen     UINT32          needed = sizeof(NV_RAM_HEADER) + size;
463*5c591343SA. Cody Schuffelen //
464*5c591343SA. Cody Schuffelen     // NvRamGetEnd points to the next available byte.
465*5c591343SA. Cody Schuffelen     return remaining >= needed;
466*5c591343SA. Cody Schuffelen }
467*5c591343SA. Cody Schuffelen 
468*5c591343SA. Cody Schuffelen //*** NvRamGetIndex()
469*5c591343SA. Cody Schuffelen // This function returns the offset of NV data in the RAM buffer
470*5c591343SA. Cody Schuffelen //
471*5c591343SA. Cody Schuffelen // This function requires that NV Index is in RAM. That is, the
472*5c591343SA. Cody Schuffelen // index must be known to exist.
473*5c591343SA. Cody Schuffelen static NV_RAM_REF
NvRamGetIndex(TPMI_RH_NV_INDEX handle)474*5c591343SA. Cody Schuffelen NvRamGetIndex(
475*5c591343SA. Cody Schuffelen     TPMI_RH_NV_INDEX     handle         // IN: NV handle
476*5c591343SA. Cody Schuffelen     )
477*5c591343SA. Cody Schuffelen {
478*5c591343SA. Cody Schuffelen     NV_RAM_REF          iter = NV_RAM_REF_INIT;
479*5c591343SA. Cody Schuffelen     NV_RAM_REF          currentAddr;
480*5c591343SA. Cody Schuffelen     TPM_HANDLE          foundHandle;
481*5c591343SA. Cody Schuffelen //
482*5c591343SA. Cody Schuffelen     while((currentAddr = NvRamNext(&iter, &foundHandle)) != 0)
483*5c591343SA. Cody Schuffelen     {
484*5c591343SA. Cody Schuffelen         if(handle == foundHandle)
485*5c591343SA. Cody Schuffelen             break;
486*5c591343SA. Cody Schuffelen     }
487*5c591343SA. Cody Schuffelen     return currentAddr;
488*5c591343SA. Cody Schuffelen }
489*5c591343SA. Cody Schuffelen 
490*5c591343SA. Cody Schuffelen //*** NvUpdateIndexOrderlyData()
491*5c591343SA. Cody Schuffelen // This function is used to cause an update of the orderly data to the NV backing
492*5c591343SA. Cody Schuffelen // store.
493*5c591343SA. Cody Schuffelen void
NvUpdateIndexOrderlyData(void)494*5c591343SA. Cody Schuffelen NvUpdateIndexOrderlyData(
495*5c591343SA. Cody Schuffelen     void
496*5c591343SA. Cody Schuffelen     )
497*5c591343SA. Cody Schuffelen {
498*5c591343SA. Cody Schuffelen     // Write reserved RAM space to NV
499*5c591343SA. Cody Schuffelen     NvWrite(NV_INDEX_RAM_DATA, sizeof(s_indexOrderlyRam), s_indexOrderlyRam);
500*5c591343SA. Cody Schuffelen }
501*5c591343SA. Cody Schuffelen 
502*5c591343SA. Cody Schuffelen //*** NvAddRAM()
503*5c591343SA. Cody Schuffelen // This function adds a new data area to RAM.
504*5c591343SA. Cody Schuffelen //
505*5c591343SA. Cody Schuffelen // This function requires that enough free RAM space is available to add
506*5c591343SA. Cody Schuffelen // the new data.
507*5c591343SA. Cody Schuffelen //
508*5c591343SA. Cody Schuffelen // This function should be called after the NV Index space has been updated
509*5c591343SA. Cody Schuffelen // and the index removed. This insures that NV is available so that checking
510*5c591343SA. Cody Schuffelen // for NV availability is not required during this function.
511*5c591343SA. Cody Schuffelen static void
NvAddRAM(TPMS_NV_PUBLIC * index)512*5c591343SA. Cody Schuffelen NvAddRAM(
513*5c591343SA. Cody Schuffelen     TPMS_NV_PUBLIC  *index          // IN: the index descriptor
514*5c591343SA. Cody Schuffelen     )
515*5c591343SA. Cody Schuffelen {
516*5c591343SA. Cody Schuffelen     NV_RAM_HEADER       header;
517*5c591343SA. Cody Schuffelen     NV_RAM_REF          end = NvRamGetEnd();
518*5c591343SA. Cody Schuffelen //
519*5c591343SA. Cody Schuffelen     header.size = sizeof(NV_RAM_HEADER) + index->dataSize;
520*5c591343SA. Cody Schuffelen     header.handle = index->nvIndex;
521*5c591343SA. Cody Schuffelen     MemoryCopy(&header.attributes, &index->attributes, sizeof(TPMA_NV));
522*5c591343SA. Cody Schuffelen 
523*5c591343SA. Cody Schuffelen     pAssert(ORDERLY_RAM_ADDRESS_OK(end, header.size));
524*5c591343SA. Cody Schuffelen 
525*5c591343SA. Cody Schuffelen     // Copy the header to the memory
526*5c591343SA. Cody Schuffelen     MemoryCopy(end, &header, sizeof(NV_RAM_HEADER));
527*5c591343SA. Cody Schuffelen 
528*5c591343SA. Cody Schuffelen     // Clear the data area (just in case)
529*5c591343SA. Cody Schuffelen     MemorySet(end + sizeof(NV_RAM_HEADER), 0, index->dataSize);
530*5c591343SA. Cody Schuffelen 
531*5c591343SA. Cody Schuffelen     // Step over this new entry
532*5c591343SA. Cody Schuffelen     end += header.size;
533*5c591343SA. Cody Schuffelen 
534*5c591343SA. Cody Schuffelen     // If the end marker will fit, add it
535*5c591343SA. Cody Schuffelen     if(end + sizeof(UINT32) < RAM_ORDERLY_END)
536*5c591343SA. Cody Schuffelen         MemorySet(end, 0, sizeof(UINT32));
537*5c591343SA. Cody Schuffelen     // Write reserved RAM space to NV to reflect the newly added NV Index
538*5c591343SA. Cody Schuffelen     SET_NV_UPDATE(UT_ORDERLY);
539*5c591343SA. Cody Schuffelen 
540*5c591343SA. Cody Schuffelen     return;
541*5c591343SA. Cody Schuffelen }
542*5c591343SA. Cody Schuffelen 
543*5c591343SA. Cody Schuffelen //*** NvDeleteRAM()
544*5c591343SA. Cody Schuffelen // This function is used to delete a RAM-backed NV Index data area.
545*5c591343SA. Cody Schuffelen // The space used by the entry are overwritten by the contents of the
546*5c591343SA. Cody Schuffelen // Index data that comes after (the data is moved up to fill the hole left
547*5c591343SA. Cody Schuffelen // by removing this index. The reclaimed space is cleared to zeros.
548*5c591343SA. Cody Schuffelen // This function assumes the data of NV Index exists in RAM.
549*5c591343SA. Cody Schuffelen //
550*5c591343SA. Cody Schuffelen // This function should be called after the NV Index space has been updated
551*5c591343SA. Cody Schuffelen // and the index removed. This insures that NV is available so that checking
552*5c591343SA. Cody Schuffelen // for NV availability is not required during this function.
553*5c591343SA. Cody Schuffelen static void
NvDeleteRAM(TPMI_RH_NV_INDEX handle)554*5c591343SA. Cody Schuffelen NvDeleteRAM(
555*5c591343SA. Cody Schuffelen     TPMI_RH_NV_INDEX     handle         // IN: NV handle
556*5c591343SA. Cody Schuffelen     )
557*5c591343SA. Cody Schuffelen {
558*5c591343SA. Cody Schuffelen     NV_RAM_REF           nodeAddress;
559*5c591343SA. Cody Schuffelen     NV_RAM_REF           nextNode;
560*5c591343SA. Cody Schuffelen     UINT32               size;
561*5c591343SA. Cody Schuffelen     NV_RAM_REF           lastUsed = NvRamGetEnd();
562*5c591343SA. Cody Schuffelen //
563*5c591343SA. Cody Schuffelen     nodeAddress = NvRamGetIndex(handle);
564*5c591343SA. Cody Schuffelen 
565*5c591343SA. Cody Schuffelen     pAssert(nodeAddress != 0);
566*5c591343SA. Cody Schuffelen 
567*5c591343SA. Cody Schuffelen     // Get node size
568*5c591343SA. Cody Schuffelen     MemoryCopy(&size, nodeAddress, sizeof(size));
569*5c591343SA. Cody Schuffelen 
570*5c591343SA. Cody Schuffelen     // Get the offset of next node
571*5c591343SA. Cody Schuffelen     nextNode = nodeAddress + size;
572*5c591343SA. Cody Schuffelen 
573*5c591343SA. Cody Schuffelen     // Copy the data
574*5c591343SA. Cody Schuffelen     MemoryCopy(nodeAddress, nextNode, (int)(lastUsed - nextNode));
575*5c591343SA. Cody Schuffelen 
576*5c591343SA. Cody Schuffelen     // Clear out the reclaimed space
577*5c591343SA. Cody Schuffelen     MemorySet(lastUsed - size, 0, size);
578*5c591343SA. Cody Schuffelen 
579*5c591343SA. Cody Schuffelen     // Write reserved RAM space to NV to reflect the newly delete NV Index
580*5c591343SA. Cody Schuffelen     SET_NV_UPDATE(UT_ORDERLY);
581*5c591343SA. Cody Schuffelen 
582*5c591343SA. Cody Schuffelen     return;
583*5c591343SA. Cody Schuffelen }
584*5c591343SA. Cody Schuffelen 
585*5c591343SA. Cody Schuffelen //*** NvReadIndex()
586*5c591343SA. Cody Schuffelen // This function is used to read the NV Index NV_INDEX. This is used so that the
587*5c591343SA. Cody Schuffelen // index information can be compressed and only this function would be needed
588*5c591343SA. Cody Schuffelen // to decompress it. Mostly, compression would only be able to save the space
589*5c591343SA. Cody Schuffelen // needed by the policy.
590*5c591343SA. Cody Schuffelen void
NvReadNvIndexInfo(NV_REF ref,NV_INDEX * nvIndex)591*5c591343SA. Cody Schuffelen NvReadNvIndexInfo(
592*5c591343SA. Cody Schuffelen     NV_REF           ref,           // IN: points to NV where index is located
593*5c591343SA. Cody Schuffelen     NV_INDEX        *nvIndex        // OUT: place to receive index data
594*5c591343SA. Cody Schuffelen     )
595*5c591343SA. Cody Schuffelen {
596*5c591343SA. Cody Schuffelen     pAssert(nvIndex != NULL);
597*5c591343SA. Cody Schuffelen     NvRead(nvIndex, ref, sizeof(NV_INDEX));
598*5c591343SA. Cody Schuffelen     return;
599*5c591343SA. Cody Schuffelen }
600*5c591343SA. Cody Schuffelen 
601*5c591343SA. Cody Schuffelen //*** NvReadObject()
602*5c591343SA. Cody Schuffelen // This function is used to read a persistent object. This is used so that the
603*5c591343SA. Cody Schuffelen // object information can be compressed and only this function would be needed
604*5c591343SA. Cody Schuffelen // to uncompress it.
605*5c591343SA. Cody Schuffelen void
NvReadObject(NV_REF ref,OBJECT * object)606*5c591343SA. Cody Schuffelen NvReadObject(
607*5c591343SA. Cody Schuffelen     NV_REF           ref,           // IN: points to NV where index is located
608*5c591343SA. Cody Schuffelen     OBJECT          *object         // OUT: place to receive the object data
609*5c591343SA. Cody Schuffelen     )
610*5c591343SA. Cody Schuffelen {
611*5c591343SA. Cody Schuffelen     NvRead(object, (ref + sizeof(TPM_HANDLE)), sizeof(OBJECT));
612*5c591343SA. Cody Schuffelen     return;
613*5c591343SA. Cody Schuffelen }
614*5c591343SA. Cody Schuffelen 
615*5c591343SA. Cody Schuffelen //*** NvFindEvict()
616*5c591343SA. Cody Schuffelen // This function will return the NV offset of an evict object
617*5c591343SA. Cody Schuffelen //  Return Type: UINT32
618*5c591343SA. Cody Schuffelen //      0               evict object not found
619*5c591343SA. Cody Schuffelen //      != 0            offset of evict object
620*5c591343SA. Cody Schuffelen static NV_REF
NvFindEvict(TPM_HANDLE nvHandle,OBJECT * object)621*5c591343SA. Cody Schuffelen NvFindEvict(
622*5c591343SA. Cody Schuffelen     TPM_HANDLE       nvHandle,
623*5c591343SA. Cody Schuffelen     OBJECT          *object
624*5c591343SA. Cody Schuffelen     )
625*5c591343SA. Cody Schuffelen {
626*5c591343SA. Cody Schuffelen     NV_REF          found = NvFindHandle(nvHandle);
627*5c591343SA. Cody Schuffelen //
628*5c591343SA. Cody Schuffelen     // If we found the handle and the request included an object pointer, fill it in
629*5c591343SA. Cody Schuffelen     if(found != 0 && object != NULL)
630*5c591343SA. Cody Schuffelen         NvReadObject(found, object);
631*5c591343SA. Cody Schuffelen     return found;
632*5c591343SA. Cody Schuffelen }
633*5c591343SA. Cody Schuffelen 
634*5c591343SA. Cody Schuffelen //*** NvIndexIsDefined()
635*5c591343SA. Cody Schuffelen // See if an index is already defined
636*5c591343SA. Cody Schuffelen BOOL
NvIndexIsDefined(TPM_HANDLE nvHandle)637*5c591343SA. Cody Schuffelen NvIndexIsDefined(
638*5c591343SA. Cody Schuffelen     TPM_HANDLE       nvHandle       // IN: Index to look for
639*5c591343SA. Cody Schuffelen     )
640*5c591343SA. Cody Schuffelen {
641*5c591343SA. Cody Schuffelen     return (NvFindHandle(nvHandle) != 0);
642*5c591343SA. Cody Schuffelen }
643*5c591343SA. Cody Schuffelen 
644*5c591343SA. Cody Schuffelen //*** NvConditionallyWrite()
645*5c591343SA. Cody Schuffelen // Function to check if the data to be written has changed
646*5c591343SA. Cody Schuffelen // and write it if it has
647*5c591343SA. Cody Schuffelen //  Return Type: TPM_RC
648*5c591343SA. Cody Schuffelen //      TPM_RC_NV_RATE           NV is unavailable because of rate limit
649*5c591343SA. Cody Schuffelen //      TPM_RC_NV_UNAVAILABLE    NV is inaccessible
650*5c591343SA. Cody Schuffelen static TPM_RC
NvConditionallyWrite(NV_REF entryAddr,UINT32 size,void * data)651*5c591343SA. Cody Schuffelen NvConditionallyWrite(
652*5c591343SA. Cody Schuffelen     NV_REF           entryAddr,     // IN: stating address
653*5c591343SA. Cody Schuffelen     UINT32           size,          // IN: size of the data to write
654*5c591343SA. Cody Schuffelen     void            *data           // IN: the data to write
655*5c591343SA. Cody Schuffelen     )
656*5c591343SA. Cody Schuffelen {
657*5c591343SA. Cody Schuffelen     // If the index data is actually changed, then a write to NV is required
658*5c591343SA. Cody Schuffelen     if(_plat__NvIsDifferent(entryAddr, size, data))
659*5c591343SA. Cody Schuffelen     {
660*5c591343SA. Cody Schuffelen         // Write the data if NV is available
661*5c591343SA. Cody Schuffelen         if(g_NvStatus == TPM_RC_SUCCESS)
662*5c591343SA. Cody Schuffelen         {
663*5c591343SA. Cody Schuffelen             NvWrite(entryAddr, size, data);
664*5c591343SA. Cody Schuffelen         }
665*5c591343SA. Cody Schuffelen         return g_NvStatus;
666*5c591343SA. Cody Schuffelen     }
667*5c591343SA. Cody Schuffelen     return TPM_RC_SUCCESS;
668*5c591343SA. Cody Schuffelen }
669*5c591343SA. Cody Schuffelen 
670*5c591343SA. Cody Schuffelen //*** NvReadNvIndexAttributes()
671*5c591343SA. Cody Schuffelen // This function returns the attributes of an NV Index.
672*5c591343SA. Cody Schuffelen static TPMA_NV
NvReadNvIndexAttributes(NV_REF locator)673*5c591343SA. Cody Schuffelen NvReadNvIndexAttributes(
674*5c591343SA. Cody Schuffelen     NV_REF           locator        // IN: reference to an NV index
675*5c591343SA. Cody Schuffelen     )
676*5c591343SA. Cody Schuffelen {
677*5c591343SA. Cody Schuffelen     TPMA_NV                 attributes;
678*5c591343SA. Cody Schuffelen //
679*5c591343SA. Cody Schuffelen     NvRead(&attributes,
680*5c591343SA. Cody Schuffelen            locator + offsetof(NV_INDEX, publicArea.attributes),
681*5c591343SA. Cody Schuffelen            sizeof(TPMA_NV));
682*5c591343SA. Cody Schuffelen     return attributes;
683*5c591343SA. Cody Schuffelen }
684*5c591343SA. Cody Schuffelen 
685*5c591343SA. Cody Schuffelen //*** NvReadRamIndexAttributes()
686*5c591343SA. Cody Schuffelen // This function returns the attributes from the RAM header structure. This function
687*5c591343SA. Cody Schuffelen // is used to deal with the fact that the header structure is only byte aligned.
688*5c591343SA. Cody Schuffelen static TPMA_NV
NvReadRamIndexAttributes(NV_RAM_REF ref)689*5c591343SA. Cody Schuffelen NvReadRamIndexAttributes(
690*5c591343SA. Cody Schuffelen     NV_RAM_REF       ref            // IN: pointer to a NV_RAM_HEADER
691*5c591343SA. Cody Schuffelen     )
692*5c591343SA. Cody Schuffelen {
693*5c591343SA. Cody Schuffelen     TPMA_NV         attributes;
694*5c591343SA. Cody Schuffelen //
695*5c591343SA. Cody Schuffelen     MemoryCopy(&attributes, ref + offsetof(NV_RAM_HEADER, attributes),
696*5c591343SA. Cody Schuffelen                sizeof(TPMA_NV));
697*5c591343SA. Cody Schuffelen     return attributes;
698*5c591343SA. Cody Schuffelen }
699*5c591343SA. Cody Schuffelen 
700*5c591343SA. Cody Schuffelen //*** NvWriteNvIndexAttributes()
701*5c591343SA. Cody Schuffelen // This function is used to write just the attributes of an index to NV.
702*5c591343SA. Cody Schuffelen //  Return type: TPM_RC
703*5c591343SA. Cody Schuffelen //      TPM_RC_NV_RATE          NV is rate limiting so retry
704*5c591343SA. Cody Schuffelen //      TPM_RC_NV_UNAVAILABLE   NV is not available
705*5c591343SA. Cody Schuffelen static TPM_RC
NvWriteNvIndexAttributes(NV_REF locator,TPMA_NV attributes)706*5c591343SA. Cody Schuffelen NvWriteNvIndexAttributes(
707*5c591343SA. Cody Schuffelen     NV_REF           locator,       // IN: location of the index
708*5c591343SA. Cody Schuffelen     TPMA_NV          attributes     // IN: attributes to write
709*5c591343SA. Cody Schuffelen     )
710*5c591343SA. Cody Schuffelen {
711*5c591343SA. Cody Schuffelen     return NvConditionallyWrite(
712*5c591343SA. Cody Schuffelen         locator + offsetof(NV_INDEX, publicArea.attributes),
713*5c591343SA. Cody Schuffelen         sizeof(TPMA_NV),
714*5c591343SA. Cody Schuffelen         &attributes);
715*5c591343SA. Cody Schuffelen }
716*5c591343SA. Cody Schuffelen 
717*5c591343SA. Cody Schuffelen //*** NvWriteRamIndexAttributes()
718*5c591343SA. Cody Schuffelen // This function is used to write the index attributes into an unaligned structure
719*5c591343SA. Cody Schuffelen static void
NvWriteRamIndexAttributes(NV_RAM_REF ref,TPMA_NV attributes)720*5c591343SA. Cody Schuffelen NvWriteRamIndexAttributes(
721*5c591343SA. Cody Schuffelen     NV_RAM_REF       ref,           // IN: address of the header
722*5c591343SA. Cody Schuffelen     TPMA_NV          attributes     // IN: the attributes to write
723*5c591343SA. Cody Schuffelen     )
724*5c591343SA. Cody Schuffelen {
725*5c591343SA. Cody Schuffelen     MemoryCopy(ref + offsetof(NV_RAM_HEADER, attributes), &attributes,
726*5c591343SA. Cody Schuffelen                sizeof(TPMA_NV));
727*5c591343SA. Cody Schuffelen     return;
728*5c591343SA. Cody Schuffelen }
729*5c591343SA. Cody Schuffelen 
730*5c591343SA. Cody Schuffelen //************************************************
731*5c591343SA. Cody Schuffelen //** Externally Accessible Functions
732*5c591343SA. Cody Schuffelen //************************************************
733*5c591343SA. Cody Schuffelen 
734*5c591343SA. Cody Schuffelen //*** NvIsPlatformPersistentHandle()
735*5c591343SA. Cody Schuffelen // This function indicates if a handle references a persistent object in the
736*5c591343SA. Cody Schuffelen // range belonging to the platform.
737*5c591343SA. Cody Schuffelen //  Return Type: BOOL
738*5c591343SA. Cody Schuffelen //      TRUE(1)         handle references a platform persistent object
739*5c591343SA. Cody Schuffelen //      FALSE(0)        handle does not reference platform persistent object
740*5c591343SA. Cody Schuffelen BOOL
NvIsPlatformPersistentHandle(TPM_HANDLE handle)741*5c591343SA. Cody Schuffelen NvIsPlatformPersistentHandle(
742*5c591343SA. Cody Schuffelen     TPM_HANDLE       handle         // IN: handle
743*5c591343SA. Cody Schuffelen     )
744*5c591343SA. Cody Schuffelen {
745*5c591343SA. Cody Schuffelen     return (handle >= PLATFORM_PERSISTENT && handle <= PERSISTENT_LAST);
746*5c591343SA. Cody Schuffelen }
747*5c591343SA. Cody Schuffelen 
748*5c591343SA. Cody Schuffelen //*** NvIsOwnerPersistentHandle()
749*5c591343SA. Cody Schuffelen // This function indicates if a handle references a persistent object in the
750*5c591343SA. Cody Schuffelen // range belonging to the owner.
751*5c591343SA. Cody Schuffelen //  Return Type: BOOL
752*5c591343SA. Cody Schuffelen //      TRUE(1)         handle is owner persistent handle
753*5c591343SA. Cody Schuffelen //      FALSE(0)        handle is not owner persistent handle and may not be
754*5c591343SA. Cody Schuffelen //                      a persistent handle at all
755*5c591343SA. Cody Schuffelen BOOL
NvIsOwnerPersistentHandle(TPM_HANDLE handle)756*5c591343SA. Cody Schuffelen NvIsOwnerPersistentHandle(
757*5c591343SA. Cody Schuffelen     TPM_HANDLE       handle         // IN: handle
758*5c591343SA. Cody Schuffelen     )
759*5c591343SA. Cody Schuffelen {
760*5c591343SA. Cody Schuffelen     return (handle >= PERSISTENT_FIRST && handle < PLATFORM_PERSISTENT);
761*5c591343SA. Cody Schuffelen }
762*5c591343SA. Cody Schuffelen 
763*5c591343SA. Cody Schuffelen //*** NvIndexIsAccessible()
764*5c591343SA. Cody Schuffelen //
765*5c591343SA. Cody Schuffelen // This function validates that a handle references a defined NV Index and
766*5c591343SA. Cody Schuffelen // that the Index is currently accessible.
767*5c591343SA. Cody Schuffelen //  Return Type: TPM_RC
768*5c591343SA. Cody Schuffelen //      TPM_RC_HANDLE           the handle points to an undefined NV Index
769*5c591343SA. Cody Schuffelen //                              If shEnable is CLEAR, this would include an index
770*5c591343SA. Cody Schuffelen //                              created using ownerAuth. If phEnableNV is CLEAR,
771*5c591343SA. Cody Schuffelen //                              this would include and index created using
772*5c591343SA. Cody Schuffelen //                              platformAuth
773*5c591343SA. Cody Schuffelen //      TPM_RC_NV_READLOCKED    Index is present but locked for reading and command
774*5c591343SA. Cody Schuffelen //                              does not write to the index
775*5c591343SA. Cody Schuffelen //      TPM_RC_NV_WRITELOCKED   Index is present but locked for writing and command
776*5c591343SA. Cody Schuffelen //                              writes to the index
777*5c591343SA. Cody Schuffelen TPM_RC
NvIndexIsAccessible(TPMI_RH_NV_INDEX handle)778*5c591343SA. Cody Schuffelen NvIndexIsAccessible(
779*5c591343SA. Cody Schuffelen     TPMI_RH_NV_INDEX     handle        // IN: handle
780*5c591343SA. Cody Schuffelen     )
781*5c591343SA. Cody Schuffelen {
782*5c591343SA. Cody Schuffelen     NV_INDEX            *nvIndex = NvGetIndexInfo(handle, NULL);
783*5c591343SA. Cody Schuffelen //
784*5c591343SA. Cody Schuffelen     if(nvIndex == NULL)
785*5c591343SA. Cody Schuffelen     // If index is not found, return TPM_RC_HANDLE
786*5c591343SA. Cody Schuffelen         return TPM_RC_HANDLE;
787*5c591343SA. Cody Schuffelen     if(gc.shEnable == FALSE || gc.phEnableNV == FALSE)
788*5c591343SA. Cody Schuffelen     {
789*5c591343SA. Cody Schuffelen         // if shEnable is CLEAR, an ownerCreate NV Index should not be
790*5c591343SA. Cody Schuffelen         // indicated as present
791*5c591343SA. Cody Schuffelen         if(!IS_ATTRIBUTE(nvIndex->publicArea.attributes, TPMA_NV, PLATFORMCREATE))
792*5c591343SA. Cody Schuffelen         {
793*5c591343SA. Cody Schuffelen             if(gc.shEnable == FALSE)
794*5c591343SA. Cody Schuffelen                 return TPM_RC_HANDLE;
795*5c591343SA. Cody Schuffelen         }
796*5c591343SA. Cody Schuffelen         // if phEnableNV is CLEAR, a platform created Index should not
797*5c591343SA. Cody Schuffelen         // be visible
798*5c591343SA. Cody Schuffelen         else if(gc.phEnableNV == FALSE)
799*5c591343SA. Cody Schuffelen             return TPM_RC_HANDLE;
800*5c591343SA. Cody Schuffelen     }
801*5c591343SA. Cody Schuffelen #if 0 // Writelock test for debug
802*5c591343SA. Cody Schuffelen     // If the Index is write locked and this is an NV Write operation...
803*5c591343SA. Cody Schuffelen     if(IS_ATTRIBUTE(nvIndex->publicArea.attributes, TPMA_NV, WRITELOCKED)
804*5c591343SA. Cody Schuffelen        &&  IsWriteOperation(commandIndex))
805*5c591343SA. Cody Schuffelen     {
806*5c591343SA. Cody Schuffelen         // then return a locked indication unless the command is TPM2_NV_WriteLock
807*5c591343SA. Cody Schuffelen         if(GetCommandCode(commandIndex) != TPM_CC_NV_WriteLock)
808*5c591343SA. Cody Schuffelen             return TPM_RC_NV_LOCKED;
809*5c591343SA. Cody Schuffelen         return TPM_RC_SUCCESS;
810*5c591343SA. Cody Schuffelen     }
811*5c591343SA. Cody Schuffelen #endif
812*5c591343SA. Cody Schuffelen #if 0   // Readlock Test for debug
813*5c591343SA. Cody Schuffelen     // If the Index is read locked and this is an NV Read operation...
814*5c591343SA. Cody Schuffelen     if(IS_ATTRIBUTE(nvIndex->publicArea.attributes, TPMA_NV, READLOCKED)
815*5c591343SA. Cody Schuffelen        && IsReadOperation(commandIndex))
816*5c591343SA. Cody Schuffelen     {
817*5c591343SA. Cody Schuffelen         // then return a locked indication unless the command is TPM2_NV_ReadLock
818*5c591343SA. Cody Schuffelen         if(GetCommandCode(commandIndex) != TPM_CC_NV_ReadLock)
819*5c591343SA. Cody Schuffelen             return TPM_RC_NV_LOCKED;
820*5c591343SA. Cody Schuffelen     }
821*5c591343SA. Cody Schuffelen #endif
822*5c591343SA. Cody Schuffelen     // NV Index is accessible
823*5c591343SA. Cody Schuffelen     return TPM_RC_SUCCESS;
824*5c591343SA. Cody Schuffelen }
825*5c591343SA. Cody Schuffelen 
826*5c591343SA. Cody Schuffelen //*** NvGetEvictObject()
827*5c591343SA. Cody Schuffelen // This function is used to dereference an evict object handle and get a pointer
828*5c591343SA. Cody Schuffelen // to the object.
829*5c591343SA. Cody Schuffelen //  Return Type: TPM_RC
830*5c591343SA. Cody Schuffelen //      TPM_RC_HANDLE           the handle does not point to an existing
831*5c591343SA. Cody Schuffelen //                              persistent object
832*5c591343SA. Cody Schuffelen TPM_RC
NvGetEvictObject(TPM_HANDLE handle,OBJECT * object)833*5c591343SA. Cody Schuffelen NvGetEvictObject(
834*5c591343SA. Cody Schuffelen     TPM_HANDLE       handle,        // IN: handle
835*5c591343SA. Cody Schuffelen     OBJECT          *object         // OUT: object data
836*5c591343SA. Cody Schuffelen     )
837*5c591343SA. Cody Schuffelen {
838*5c591343SA. Cody Schuffelen     NV_REF          entityAddr;         // offset points to the entity
839*5c591343SA. Cody Schuffelen //
840*5c591343SA. Cody Schuffelen     // Find the address of evict object and copy to object
841*5c591343SA. Cody Schuffelen     entityAddr = NvFindEvict(handle, object);
842*5c591343SA. Cody Schuffelen 
843*5c591343SA. Cody Schuffelen     // whether there is an error or not, make sure that the evict
844*5c591343SA. Cody Schuffelen     // status of the object is set so that the slot will get freed on exit
845*5c591343SA. Cody Schuffelen     // Must do this after NvFindEvict loads the object
846*5c591343SA. Cody Schuffelen     object->attributes.evict = SET;
847*5c591343SA. Cody Schuffelen 
848*5c591343SA. Cody Schuffelen     // If handle is not found, return an error
849*5c591343SA. Cody Schuffelen     if(entityAddr == 0)
850*5c591343SA. Cody Schuffelen         return TPM_RC_HANDLE;
851*5c591343SA. Cody Schuffelen     return TPM_RC_SUCCESS;
852*5c591343SA. Cody Schuffelen }
853*5c591343SA. Cody Schuffelen 
854*5c591343SA. Cody Schuffelen //*** NvIndexCacheInit()
855*5c591343SA. Cody Schuffelen // Function to initialize the Index cache
856*5c591343SA. Cody Schuffelen void
NvIndexCacheInit(void)857*5c591343SA. Cody Schuffelen NvIndexCacheInit(
858*5c591343SA. Cody Schuffelen     void
859*5c591343SA. Cody Schuffelen     )
860*5c591343SA. Cody Schuffelen {
861*5c591343SA. Cody Schuffelen     s_cachedNvRef = NV_REF_INIT;
862*5c591343SA. Cody Schuffelen     s_cachedNvRamRef = NV_RAM_REF_INIT;
863*5c591343SA. Cody Schuffelen     s_cachedNvIndex.publicArea.nvIndex = TPM_RH_UNASSIGNED;
864*5c591343SA. Cody Schuffelen     return;
865*5c591343SA. Cody Schuffelen }
866*5c591343SA. Cody Schuffelen 
867*5c591343SA. Cody Schuffelen 
868*5c591343SA. Cody Schuffelen //*** NvGetIndexData()
869*5c591343SA. Cody Schuffelen // This function is used to access the data in an NV Index. The data is returned
870*5c591343SA. Cody Schuffelen // as a byte sequence.
871*5c591343SA. Cody Schuffelen //
872*5c591343SA. Cody Schuffelen // This function requires that the NV Index be defined, and that the
873*5c591343SA. Cody Schuffelen // required data is within the data range.  It also requires that TPMA_NV_WRITTEN
874*5c591343SA. Cody Schuffelen // of the Index is SET.
875*5c591343SA. Cody Schuffelen void
NvGetIndexData(NV_INDEX * nvIndex,NV_REF locator,UINT32 offset,UINT16 size,void * data)876*5c591343SA. Cody Schuffelen NvGetIndexData(
877*5c591343SA. Cody Schuffelen     NV_INDEX            *nvIndex,       // IN: the in RAM index descriptor
878*5c591343SA. Cody Schuffelen     NV_REF               locator,       // IN: where the data is located
879*5c591343SA. Cody Schuffelen     UINT32               offset,        // IN: offset of NV data
880*5c591343SA. Cody Schuffelen     UINT16               size,          // IN: number of octets of NV data to read
881*5c591343SA. Cody Schuffelen     void                *data           // OUT: data buffer
882*5c591343SA. Cody Schuffelen     )
883*5c591343SA. Cody Schuffelen {
884*5c591343SA. Cody Schuffelen     TPMA_NV             nvAttributes;
885*5c591343SA. Cody Schuffelen //
886*5c591343SA. Cody Schuffelen     pAssert(nvIndex != NULL);
887*5c591343SA. Cody Schuffelen 
888*5c591343SA. Cody Schuffelen     nvAttributes = nvIndex->publicArea.attributes;
889*5c591343SA. Cody Schuffelen 
890*5c591343SA. Cody Schuffelen     pAssert(IS_ATTRIBUTE(nvAttributes, TPMA_NV, WRITTEN));
891*5c591343SA. Cody Schuffelen 
892*5c591343SA. Cody Schuffelen     if(IS_ATTRIBUTE(nvAttributes, TPMA_NV, ORDERLY))
893*5c591343SA. Cody Schuffelen     {
894*5c591343SA. Cody Schuffelen         // Get data from RAM buffer
895*5c591343SA. Cody Schuffelen         NV_RAM_REF           ramAddr = NvRamGetIndex(nvIndex->publicArea.nvIndex);
896*5c591343SA. Cody Schuffelen         pAssert(ramAddr != 0 && (size <=
897*5c591343SA. Cody Schuffelen                 ((NV_RAM_HEADER *)ramAddr)->size - sizeof(NV_RAM_HEADER) - offset));
898*5c591343SA. Cody Schuffelen         MemoryCopy(data, ramAddr + sizeof(NV_RAM_HEADER) + offset, size);
899*5c591343SA. Cody Schuffelen     }
900*5c591343SA. Cody Schuffelen     else
901*5c591343SA. Cody Schuffelen     {
902*5c591343SA. Cody Schuffelen         // Validate that read falls within range of the index
903*5c591343SA. Cody Schuffelen         pAssert(offset <= nvIndex->publicArea.dataSize
904*5c591343SA. Cody Schuffelen                 &&  size <= (nvIndex->publicArea.dataSize - offset));
905*5c591343SA. Cody Schuffelen         NvRead(data, locator + sizeof(NV_INDEX) + offset, size);
906*5c591343SA. Cody Schuffelen     }
907*5c591343SA. Cody Schuffelen     return;
908*5c591343SA. Cody Schuffelen }
909*5c591343SA. Cody Schuffelen 
910*5c591343SA. Cody Schuffelen //*** NvHashIndexData()
911*5c591343SA. Cody Schuffelen // This function adds Index data to a hash. It does this in parts to avoid large stack
912*5c591343SA. Cody Schuffelen // buffers.
913*5c591343SA. Cody Schuffelen void
NvHashIndexData(HASH_STATE * hashState,NV_INDEX * nvIndex,NV_REF locator,UINT32 offset,UINT16 size)914*5c591343SA. Cody Schuffelen NvHashIndexData(
915*5c591343SA. Cody Schuffelen     HASH_STATE          *hashState,     // IN: Initialized hash state
916*5c591343SA. Cody Schuffelen     NV_INDEX            *nvIndex,       // IN: Index
917*5c591343SA. Cody Schuffelen     NV_REF               locator,       // IN: where the data is located
918*5c591343SA. Cody Schuffelen     UINT32               offset,        // IN: starting offset
919*5c591343SA. Cody Schuffelen     UINT16               size           // IN: amount to hash
920*5c591343SA. Cody Schuffelen )
921*5c591343SA. Cody Schuffelen {
922*5c591343SA. Cody Schuffelen #define BUFFER_SIZE     64
923*5c591343SA. Cody Schuffelen     BYTE                 buffer[BUFFER_SIZE];
924*5c591343SA. Cody Schuffelen     if (offset > nvIndex->publicArea.dataSize)
925*5c591343SA. Cody Schuffelen         return;
926*5c591343SA. Cody Schuffelen     // Make sure that we don't try to read off the end.
927*5c591343SA. Cody Schuffelen     if ((offset + size) > nvIndex->publicArea.dataSize)
928*5c591343SA. Cody Schuffelen         size = nvIndex->publicArea.dataSize - (UINT16)offset;
929*5c591343SA. Cody Schuffelen #if BUFFER_SIZE >= MAX_NV_INDEX_SIZE
930*5c591343SA. Cody Schuffelen     NvGetIndexData(nvIndex, locator, offset, size, buffer);
931*5c591343SA. Cody Schuffelen     CryptDigestUpdate(hashState, size, buffer);
932*5c591343SA. Cody Schuffelen #else
933*5c591343SA. Cody Schuffelen     {
934*5c591343SA. Cody Schuffelen         INT16                i;
935*5c591343SA. Cody Schuffelen         UINT16               readSize;
936*5c591343SA. Cody Schuffelen         //
937*5c591343SA. Cody Schuffelen         for (i = size; i > 0; offset += readSize, i -= readSize)
938*5c591343SA. Cody Schuffelen         {
939*5c591343SA. Cody Schuffelen             readSize = (i < BUFFER_SIZE) ? i : BUFFER_SIZE;
940*5c591343SA. Cody Schuffelen             NvGetIndexData(nvIndex, locator, offset, readSize, buffer);
941*5c591343SA. Cody Schuffelen             CryptDigestUpdate(hashState, readSize, buffer);
942*5c591343SA. Cody Schuffelen         }
943*5c591343SA. Cody Schuffelen     }
944*5c591343SA. Cody Schuffelen #endif // BUFFER_SIZE >= MAX_NV_INDEX_SIZE
945*5c591343SA. Cody Schuffelen #undef  BUFFER_SIZE
946*5c591343SA. Cody Schuffelen }
947*5c591343SA. Cody Schuffelen 
948*5c591343SA. Cody Schuffelen 
949*5c591343SA. Cody Schuffelen //*** NvGetUINT64Data()
950*5c591343SA. Cody Schuffelen // Get data in integer format of a bit or counter NV Index.
951*5c591343SA. Cody Schuffelen //
952*5c591343SA. Cody Schuffelen // This function requires that the NV Index is defined and that the NV Index
953*5c591343SA. Cody Schuffelen // previously has been written.
954*5c591343SA. Cody Schuffelen UINT64
NvGetUINT64Data(NV_INDEX * nvIndex,NV_REF locator)955*5c591343SA. Cody Schuffelen NvGetUINT64Data(
956*5c591343SA. Cody Schuffelen     NV_INDEX            *nvIndex,       // IN: the in RAM index descriptor
957*5c591343SA. Cody Schuffelen     NV_REF               locator        // IN: where index exists in NV
958*5c591343SA. Cody Schuffelen     )
959*5c591343SA. Cody Schuffelen {
960*5c591343SA. Cody Schuffelen     UINT64                intVal;
961*5c591343SA. Cody Schuffelen //
962*5c591343SA. Cody Schuffelen     // Read the value and convert it to internal format
963*5c591343SA. Cody Schuffelen     NvGetIndexData(nvIndex, locator, 0, 8, &intVal);
964*5c591343SA. Cody Schuffelen     return BYTE_ARRAY_TO_UINT64(((BYTE *)&intVal));
965*5c591343SA. Cody Schuffelen }
966*5c591343SA. Cody Schuffelen 
967*5c591343SA. Cody Schuffelen //*** NvWriteIndexAttributes()
968*5c591343SA. Cody Schuffelen // This function is used to write just the attributes of an index.
969*5c591343SA. Cody Schuffelen //  Return type: TPM_RC
970*5c591343SA. Cody Schuffelen //      TPM_RC_NV_RATE          NV is rate limiting so retry
971*5c591343SA. Cody Schuffelen //      TPM_RC_NV_UNAVAILABLE   NV is not available
972*5c591343SA. Cody Schuffelen TPM_RC
NvWriteIndexAttributes(TPM_HANDLE handle,NV_REF locator,TPMA_NV attributes)973*5c591343SA. Cody Schuffelen NvWriteIndexAttributes(
974*5c591343SA. Cody Schuffelen     TPM_HANDLE       handle,
975*5c591343SA. Cody Schuffelen     NV_REF           locator,       // IN: location of the index
976*5c591343SA. Cody Schuffelen     TPMA_NV          attributes     // IN: attributes to write
977*5c591343SA. Cody Schuffelen     )
978*5c591343SA. Cody Schuffelen {
979*5c591343SA. Cody Schuffelen     TPM_RC              result;
980*5c591343SA. Cody Schuffelen //
981*5c591343SA. Cody Schuffelen     if(IS_ATTRIBUTE(attributes, TPMA_NV, ORDERLY))
982*5c591343SA. Cody Schuffelen     {
983*5c591343SA. Cody Schuffelen         NV_RAM_REF      ram = NvRamGetIndex(handle);
984*5c591343SA. Cody Schuffelen         NvWriteRamIndexAttributes(ram, attributes);
985*5c591343SA. Cody Schuffelen         result = TPM_RC_SUCCESS;
986*5c591343SA. Cody Schuffelen     }
987*5c591343SA. Cody Schuffelen     else
988*5c591343SA. Cody Schuffelen     {
989*5c591343SA. Cody Schuffelen         result = NvWriteNvIndexAttributes(locator, attributes);
990*5c591343SA. Cody Schuffelen     }
991*5c591343SA. Cody Schuffelen     return result;
992*5c591343SA. Cody Schuffelen }
993*5c591343SA. Cody Schuffelen 
994*5c591343SA. Cody Schuffelen //*** NvWriteIndexAuth()
995*5c591343SA. Cody Schuffelen // This function is used to write the authValue of an index. It is used by
996*5c591343SA. Cody Schuffelen // TPM2_NV_ChangeAuth()
997*5c591343SA. Cody Schuffelen //  Return type: TPM_RC
998*5c591343SA. Cody Schuffelen //      TPM_RC_NV_RATE          NV is rate limiting so retry
999*5c591343SA. Cody Schuffelen //      TPM_RC_NV_UNAVAILABLE   NV is not available
1000*5c591343SA. Cody Schuffelen TPM_RC
NvWriteIndexAuth(NV_REF locator,TPM2B_AUTH * authValue)1001*5c591343SA. Cody Schuffelen NvWriteIndexAuth(
1002*5c591343SA. Cody Schuffelen     NV_REF           locator,       // IN: location of the index
1003*5c591343SA. Cody Schuffelen     TPM2B_AUTH      *authValue      // IN: the authValue to write
1004*5c591343SA. Cody Schuffelen     )
1005*5c591343SA. Cody Schuffelen {
1006*5c591343SA. Cody Schuffelen     TPM_RC              result;
1007*5c591343SA. Cody Schuffelen //
1008*5c591343SA. Cody Schuffelen     // If the locator is pointing to the cached index value...
1009*5c591343SA. Cody Schuffelen     if(locator == s_cachedNvRef)
1010*5c591343SA. Cody Schuffelen     {
1011*5c591343SA. Cody Schuffelen         // copy the authValue to the cached index so it will be there if we
1012*5c591343SA. Cody Schuffelen         // look for it. This is a safety thing.
1013*5c591343SA. Cody Schuffelen         MemoryCopy2B(&s_cachedNvIndex.authValue.b, &authValue->b,
1014*5c591343SA. Cody Schuffelen                      sizeof(s_cachedNvIndex.authValue.t.buffer));
1015*5c591343SA. Cody Schuffelen     }
1016*5c591343SA. Cody Schuffelen     result = NvConditionallyWrite(
1017*5c591343SA. Cody Schuffelen         locator + offsetof(NV_INDEX, authValue),
1018*5c591343SA. Cody Schuffelen         sizeof(UINT16) + authValue->t.size,
1019*5c591343SA. Cody Schuffelen         authValue);
1020*5c591343SA. Cody Schuffelen     return result;
1021*5c591343SA. Cody Schuffelen }
1022*5c591343SA. Cody Schuffelen 
1023*5c591343SA. Cody Schuffelen //*** NvGetIndexInfo()
1024*5c591343SA. Cody Schuffelen // This function loads the nvIndex Info into the NV cache and returns a pointer
1025*5c591343SA. Cody Schuffelen // to the NV_INDEX. If the returned value is zero, the index was not found.
1026*5c591343SA. Cody Schuffelen // The 'locator' parameter, if not NULL, will be set to the offset in NV of the
1027*5c591343SA. Cody Schuffelen // Index (the location of the handle of the Index).
1028*5c591343SA. Cody Schuffelen //
1029*5c591343SA. Cody Schuffelen // This function will set the index cache. If the index is orderly, the attributes
1030*5c591343SA. Cody Schuffelen // from RAM are substituted for the attributes in the cached index
1031*5c591343SA. Cody Schuffelen NV_INDEX *
NvGetIndexInfo(TPM_HANDLE nvHandle,NV_REF * locator)1032*5c591343SA. Cody Schuffelen NvGetIndexInfo(
1033*5c591343SA. Cody Schuffelen     TPM_HANDLE       nvHandle,      // IN: the index handle
1034*5c591343SA. Cody Schuffelen     NV_REF          *locator        // OUT: location of the index
1035*5c591343SA. Cody Schuffelen     )
1036*5c591343SA. Cody Schuffelen {
1037*5c591343SA. Cody Schuffelen     if(s_cachedNvIndex.publicArea.nvIndex != nvHandle)
1038*5c591343SA. Cody Schuffelen     {
1039*5c591343SA. Cody Schuffelen         s_cachedNvIndex.publicArea.nvIndex = TPM_RH_UNASSIGNED;
1040*5c591343SA. Cody Schuffelen         s_cachedNvRamRef = 0;
1041*5c591343SA. Cody Schuffelen         s_cachedNvRef = NvFindHandle(nvHandle);
1042*5c591343SA. Cody Schuffelen         if(s_cachedNvRef == 0)
1043*5c591343SA. Cody Schuffelen             return NULL;
1044*5c591343SA. Cody Schuffelen         NvReadNvIndexInfo(s_cachedNvRef, &s_cachedNvIndex);
1045*5c591343SA. Cody Schuffelen         if(IS_ATTRIBUTE(s_cachedNvIndex.publicArea.attributes, TPMA_NV, ORDERLY))
1046*5c591343SA. Cody Schuffelen         {
1047*5c591343SA. Cody Schuffelen             s_cachedNvRamRef = NvRamGetIndex(nvHandle);
1048*5c591343SA. Cody Schuffelen             s_cachedNvIndex.publicArea.attributes =
1049*5c591343SA. Cody Schuffelen                 NvReadRamIndexAttributes(s_cachedNvRamRef);
1050*5c591343SA. Cody Schuffelen         }
1051*5c591343SA. Cody Schuffelen     }
1052*5c591343SA. Cody Schuffelen     if(locator != NULL)
1053*5c591343SA. Cody Schuffelen         *locator = s_cachedNvRef;
1054*5c591343SA. Cody Schuffelen     return &s_cachedNvIndex;
1055*5c591343SA. Cody Schuffelen }
1056*5c591343SA. Cody Schuffelen 
1057*5c591343SA. Cody Schuffelen //*** NvWriteIndexData()
1058*5c591343SA. Cody Schuffelen // This function is used to write NV index data. It is intended to be used to
1059*5c591343SA. Cody Schuffelen // update the data associated with the default index.
1060*5c591343SA. Cody Schuffelen //
1061*5c591343SA. Cody Schuffelen // This function requires that the NV Index is defined, and the data is
1062*5c591343SA. Cody Schuffelen // within the defined data range for the index.
1063*5c591343SA. Cody Schuffelen //
1064*5c591343SA. Cody Schuffelen // Index data is only written due to a command that modifies the data in a single
1065*5c591343SA. Cody Schuffelen // index. There is no case where changes are made to multiple indexes data at the
1066*5c591343SA. Cody Schuffelen // same time. Multiple attributes may be change but not multiple index data. This
1067*5c591343SA. Cody Schuffelen // is important because we will normally be handling the index for which we have
1068*5c591343SA. Cody Schuffelen // the cached pointer values.
1069*5c591343SA. Cody Schuffelen //  Return type: TPM_RC
1070*5c591343SA. Cody Schuffelen //      TPM_RC_NV_RATE          NV is rate limiting so retry
1071*5c591343SA. Cody Schuffelen //      TPM_RC_NV_UNAVAILABLE   NV is not available
1072*5c591343SA. Cody Schuffelen TPM_RC
NvWriteIndexData(NV_INDEX * nvIndex,UINT32 offset,UINT32 size,void * data)1073*5c591343SA. Cody Schuffelen NvWriteIndexData(
1074*5c591343SA. Cody Schuffelen     NV_INDEX        *nvIndex,       // IN: the description of the index
1075*5c591343SA. Cody Schuffelen     UINT32           offset,        // IN: offset of NV data
1076*5c591343SA. Cody Schuffelen     UINT32           size,          // IN: size of NV data
1077*5c591343SA. Cody Schuffelen     void            *data           // IN: data buffer
1078*5c591343SA. Cody Schuffelen     )
1079*5c591343SA. Cody Schuffelen {
1080*5c591343SA. Cody Schuffelen     TPM_RC               result = TPM_RC_SUCCESS;
1081*5c591343SA. Cody Schuffelen //
1082*5c591343SA. Cody Schuffelen     pAssert(nvIndex != NULL);
1083*5c591343SA. Cody Schuffelen     // Make sure that this is dealing with the 'default' index.
1084*5c591343SA. Cody Schuffelen     // Note: it is tempting to change the calling sequence so that the 'default' is
1085*5c591343SA. Cody Schuffelen     // presumed.
1086*5c591343SA. Cody Schuffelen     pAssert(nvIndex->publicArea.nvIndex == s_cachedNvIndex.publicArea.nvIndex);
1087*5c591343SA. Cody Schuffelen 
1088*5c591343SA. Cody Schuffelen     // Validate that write falls within range of the index
1089*5c591343SA. Cody Schuffelen     pAssert(offset <= nvIndex->publicArea.dataSize
1090*5c591343SA. Cody Schuffelen             &&  size <= (nvIndex->publicArea.dataSize - offset));
1091*5c591343SA. Cody Schuffelen 
1092*5c591343SA. Cody Schuffelen     // Update TPMA_NV_WRITTEN bit if necessary
1093*5c591343SA. Cody Schuffelen     if(!IS_ATTRIBUTE(nvIndex->publicArea.attributes, TPMA_NV, WRITTEN))
1094*5c591343SA. Cody Schuffelen     {
1095*5c591343SA. Cody Schuffelen         // Update the in memory version of the attributes
1096*5c591343SA. Cody Schuffelen         SET_ATTRIBUTE(nvIndex->publicArea.attributes, TPMA_NV, WRITTEN);
1097*5c591343SA. Cody Schuffelen 
1098*5c591343SA. Cody Schuffelen         // If this is not orderly, then update the NV version of
1099*5c591343SA. Cody Schuffelen         // the attributes
1100*5c591343SA. Cody Schuffelen         if(!IS_ATTRIBUTE(nvIndex->publicArea.attributes, TPMA_NV, ORDERLY))
1101*5c591343SA. Cody Schuffelen         {
1102*5c591343SA. Cody Schuffelen             result = NvWriteNvIndexAttributes(s_cachedNvRef,
1103*5c591343SA. Cody Schuffelen                                               nvIndex->publicArea.attributes);
1104*5c591343SA. Cody Schuffelen             if(result != TPM_RC_SUCCESS)
1105*5c591343SA. Cody Schuffelen                 return result;
1106*5c591343SA. Cody Schuffelen             // If this is a partial write of an ordinary index, clear the whole
1107*5c591343SA. Cody Schuffelen             // index.
1108*5c591343SA. Cody Schuffelen             if(IsNvOrdinaryIndex(nvIndex->publicArea.attributes)
1109*5c591343SA. Cody Schuffelen                && (nvIndex->publicArea.dataSize > size))
1110*5c591343SA. Cody Schuffelen                 _plat__NvMemoryClear(s_cachedNvRef + sizeof(NV_INDEX),
1111*5c591343SA. Cody Schuffelen                                      nvIndex->publicArea.dataSize);
1112*5c591343SA. Cody Schuffelen         }
1113*5c591343SA. Cody Schuffelen         else
1114*5c591343SA. Cody Schuffelen         {
1115*5c591343SA. Cody Schuffelen             // This is orderly so update the RAM version
1116*5c591343SA. Cody Schuffelen             MemoryCopy(s_cachedNvRamRef + offsetof(NV_RAM_HEADER, attributes),
1117*5c591343SA. Cody Schuffelen                        &nvIndex->publicArea.attributes, sizeof(TPMA_NV));
1118*5c591343SA. Cody Schuffelen             // If setting WRITTEN for an orderly counter, make sure that the
1119*5c591343SA. Cody Schuffelen             // state saved version of the counter is saved
1120*5c591343SA. Cody Schuffelen             if(IsNvCounterIndex(nvIndex->publicArea.attributes))
1121*5c591343SA. Cody Schuffelen                 SET_NV_UPDATE(UT_ORDERLY);
1122*5c591343SA. Cody Schuffelen             // If setting the written attribute on an ordinary index, make sure that
1123*5c591343SA. Cody Schuffelen             // the data is all cleared out in case there is a partial write. This
1124*5c591343SA. Cody Schuffelen             // is only necessary for ordinary indexes because all of the other types
1125*5c591343SA. Cody Schuffelen             // are always written in total.
1126*5c591343SA. Cody Schuffelen             else if(IsNvOrdinaryIndex(nvIndex->publicArea.attributes))
1127*5c591343SA. Cody Schuffelen                 MemorySet(s_cachedNvRamRef + sizeof(NV_RAM_HEADER),
1128*5c591343SA. Cody Schuffelen                           0, nvIndex->publicArea.dataSize);
1129*5c591343SA. Cody Schuffelen         }
1130*5c591343SA. Cody Schuffelen     }
1131*5c591343SA. Cody Schuffelen     // If this is orderly data, write it to RAM
1132*5c591343SA. Cody Schuffelen     if(IS_ATTRIBUTE(nvIndex->publicArea.attributes, TPMA_NV, ORDERLY))
1133*5c591343SA. Cody Schuffelen     {
1134*5c591343SA. Cody Schuffelen         // Note: if this is the first write to a counter, the code above will queue
1135*5c591343SA. Cody Schuffelen         // the write to NV of the RAM data in order to update TPMA_NV_WRITTEN. In
1136*5c591343SA. Cody Schuffelen         // process of doing that write, it will also write the initial counter value
1137*5c591343SA. Cody Schuffelen 
1138*5c591343SA. Cody Schuffelen         // Update RAM
1139*5c591343SA. Cody Schuffelen         MemoryCopy(s_cachedNvRamRef + sizeof(NV_RAM_HEADER) + offset, data, size);
1140*5c591343SA. Cody Schuffelen 
1141*5c591343SA. Cody Schuffelen         // And indicate that the TPM is no longer orderly
1142*5c591343SA. Cody Schuffelen         g_clearOrderly = TRUE;
1143*5c591343SA. Cody Schuffelen     }
1144*5c591343SA. Cody Schuffelen     else
1145*5c591343SA. Cody Schuffelen     {
1146*5c591343SA. Cody Schuffelen         // Offset into the index to the first byte of the data to be written to NV
1147*5c591343SA. Cody Schuffelen         result = NvConditionallyWrite(s_cachedNvRef + sizeof(NV_INDEX) + offset,
1148*5c591343SA. Cody Schuffelen                                       size, data);
1149*5c591343SA. Cody Schuffelen     }
1150*5c591343SA. Cody Schuffelen     return result;
1151*5c591343SA. Cody Schuffelen }
1152*5c591343SA. Cody Schuffelen 
1153*5c591343SA. Cody Schuffelen //*** NvWriteUINT64Data()
1154*5c591343SA. Cody Schuffelen // This function to write back a UINT64 value. The various UINT64 values (bits,
1155*5c591343SA. Cody Schuffelen // counters, and PINs) are kept in canonical format but manipulate in native
1156*5c591343SA. Cody Schuffelen // format. This takes a native format value converts it and saves it back as
1157*5c591343SA. Cody Schuffelen // in canonical format.
1158*5c591343SA. Cody Schuffelen //
1159*5c591343SA. Cody Schuffelen // This function will return the value from NV or RAM depending on the type of the
1160*5c591343SA. Cody Schuffelen // index (orderly or not)
1161*5c591343SA. Cody Schuffelen //
1162*5c591343SA. Cody Schuffelen TPM_RC
NvWriteUINT64Data(NV_INDEX * nvIndex,UINT64 intValue)1163*5c591343SA. Cody Schuffelen NvWriteUINT64Data(
1164*5c591343SA. Cody Schuffelen     NV_INDEX        *nvIndex,       // IN: the description of the index
1165*5c591343SA. Cody Schuffelen     UINT64           intValue       // IN: the value to write
1166*5c591343SA. Cody Schuffelen     )
1167*5c591343SA. Cody Schuffelen {
1168*5c591343SA. Cody Schuffelen     BYTE            bytes[8];
1169*5c591343SA. Cody Schuffelen     UINT64_TO_BYTE_ARRAY(intValue, bytes);
1170*5c591343SA. Cody Schuffelen //
1171*5c591343SA. Cody Schuffelen     return NvWriteIndexData(nvIndex, 0, 8, &bytes);
1172*5c591343SA. Cody Schuffelen }
1173*5c591343SA. Cody Schuffelen 
1174*5c591343SA. Cody Schuffelen //*** NvGetIndexName()
1175*5c591343SA. Cody Schuffelen // This function computes the Name of an index
1176*5c591343SA. Cody Schuffelen // The 'name' buffer receives the bytes of the Name and the return value
1177*5c591343SA. Cody Schuffelen // is the number of octets in the Name.
1178*5c591343SA. Cody Schuffelen //
1179*5c591343SA. Cody Schuffelen // This function requires that the NV Index is defined.
1180*5c591343SA. Cody Schuffelen TPM2B_NAME *
NvGetIndexName(NV_INDEX * nvIndex,TPM2B_NAME * name)1181*5c591343SA. Cody Schuffelen NvGetIndexName(
1182*5c591343SA. Cody Schuffelen     NV_INDEX        *nvIndex,       // IN: the index over which the name is to be
1183*5c591343SA. Cody Schuffelen                                     //     computed
1184*5c591343SA. Cody Schuffelen     TPM2B_NAME      *name           // OUT: name of the index
1185*5c591343SA. Cody Schuffelen     )
1186*5c591343SA. Cody Schuffelen {
1187*5c591343SA. Cody Schuffelen     UINT16               dataSize, digestSize;
1188*5c591343SA. Cody Schuffelen     BYTE                 marshalBuffer[sizeof(TPMS_NV_PUBLIC)];
1189*5c591343SA. Cody Schuffelen     BYTE                *buffer;
1190*5c591343SA. Cody Schuffelen     HASH_STATE           hashState;
1191*5c591343SA. Cody Schuffelen //
1192*5c591343SA. Cody Schuffelen     // Marshal public area
1193*5c591343SA. Cody Schuffelen     buffer = marshalBuffer;
1194*5c591343SA. Cody Schuffelen     dataSize = TPMS_NV_PUBLIC_Marshal(&nvIndex->publicArea, &buffer, NULL);
1195*5c591343SA. Cody Schuffelen 
1196*5c591343SA. Cody Schuffelen     // hash public area
1197*5c591343SA. Cody Schuffelen     digestSize = CryptHashStart(&hashState, nvIndex->publicArea.nameAlg);
1198*5c591343SA. Cody Schuffelen     CryptDigestUpdate(&hashState, dataSize, marshalBuffer);
1199*5c591343SA. Cody Schuffelen 
1200*5c591343SA. Cody Schuffelen     // Complete digest leaving room for the nameAlg
1201*5c591343SA. Cody Schuffelen     CryptHashEnd(&hashState, digestSize, &name->b.buffer[2]);
1202*5c591343SA. Cody Schuffelen 
1203*5c591343SA. Cody Schuffelen     // Include the nameAlg
1204*5c591343SA. Cody Schuffelen     UINT16_TO_BYTE_ARRAY(nvIndex->publicArea.nameAlg, name->b.buffer);
1205*5c591343SA. Cody Schuffelen     name->t.size = digestSize + 2;
1206*5c591343SA. Cody Schuffelen     return name;
1207*5c591343SA. Cody Schuffelen }
1208*5c591343SA. Cody Schuffelen 
1209*5c591343SA. Cody Schuffelen //*** NvGetNameByIndexHandle()
1210*5c591343SA. Cody Schuffelen // This function is used to compute the Name of an NV Index referenced by handle.
1211*5c591343SA. Cody Schuffelen //
1212*5c591343SA. Cody Schuffelen // The 'name' buffer receives the bytes of the Name and the return value
1213*5c591343SA. Cody Schuffelen // is the number of octets in the Name.
1214*5c591343SA. Cody Schuffelen //
1215*5c591343SA. Cody Schuffelen // This function requires that the NV Index is defined.
1216*5c591343SA. Cody Schuffelen TPM2B_NAME *
NvGetNameByIndexHandle(TPMI_RH_NV_INDEX handle,TPM2B_NAME * name)1217*5c591343SA. Cody Schuffelen NvGetNameByIndexHandle(
1218*5c591343SA. Cody Schuffelen     TPMI_RH_NV_INDEX     handle,        // IN: handle of the index
1219*5c591343SA. Cody Schuffelen     TPM2B_NAME          *name           // OUT: name of the index
1220*5c591343SA. Cody Schuffelen     )
1221*5c591343SA. Cody Schuffelen {
1222*5c591343SA. Cody Schuffelen     NV_INDEX             *nvIndex = NvGetIndexInfo(handle, NULL);
1223*5c591343SA. Cody Schuffelen //
1224*5c591343SA. Cody Schuffelen     return NvGetIndexName(nvIndex, name);
1225*5c591343SA. Cody Schuffelen }
1226*5c591343SA. Cody Schuffelen 
1227*5c591343SA. Cody Schuffelen //*** NvDefineIndex()
1228*5c591343SA. Cody Schuffelen // This function is used to assign NV memory to an NV Index.
1229*5c591343SA. Cody Schuffelen //
1230*5c591343SA. Cody Schuffelen //  Return Type: TPM_RC
1231*5c591343SA. Cody Schuffelen //      TPM_RC_NV_SPACE         insufficient NV space
1232*5c591343SA. Cody Schuffelen TPM_RC
NvDefineIndex(TPMS_NV_PUBLIC * publicArea,TPM2B_AUTH * authValue)1233*5c591343SA. Cody Schuffelen NvDefineIndex(
1234*5c591343SA. Cody Schuffelen     TPMS_NV_PUBLIC  *publicArea,    // IN: A template for an area to create.
1235*5c591343SA. Cody Schuffelen     TPM2B_AUTH      *authValue      // IN: The initial authorization value
1236*5c591343SA. Cody Schuffelen     )
1237*5c591343SA. Cody Schuffelen {
1238*5c591343SA. Cody Schuffelen     // The buffer to be written to NV memory
1239*5c591343SA. Cody Schuffelen     NV_INDEX        nvIndex;            // the index data
1240*5c591343SA. Cody Schuffelen     UINT16          entrySize;          // size of entry
1241*5c591343SA. Cody Schuffelen     TPM_RC          result;
1242*5c591343SA. Cody Schuffelen //
1243*5c591343SA. Cody Schuffelen     entrySize = sizeof(NV_INDEX);
1244*5c591343SA. Cody Schuffelen 
1245*5c591343SA. Cody Schuffelen     // only allocate data space for indexes that are going to be written to NV.
1246*5c591343SA. Cody Schuffelen     // Orderly indexes don't need space.
1247*5c591343SA. Cody Schuffelen     if(!IS_ATTRIBUTE(publicArea->attributes, TPMA_NV, ORDERLY))
1248*5c591343SA. Cody Schuffelen         entrySize += publicArea->dataSize;
1249*5c591343SA. Cody Schuffelen     // Check if we have enough space to create the NV Index
1250*5c591343SA. Cody Schuffelen     // In this implementation, the only resource limitation is the available NV
1251*5c591343SA. Cody Schuffelen     // space (and possibly RAM space.)  Other implementation may have other
1252*5c591343SA. Cody Schuffelen     // limitation on counter or on NV slots
1253*5c591343SA. Cody Schuffelen     if(!NvTestSpace(entrySize, TRUE, IsNvCounterIndex(publicArea->attributes)))
1254*5c591343SA. Cody Schuffelen         return TPM_RC_NV_SPACE;
1255*5c591343SA. Cody Schuffelen 
1256*5c591343SA. Cody Schuffelen     // if the index to be defined is RAM backed, check RAM space availability
1257*5c591343SA. Cody Schuffelen     // as well
1258*5c591343SA. Cody Schuffelen     if(IS_ATTRIBUTE(publicArea->attributes, TPMA_NV, ORDERLY)
1259*5c591343SA. Cody Schuffelen        &&  !NvRamTestSpaceIndex(publicArea->dataSize))
1260*5c591343SA. Cody Schuffelen         return TPM_RC_NV_SPACE;
1261*5c591343SA. Cody Schuffelen     // Copy input value to nvBuffer
1262*5c591343SA. Cody Schuffelen     nvIndex.publicArea = *publicArea;
1263*5c591343SA. Cody Schuffelen 
1264*5c591343SA. Cody Schuffelen     // Copy the authValue
1265*5c591343SA. Cody Schuffelen     nvIndex.authValue = *authValue;
1266*5c591343SA. Cody Schuffelen 
1267*5c591343SA. Cody Schuffelen     // Add index to NV memory
1268*5c591343SA. Cody Schuffelen     result = NvAdd(entrySize, sizeof(NV_INDEX), TPM_RH_UNASSIGNED,
1269*5c591343SA. Cody Schuffelen                    (BYTE *)&nvIndex);
1270*5c591343SA. Cody Schuffelen     if(result == TPM_RC_SUCCESS)
1271*5c591343SA. Cody Schuffelen     {
1272*5c591343SA. Cody Schuffelen     // If the data of NV Index is RAM backed, add the data area in RAM as well
1273*5c591343SA. Cody Schuffelen         if(IS_ATTRIBUTE(publicArea->attributes, TPMA_NV, ORDERLY))
1274*5c591343SA. Cody Schuffelen             NvAddRAM(publicArea);
1275*5c591343SA. Cody Schuffelen     }
1276*5c591343SA. Cody Schuffelen     return result;
1277*5c591343SA. Cody Schuffelen }
1278*5c591343SA. Cody Schuffelen 
1279*5c591343SA. Cody Schuffelen //*** NvAddEvictObject()
1280*5c591343SA. Cody Schuffelen // This function is used to assign NV memory to a persistent object.
1281*5c591343SA. Cody Schuffelen //  Return Type: TPM_RC
1282*5c591343SA. Cody Schuffelen //      TPM_RC_NV_HANDLE        the requested handle is already in use
1283*5c591343SA. Cody Schuffelen //      TPM_RC_NV_SPACE         insufficient NV space
1284*5c591343SA. Cody Schuffelen TPM_RC
NvAddEvictObject(TPMI_DH_OBJECT evictHandle,OBJECT * object)1285*5c591343SA. Cody Schuffelen NvAddEvictObject(
1286*5c591343SA. Cody Schuffelen     TPMI_DH_OBJECT   evictHandle,   // IN: new evict handle
1287*5c591343SA. Cody Schuffelen     OBJECT          *object         // IN: object to be added
1288*5c591343SA. Cody Schuffelen     )
1289*5c591343SA. Cody Schuffelen {
1290*5c591343SA. Cody Schuffelen     TPM_HANDLE       temp = object->evictHandle;
1291*5c591343SA. Cody Schuffelen     TPM_RC           result;
1292*5c591343SA. Cody Schuffelen //
1293*5c591343SA. Cody Schuffelen     // Check if we have enough space to add the evict object
1294*5c591343SA. Cody Schuffelen     // An evict object needs 8 bytes in index table + sizeof OBJECT
1295*5c591343SA. Cody Schuffelen     // In this implementation, the only resource limitation is the available NV
1296*5c591343SA. Cody Schuffelen     // space.  Other implementation may have other limitation on evict object
1297*5c591343SA. Cody Schuffelen     // handle space
1298*5c591343SA. Cody Schuffelen     if(!NvTestSpace(sizeof(OBJECT) + sizeof(TPM_HANDLE), FALSE, FALSE))
1299*5c591343SA. Cody Schuffelen         return TPM_RC_NV_SPACE;
1300*5c591343SA. Cody Schuffelen 
1301*5c591343SA. Cody Schuffelen     // Set evict attribute and handle
1302*5c591343SA. Cody Schuffelen     object->attributes.evict = SET;
1303*5c591343SA. Cody Schuffelen     object->evictHandle = evictHandle;
1304*5c591343SA. Cody Schuffelen 
1305*5c591343SA. Cody Schuffelen     // Now put this in NV
1306*5c591343SA. Cody Schuffelen     result = NvAdd(sizeof(OBJECT), sizeof(OBJECT), evictHandle, (BYTE *)object);
1307*5c591343SA. Cody Schuffelen 
1308*5c591343SA. Cody Schuffelen     // Put things back the way they were
1309*5c591343SA. Cody Schuffelen     object->attributes.evict = CLEAR;
1310*5c591343SA. Cody Schuffelen     object->evictHandle = temp;
1311*5c591343SA. Cody Schuffelen 
1312*5c591343SA. Cody Schuffelen     return result;
1313*5c591343SA. Cody Schuffelen }
1314*5c591343SA. Cody Schuffelen 
1315*5c591343SA. Cody Schuffelen //*** NvDeleteIndex()
1316*5c591343SA. Cody Schuffelen // This function is used to delete an NV Index.
1317*5c591343SA. Cody Schuffelen //  Return Type: TPM_RC
1318*5c591343SA. Cody Schuffelen //      TPM_RC_NV_UNAVAILABLE   NV is not accessible
1319*5c591343SA. Cody Schuffelen //      TPM_RC_NV_RATE          NV is rate limiting
1320*5c591343SA. Cody Schuffelen TPM_RC
NvDeleteIndex(NV_INDEX * nvIndex,NV_REF entityAddr)1321*5c591343SA. Cody Schuffelen NvDeleteIndex(
1322*5c591343SA. Cody Schuffelen     NV_INDEX        *nvIndex,       // IN: an in RAM index descriptor
1323*5c591343SA. Cody Schuffelen     NV_REF           entityAddr     // IN: location in NV
1324*5c591343SA. Cody Schuffelen     )
1325*5c591343SA. Cody Schuffelen {
1326*5c591343SA. Cody Schuffelen     TPM_RC           result;
1327*5c591343SA. Cody Schuffelen //
1328*5c591343SA. Cody Schuffelen     if(nvIndex != NULL)
1329*5c591343SA. Cody Schuffelen     {
1330*5c591343SA. Cody Schuffelen         // Whenever a counter is deleted, make sure that the MaxCounter value is
1331*5c591343SA. Cody Schuffelen         // updated to reflect the value
1332*5c591343SA. Cody Schuffelen         if(IsNvCounterIndex(nvIndex->publicArea.attributes)
1333*5c591343SA. Cody Schuffelen            && IS_ATTRIBUTE(nvIndex->publicArea.attributes, TPMA_NV, WRITTEN))
1334*5c591343SA. Cody Schuffelen             NvUpdateMaxCount(NvGetUINT64Data(nvIndex, entityAddr));
1335*5c591343SA. Cody Schuffelen         result = NvDelete(entityAddr);
1336*5c591343SA. Cody Schuffelen         if(result != TPM_RC_SUCCESS)
1337*5c591343SA. Cody Schuffelen             return result;
1338*5c591343SA. Cody Schuffelen         // If the NV Index is RAM backed, delete the RAM data as well
1339*5c591343SA. Cody Schuffelen         if(IS_ATTRIBUTE(nvIndex->publicArea.attributes, TPMA_NV, ORDERLY))
1340*5c591343SA. Cody Schuffelen             NvDeleteRAM(nvIndex->publicArea.nvIndex);
1341*5c591343SA. Cody Schuffelen         NvIndexCacheInit();
1342*5c591343SA. Cody Schuffelen     }
1343*5c591343SA. Cody Schuffelen     return TPM_RC_SUCCESS;
1344*5c591343SA. Cody Schuffelen }
1345*5c591343SA. Cody Schuffelen 
1346*5c591343SA. Cody Schuffelen //*** NvDeleteEvict()
1347*5c591343SA. Cody Schuffelen // This function will delete a NV evict object.
1348*5c591343SA. Cody Schuffelen // Will return success if object deleted or if it does not exist
1349*5c591343SA. Cody Schuffelen 
1350*5c591343SA. Cody Schuffelen TPM_RC
NvDeleteEvict(TPM_HANDLE handle)1351*5c591343SA. Cody Schuffelen NvDeleteEvict(
1352*5c591343SA. Cody Schuffelen     TPM_HANDLE       handle         // IN: handle of entity to be deleted
1353*5c591343SA. Cody Schuffelen     )
1354*5c591343SA. Cody Schuffelen {
1355*5c591343SA. Cody Schuffelen     NV_REF      entityAddr = NvFindEvict(handle, NULL);     // pointer to entity
1356*5c591343SA. Cody Schuffelen     TPM_RC      result = TPM_RC_SUCCESS;
1357*5c591343SA. Cody Schuffelen //
1358*5c591343SA. Cody Schuffelen     if(entityAddr != 0)
1359*5c591343SA. Cody Schuffelen         result = NvDelete(entityAddr);
1360*5c591343SA. Cody Schuffelen     return result;
1361*5c591343SA. Cody Schuffelen }
1362*5c591343SA. Cody Schuffelen 
1363*5c591343SA. Cody Schuffelen //*** NvFlushHierarchy()
1364*5c591343SA. Cody Schuffelen // This function will delete persistent objects belonging to the indicated hierarchy.
1365*5c591343SA. Cody Schuffelen // If the storage hierarchy is selected, the function will also delete any
1366*5c591343SA. Cody Schuffelen // NV Index defined using ownerAuth.
1367*5c591343SA. Cody Schuffelen //  Return Type: TPM_RC
1368*5c591343SA. Cody Schuffelen //      TPM_RC_NV_RATE           NV is unavailable because of rate limit
1369*5c591343SA. Cody Schuffelen //      TPM_RC_NV_UNAVAILABLE    NV is inaccessible
1370*5c591343SA. Cody Schuffelen TPM_RC
NvFlushHierarchy(TPMI_RH_HIERARCHY hierarchy)1371*5c591343SA. Cody Schuffelen NvFlushHierarchy(
1372*5c591343SA. Cody Schuffelen     TPMI_RH_HIERARCHY    hierarchy      // IN: hierarchy to be flushed.
1373*5c591343SA. Cody Schuffelen     )
1374*5c591343SA. Cody Schuffelen {
1375*5c591343SA. Cody Schuffelen     NV_REF           iter = NV_REF_INIT;
1376*5c591343SA. Cody Schuffelen     NV_REF           currentAddr;
1377*5c591343SA. Cody Schuffelen     TPM_HANDLE       entityHandle;
1378*5c591343SA. Cody Schuffelen     TPM_RC           result = TPM_RC_SUCCESS;
1379*5c591343SA. Cody Schuffelen //
1380*5c591343SA. Cody Schuffelen     while((currentAddr = NvNext(&iter, &entityHandle)) != 0)
1381*5c591343SA. Cody Schuffelen     {
1382*5c591343SA. Cody Schuffelen         if(HandleGetType(entityHandle) == TPM_HT_NV_INDEX)
1383*5c591343SA. Cody Schuffelen         {
1384*5c591343SA. Cody Schuffelen             NV_INDEX        nvIndex;
1385*5c591343SA. Cody Schuffelen //
1386*5c591343SA. Cody Schuffelen             // If flush endorsement or platform hierarchy, no NV Index would be
1387*5c591343SA. Cody Schuffelen             // flushed
1388*5c591343SA. Cody Schuffelen             if(hierarchy == TPM_RH_ENDORSEMENT || hierarchy == TPM_RH_PLATFORM)
1389*5c591343SA. Cody Schuffelen                 continue;
1390*5c591343SA. Cody Schuffelen             // Get the index information
1391*5c591343SA. Cody Schuffelen             NvReadNvIndexInfo(currentAddr, &nvIndex);
1392*5c591343SA. Cody Schuffelen 
1393*5c591343SA. Cody Schuffelen             // For storage hierarchy, flush OwnerCreated index
1394*5c591343SA. Cody Schuffelen             if(!IS_ATTRIBUTE(nvIndex.publicArea.attributes, TPMA_NV,
1395*5c591343SA. Cody Schuffelen                              PLATFORMCREATE))
1396*5c591343SA. Cody Schuffelen             {
1397*5c591343SA. Cody Schuffelen                 // Delete the index (including RAM for orderly)
1398*5c591343SA. Cody Schuffelen                 result = NvDeleteIndex(&nvIndex, currentAddr);
1399*5c591343SA. Cody Schuffelen                 if(result != TPM_RC_SUCCESS)
1400*5c591343SA. Cody Schuffelen                     break;
1401*5c591343SA. Cody Schuffelen                 // Re-iterate from beginning after a delete
1402*5c591343SA. Cody Schuffelen                 iter = NV_REF_INIT;
1403*5c591343SA. Cody Schuffelen             }
1404*5c591343SA. Cody Schuffelen         }
1405*5c591343SA. Cody Schuffelen         else if(HandleGetType(entityHandle) == TPM_HT_PERSISTENT)
1406*5c591343SA. Cody Schuffelen         {
1407*5c591343SA. Cody Schuffelen             OBJECT_ATTRIBUTES           attributes;
1408*5c591343SA. Cody Schuffelen //
1409*5c591343SA. Cody Schuffelen             NvRead(&attributes,
1410*5c591343SA. Cody Schuffelen                    (UINT32)(currentAddr
1411*5c591343SA. Cody Schuffelen                             + sizeof(TPM_HANDLE)
1412*5c591343SA. Cody Schuffelen                             + offsetof(OBJECT, attributes)),
1413*5c591343SA. Cody Schuffelen                    sizeof(OBJECT_ATTRIBUTES));
1414*5c591343SA. Cody Schuffelen             // If the evict object belongs to the hierarchy to be flushed...
1415*5c591343SA. Cody Schuffelen             if((hierarchy == TPM_RH_PLATFORM && attributes.ppsHierarchy == SET)
1416*5c591343SA. Cody Schuffelen                || (hierarchy == TPM_RH_OWNER && attributes.spsHierarchy == SET)
1417*5c591343SA. Cody Schuffelen                || (hierarchy == TPM_RH_ENDORSEMENT
1418*5c591343SA. Cody Schuffelen                    &&  attributes.epsHierarchy == SET))
1419*5c591343SA. Cody Schuffelen             {
1420*5c591343SA. Cody Schuffelen                 // ...then delete the evict object
1421*5c591343SA. Cody Schuffelen                 result = NvDelete(currentAddr);
1422*5c591343SA. Cody Schuffelen                 if(result != TPM_RC_SUCCESS)
1423*5c591343SA. Cody Schuffelen                     break;
1424*5c591343SA. Cody Schuffelen                 // Re-iterate from beginning after a delete
1425*5c591343SA. Cody Schuffelen                 iter = NV_REF_INIT;
1426*5c591343SA. Cody Schuffelen             }
1427*5c591343SA. Cody Schuffelen         }
1428*5c591343SA. Cody Schuffelen         else
1429*5c591343SA. Cody Schuffelen         {
1430*5c591343SA. Cody Schuffelen             FAIL(FATAL_ERROR_INTERNAL);
1431*5c591343SA. Cody Schuffelen         }
1432*5c591343SA. Cody Schuffelen     }
1433*5c591343SA. Cody Schuffelen     return result;
1434*5c591343SA. Cody Schuffelen }
1435*5c591343SA. Cody Schuffelen 
1436*5c591343SA. Cody Schuffelen //*** NvSetGlobalLock()
1437*5c591343SA. Cody Schuffelen // This function is used to SET the TPMA_NV_WRITELOCKED attribute for all
1438*5c591343SA. Cody Schuffelen // NV indexes that have TPMA_NV_GLOBALLOCK SET. This function is use by
1439*5c591343SA. Cody Schuffelen // TPM2_NV_GlobalWriteLock().
1440*5c591343SA. Cody Schuffelen //  Return Type: TPM_RC
1441*5c591343SA. Cody Schuffelen //      TPM_RC_NV_RATE           NV is unavailable because of rate limit
1442*5c591343SA. Cody Schuffelen //      TPM_RC_NV_UNAVAILABLE    NV is inaccessible
1443*5c591343SA. Cody Schuffelen TPM_RC
NvSetGlobalLock(void)1444*5c591343SA. Cody Schuffelen NvSetGlobalLock(
1445*5c591343SA. Cody Schuffelen     void
1446*5c591343SA. Cody Schuffelen     )
1447*5c591343SA. Cody Schuffelen {
1448*5c591343SA. Cody Schuffelen     NV_REF           iter = NV_REF_INIT;
1449*5c591343SA. Cody Schuffelen     NV_RAM_REF       ramIter = NV_RAM_REF_INIT;
1450*5c591343SA. Cody Schuffelen     NV_REF           currentAddr;
1451*5c591343SA. Cody Schuffelen     NV_RAM_REF       currentRamAddr;
1452*5c591343SA. Cody Schuffelen     TPM_RC           result = TPM_RC_SUCCESS;
1453*5c591343SA. Cody Schuffelen //
1454*5c591343SA. Cody Schuffelen     // Check all normal indexes
1455*5c591343SA. Cody Schuffelen     while((currentAddr = NvNextIndex(NULL, &iter)) != 0)
1456*5c591343SA. Cody Schuffelen     {
1457*5c591343SA. Cody Schuffelen         TPMA_NV         attributes = NvReadNvIndexAttributes(currentAddr);
1458*5c591343SA. Cody Schuffelen //
1459*5c591343SA. Cody Schuffelen         // See if it should be locked
1460*5c591343SA. Cody Schuffelen         if(!IS_ATTRIBUTE(attributes, TPMA_NV, ORDERLY)
1461*5c591343SA. Cody Schuffelen            &&  IS_ATTRIBUTE(attributes, TPMA_NV, GLOBALLOCK))
1462*5c591343SA. Cody Schuffelen         {
1463*5c591343SA. Cody Schuffelen             SET_ATTRIBUTE(attributes, TPMA_NV, WRITELOCKED);
1464*5c591343SA. Cody Schuffelen             result = NvWriteNvIndexAttributes(currentAddr, attributes);
1465*5c591343SA. Cody Schuffelen             if(result != TPM_RC_SUCCESS)
1466*5c591343SA. Cody Schuffelen                 return result;
1467*5c591343SA. Cody Schuffelen         }
1468*5c591343SA. Cody Schuffelen     }
1469*5c591343SA. Cody Schuffelen     // Now search all the orderly attributes
1470*5c591343SA. Cody Schuffelen     while((currentRamAddr = NvRamNext(&ramIter, NULL)) != 0)
1471*5c591343SA. Cody Schuffelen     {
1472*5c591343SA. Cody Schuffelen         // See if it should be locked
1473*5c591343SA. Cody Schuffelen         TPMA_NV         attributes = NvReadRamIndexAttributes(currentRamAddr);
1474*5c591343SA. Cody Schuffelen         if(IS_ATTRIBUTE(attributes, TPMA_NV, GLOBALLOCK))
1475*5c591343SA. Cody Schuffelen         {
1476*5c591343SA. Cody Schuffelen             SET_ATTRIBUTE(attributes, TPMA_NV, WRITELOCKED);
1477*5c591343SA. Cody Schuffelen             NvWriteRamIndexAttributes(currentRamAddr, attributes);
1478*5c591343SA. Cody Schuffelen         }
1479*5c591343SA. Cody Schuffelen     }
1480*5c591343SA. Cody Schuffelen     return result;
1481*5c591343SA. Cody Schuffelen }
1482*5c591343SA. Cody Schuffelen 
1483*5c591343SA. Cody Schuffelen //***InsertSort()
1484*5c591343SA. Cody Schuffelen // Sort a handle into handle list in ascending order.  The total handle number in
1485*5c591343SA. Cody Schuffelen // the list should not exceed MAX_CAP_HANDLES
1486*5c591343SA. Cody Schuffelen static void
InsertSort(TPML_HANDLE * handleList,UINT32 count,TPM_HANDLE entityHandle)1487*5c591343SA. Cody Schuffelen InsertSort(
1488*5c591343SA. Cody Schuffelen     TPML_HANDLE     *handleList,    // IN/OUT: sorted handle list
1489*5c591343SA. Cody Schuffelen     UINT32           count,         // IN: maximum count in the handle list
1490*5c591343SA. Cody Schuffelen     TPM_HANDLE       entityHandle   // IN: handle to be inserted
1491*5c591343SA. Cody Schuffelen     )
1492*5c591343SA. Cody Schuffelen {
1493*5c591343SA. Cody Schuffelen     UINT32          i, j;
1494*5c591343SA. Cody Schuffelen     UINT32          originalCount;
1495*5c591343SA. Cody Schuffelen //
1496*5c591343SA. Cody Schuffelen     // For a corner case that the maximum count is 0, do nothing
1497*5c591343SA. Cody Schuffelen     if(count == 0)
1498*5c591343SA. Cody Schuffelen         return;
1499*5c591343SA. Cody Schuffelen     // For empty list, add the handle at the beginning and return
1500*5c591343SA. Cody Schuffelen     if(handleList->count == 0)
1501*5c591343SA. Cody Schuffelen     {
1502*5c591343SA. Cody Schuffelen         handleList->handle[0] = entityHandle;
1503*5c591343SA. Cody Schuffelen         handleList->count++;
1504*5c591343SA. Cody Schuffelen         return;
1505*5c591343SA. Cody Schuffelen     }
1506*5c591343SA. Cody Schuffelen     // Check if the maximum of the list has been reached
1507*5c591343SA. Cody Schuffelen     originalCount = handleList->count;
1508*5c591343SA. Cody Schuffelen     if(originalCount < count)
1509*5c591343SA. Cody Schuffelen         handleList->count++;
1510*5c591343SA. Cody Schuffelen     // Insert the handle to the list
1511*5c591343SA. Cody Schuffelen     for(i = 0; i < originalCount; i++)
1512*5c591343SA. Cody Schuffelen     {
1513*5c591343SA. Cody Schuffelen         if(handleList->handle[i] > entityHandle)
1514*5c591343SA. Cody Schuffelen         {
1515*5c591343SA. Cody Schuffelen             for(j = handleList->count - 1; j > i; j--)
1516*5c591343SA. Cody Schuffelen             {
1517*5c591343SA. Cody Schuffelen                 handleList->handle[j] = handleList->handle[j - 1];
1518*5c591343SA. Cody Schuffelen             }
1519*5c591343SA. Cody Schuffelen             break;
1520*5c591343SA. Cody Schuffelen         }
1521*5c591343SA. Cody Schuffelen     }
1522*5c591343SA. Cody Schuffelen     // If a slot was found, insert the handle in this position
1523*5c591343SA. Cody Schuffelen     if(i < originalCount || handleList->count > originalCount)
1524*5c591343SA. Cody Schuffelen         handleList->handle[i] = entityHandle;
1525*5c591343SA. Cody Schuffelen     return;
1526*5c591343SA. Cody Schuffelen }
1527*5c591343SA. Cody Schuffelen 
1528*5c591343SA. Cody Schuffelen //*** NvCapGetPersistent()
1529*5c591343SA. Cody Schuffelen // This function is used to get a list of handles of the persistent objects,
1530*5c591343SA. Cody Schuffelen // starting at 'handle'.
1531*5c591343SA. Cody Schuffelen //
1532*5c591343SA. Cody Schuffelen // 'Handle' must be in valid persistent object handle range, but does not
1533*5c591343SA. Cody Schuffelen // have to reference an existing persistent object.
1534*5c591343SA. Cody Schuffelen //  Return Type: TPMI_YES_NO
1535*5c591343SA. Cody Schuffelen //      YES         if there are more handles available
1536*5c591343SA. Cody Schuffelen //      NO          all the available handles has been returned
1537*5c591343SA. Cody Schuffelen TPMI_YES_NO
NvCapGetPersistent(TPMI_DH_OBJECT handle,UINT32 count,TPML_HANDLE * handleList)1538*5c591343SA. Cody Schuffelen NvCapGetPersistent(
1539*5c591343SA. Cody Schuffelen     TPMI_DH_OBJECT   handle,        // IN: start handle
1540*5c591343SA. Cody Schuffelen     UINT32           count,         // IN: maximum number of returned handles
1541*5c591343SA. Cody Schuffelen     TPML_HANDLE     *handleList     // OUT: list of handle
1542*5c591343SA. Cody Schuffelen     )
1543*5c591343SA. Cody Schuffelen {
1544*5c591343SA. Cody Schuffelen     TPMI_YES_NO              more = NO;
1545*5c591343SA. Cody Schuffelen     NV_REF                   iter = NV_REF_INIT;
1546*5c591343SA. Cody Schuffelen     NV_REF                   currentAddr;
1547*5c591343SA. Cody Schuffelen     TPM_HANDLE               entityHandle;
1548*5c591343SA. Cody Schuffelen //
1549*5c591343SA. Cody Schuffelen     pAssert(HandleGetType(handle) == TPM_HT_PERSISTENT);
1550*5c591343SA. Cody Schuffelen 
1551*5c591343SA. Cody Schuffelen     // Initialize output handle list
1552*5c591343SA. Cody Schuffelen     handleList->count = 0;
1553*5c591343SA. Cody Schuffelen 
1554*5c591343SA. Cody Schuffelen     // The maximum count of handles we may return is MAX_CAP_HANDLES
1555*5c591343SA. Cody Schuffelen     if(count > MAX_CAP_HANDLES) count = MAX_CAP_HANDLES;
1556*5c591343SA. Cody Schuffelen 
1557*5c591343SA. Cody Schuffelen     while((currentAddr = NvNextEvict(&entityHandle, &iter)) != 0)
1558*5c591343SA. Cody Schuffelen     {
1559*5c591343SA. Cody Schuffelen         // Ignore persistent handles that have values less than the input handle
1560*5c591343SA. Cody Schuffelen         if(entityHandle < handle)
1561*5c591343SA. Cody Schuffelen             continue;
1562*5c591343SA. Cody Schuffelen         // if the handles in the list have reached the requested count, and there
1563*5c591343SA. Cody Schuffelen         // are still handles need to be inserted, indicate that there are more.
1564*5c591343SA. Cody Schuffelen         if(handleList->count == count)
1565*5c591343SA. Cody Schuffelen             more = YES;
1566*5c591343SA. Cody Schuffelen         // A handle with a value larger than start handle is a candidate
1567*5c591343SA. Cody Schuffelen         // for return. Insert sort it to the return list.  Insert sort algorithm
1568*5c591343SA. Cody Schuffelen         // is chosen here for simplicity based on the assumption that the total
1569*5c591343SA. Cody Schuffelen         // number of NV indexes is small.  For an implementation that may allow
1570*5c591343SA. Cody Schuffelen         // large number of NV indexes, a more efficient sorting algorithm may be
1571*5c591343SA. Cody Schuffelen         // used here.
1572*5c591343SA. Cody Schuffelen         InsertSort(handleList, count, entityHandle);
1573*5c591343SA. Cody Schuffelen     }
1574*5c591343SA. Cody Schuffelen     return more;
1575*5c591343SA. Cody Schuffelen }
1576*5c591343SA. Cody Schuffelen 
1577*5c591343SA. Cody Schuffelen //*** NvCapGetIndex()
1578*5c591343SA. Cody Schuffelen // This function returns a list of handles of NV indexes, starting from 'handle'.
1579*5c591343SA. Cody Schuffelen // 'Handle' must be in the range of NV indexes, but does not have to reference
1580*5c591343SA. Cody Schuffelen // an existing NV Index.
1581*5c591343SA. Cody Schuffelen //  Return Type: TPMI_YES_NO
1582*5c591343SA. Cody Schuffelen //      YES         if there are more handles to report
1583*5c591343SA. Cody Schuffelen //      NO          all the available handles has been reported
1584*5c591343SA. Cody Schuffelen TPMI_YES_NO
NvCapGetIndex(TPMI_DH_OBJECT handle,UINT32 count,TPML_HANDLE * handleList)1585*5c591343SA. Cody Schuffelen NvCapGetIndex(
1586*5c591343SA. Cody Schuffelen     TPMI_DH_OBJECT   handle,        // IN: start handle
1587*5c591343SA. Cody Schuffelen     UINT32           count,         // IN: max number of returned handles
1588*5c591343SA. Cody Schuffelen     TPML_HANDLE     *handleList     // OUT: list of handle
1589*5c591343SA. Cody Schuffelen     )
1590*5c591343SA. Cody Schuffelen {
1591*5c591343SA. Cody Schuffelen     TPMI_YES_NO              more = NO;
1592*5c591343SA. Cody Schuffelen     NV_REF                   iter = NV_REF_INIT;
1593*5c591343SA. Cody Schuffelen     NV_REF                   currentAddr;
1594*5c591343SA. Cody Schuffelen     TPM_HANDLE               nvHandle;
1595*5c591343SA. Cody Schuffelen //
1596*5c591343SA. Cody Schuffelen     pAssert(HandleGetType(handle) == TPM_HT_NV_INDEX);
1597*5c591343SA. Cody Schuffelen 
1598*5c591343SA. Cody Schuffelen     // Initialize output handle list
1599*5c591343SA. Cody Schuffelen     handleList->count = 0;
1600*5c591343SA. Cody Schuffelen 
1601*5c591343SA. Cody Schuffelen     // The maximum count of handles we may return is MAX_CAP_HANDLES
1602*5c591343SA. Cody Schuffelen     if(count > MAX_CAP_HANDLES) count = MAX_CAP_HANDLES;
1603*5c591343SA. Cody Schuffelen 
1604*5c591343SA. Cody Schuffelen     while((currentAddr = NvNextIndex(&nvHandle, &iter)) != 0)
1605*5c591343SA. Cody Schuffelen     {
1606*5c591343SA. Cody Schuffelen         // Ignore index handles that have values less than the 'handle'
1607*5c591343SA. Cody Schuffelen         if(nvHandle < handle)
1608*5c591343SA. Cody Schuffelen             continue;
1609*5c591343SA. Cody Schuffelen         // if the count of handles in the list has reached the requested count,
1610*5c591343SA. Cody Schuffelen         // and there are still handles to report, set more.
1611*5c591343SA. Cody Schuffelen         if(handleList->count == count)
1612*5c591343SA. Cody Schuffelen             more = YES;
1613*5c591343SA. Cody Schuffelen         // A handle with a value larger than start handle is a candidate
1614*5c591343SA. Cody Schuffelen         // for return. Insert sort it to the return list.  Insert sort algorithm
1615*5c591343SA. Cody Schuffelen         // is chosen here for simplicity based on the assumption that the total
1616*5c591343SA. Cody Schuffelen         // number of NV indexes is small.  For an implementation that may allow
1617*5c591343SA. Cody Schuffelen         // large number of NV indexes, a more efficient sorting algorithm may be
1618*5c591343SA. Cody Schuffelen         // used here.
1619*5c591343SA. Cody Schuffelen         InsertSort(handleList, count, nvHandle);
1620*5c591343SA. Cody Schuffelen     }
1621*5c591343SA. Cody Schuffelen     return more;
1622*5c591343SA. Cody Schuffelen }
1623*5c591343SA. Cody Schuffelen 
1624*5c591343SA. Cody Schuffelen //*** NvCapGetIndexNumber()
1625*5c591343SA. Cody Schuffelen // This function returns the count of NV Indexes currently defined.
1626*5c591343SA. Cody Schuffelen UINT32
NvCapGetIndexNumber(void)1627*5c591343SA. Cody Schuffelen NvCapGetIndexNumber(
1628*5c591343SA. Cody Schuffelen     void
1629*5c591343SA. Cody Schuffelen     )
1630*5c591343SA. Cody Schuffelen {
1631*5c591343SA. Cody Schuffelen     UINT32           num = 0;
1632*5c591343SA. Cody Schuffelen     NV_REF           iter = NV_REF_INIT;
1633*5c591343SA. Cody Schuffelen //
1634*5c591343SA. Cody Schuffelen     while(NvNextIndex(NULL, &iter) != 0)
1635*5c591343SA. Cody Schuffelen         num++;
1636*5c591343SA. Cody Schuffelen     return num;
1637*5c591343SA. Cody Schuffelen }
1638*5c591343SA. Cody Schuffelen 
1639*5c591343SA. Cody Schuffelen //*** NvCapGetPersistentNumber()
1640*5c591343SA. Cody Schuffelen // Function returns the count of persistent objects currently in NV memory.
1641*5c591343SA. Cody Schuffelen UINT32
NvCapGetPersistentNumber(void)1642*5c591343SA. Cody Schuffelen NvCapGetPersistentNumber(
1643*5c591343SA. Cody Schuffelen     void
1644*5c591343SA. Cody Schuffelen     )
1645*5c591343SA. Cody Schuffelen {
1646*5c591343SA. Cody Schuffelen     UINT32          num = 0;
1647*5c591343SA. Cody Schuffelen     NV_REF         iter = NV_REF_INIT;
1648*5c591343SA. Cody Schuffelen     TPM_HANDLE      handle;
1649*5c591343SA. Cody Schuffelen //
1650*5c591343SA. Cody Schuffelen     while(NvNextEvict(&handle, &iter) != 0)
1651*5c591343SA. Cody Schuffelen         num++;
1652*5c591343SA. Cody Schuffelen     return num;
1653*5c591343SA. Cody Schuffelen }
1654*5c591343SA. Cody Schuffelen 
1655*5c591343SA. Cody Schuffelen //*** NvCapGetPersistentAvail()
1656*5c591343SA. Cody Schuffelen // This function returns an estimate of the number of additional persistent
1657*5c591343SA. Cody Schuffelen // objects that could be loaded into NV memory.
1658*5c591343SA. Cody Schuffelen UINT32
NvCapGetPersistentAvail(void)1659*5c591343SA. Cody Schuffelen NvCapGetPersistentAvail(
1660*5c591343SA. Cody Schuffelen     void
1661*5c591343SA. Cody Schuffelen     )
1662*5c591343SA. Cody Schuffelen {
1663*5c591343SA. Cody Schuffelen     UINT32          availNVSpace;
1664*5c591343SA. Cody Schuffelen     UINT32          counterNum = NvCapGetCounterNumber();
1665*5c591343SA. Cody Schuffelen     UINT32          reserved = sizeof(NV_LIST_TERMINATOR);
1666*5c591343SA. Cody Schuffelen //
1667*5c591343SA. Cody Schuffelen     // Get the available space in NV storage
1668*5c591343SA. Cody Schuffelen     availNVSpace = NvGetFreeBytes();
1669*5c591343SA. Cody Schuffelen 
1670*5c591343SA. Cody Schuffelen     if(counterNum < MIN_COUNTER_INDICES)
1671*5c591343SA. Cody Schuffelen     {
1672*5c591343SA. Cody Schuffelen         // Some space has to be reserved for counter objects.
1673*5c591343SA. Cody Schuffelen         reserved += (MIN_COUNTER_INDICES - counterNum) * NV_INDEX_COUNTER_SIZE;
1674*5c591343SA. Cody Schuffelen         if(reserved > availNVSpace)
1675*5c591343SA. Cody Schuffelen             availNVSpace = 0;
1676*5c591343SA. Cody Schuffelen         else
1677*5c591343SA. Cody Schuffelen             availNVSpace -= reserved;
1678*5c591343SA. Cody Schuffelen     }
1679*5c591343SA. Cody Schuffelen     return availNVSpace / NV_EVICT_OBJECT_SIZE;
1680*5c591343SA. Cody Schuffelen }
1681*5c591343SA. Cody Schuffelen 
1682*5c591343SA. Cody Schuffelen //*** NvCapGetCounterNumber()
1683*5c591343SA. Cody Schuffelen // Get the number of defined NV Indexes that are counter indexes.
1684*5c591343SA. Cody Schuffelen UINT32
NvCapGetCounterNumber(void)1685*5c591343SA. Cody Schuffelen NvCapGetCounterNumber(
1686*5c591343SA. Cody Schuffelen     void
1687*5c591343SA. Cody Schuffelen     )
1688*5c591343SA. Cody Schuffelen {
1689*5c591343SA. Cody Schuffelen     NV_REF           iter = NV_REF_INIT;
1690*5c591343SA. Cody Schuffelen     NV_REF           currentAddr;
1691*5c591343SA. Cody Schuffelen     UINT32           num = 0;
1692*5c591343SA. Cody Schuffelen //
1693*5c591343SA. Cody Schuffelen     while((currentAddr = NvNextIndex(NULL, &iter)) != 0)
1694*5c591343SA. Cody Schuffelen     {
1695*5c591343SA. Cody Schuffelen         TPMA_NV             attributes = NvReadNvIndexAttributes(currentAddr);
1696*5c591343SA. Cody Schuffelen         if(IsNvCounterIndex(attributes))
1697*5c591343SA. Cody Schuffelen             num++;
1698*5c591343SA. Cody Schuffelen     }
1699*5c591343SA. Cody Schuffelen     return num;
1700*5c591343SA. Cody Schuffelen }
1701*5c591343SA. Cody Schuffelen 
1702*5c591343SA. Cody Schuffelen //*** NvSetStartupAttributes()
1703*5c591343SA. Cody Schuffelen // Local function to set the attributes of an Index at TPM Reset and TPM Restart.
1704*5c591343SA. Cody Schuffelen static TPMA_NV
NvSetStartupAttributes(TPMA_NV attributes,STARTUP_TYPE type)1705*5c591343SA. Cody Schuffelen NvSetStartupAttributes(
1706*5c591343SA. Cody Schuffelen     TPMA_NV         attributes,         // IN: attributes to change
1707*5c591343SA. Cody Schuffelen     STARTUP_TYPE     type               // IN: start up type
1708*5c591343SA. Cody Schuffelen     )
1709*5c591343SA. Cody Schuffelen {
1710*5c591343SA. Cody Schuffelen     // Clear read lock
1711*5c591343SA. Cody Schuffelen     CLEAR_ATTRIBUTE(attributes, TPMA_NV, READLOCKED);
1712*5c591343SA. Cody Schuffelen 
1713*5c591343SA. Cody Schuffelen     // Will change a non counter index to the unwritten state if:
1714*5c591343SA. Cody Schuffelen     // a) TPMA_NV_CLEAR_STCLEAR is SET
1715*5c591343SA. Cody Schuffelen     // b) orderly and TPM Reset
1716*5c591343SA. Cody Schuffelen     if(!IsNvCounterIndex(attributes))
1717*5c591343SA. Cody Schuffelen     {
1718*5c591343SA. Cody Schuffelen         if(IS_ATTRIBUTE(attributes, TPMA_NV, CLEAR_STCLEAR)
1719*5c591343SA. Cody Schuffelen            || (IS_ATTRIBUTE(attributes, TPMA_NV, ORDERLY)
1720*5c591343SA. Cody Schuffelen                && (type == SU_RESET)))
1721*5c591343SA. Cody Schuffelen             CLEAR_ATTRIBUTE(attributes, TPMA_NV, WRITTEN);
1722*5c591343SA. Cody Schuffelen     }
1723*5c591343SA. Cody Schuffelen     // Unlock any index that is not written or that does not have
1724*5c591343SA. Cody Schuffelen     // TPMA_NV_WRITEDEFINE SET.
1725*5c591343SA. Cody Schuffelen     if(!IS_ATTRIBUTE(attributes, TPMA_NV, WRITTEN)
1726*5c591343SA. Cody Schuffelen        || !IS_ATTRIBUTE(attributes, TPMA_NV, WRITEDEFINE))
1727*5c591343SA. Cody Schuffelen         CLEAR_ATTRIBUTE(attributes, TPMA_NV, WRITELOCKED);
1728*5c591343SA. Cody Schuffelen     return attributes;
1729*5c591343SA. Cody Schuffelen }
1730*5c591343SA. Cody Schuffelen 
1731*5c591343SA. Cody Schuffelen //*** NvEntityStartup()
1732*5c591343SA. Cody Schuffelen //  This function is called at TPM_Startup(). If the startup completes
1733*5c591343SA. Cody Schuffelen //  a TPM Resume cycle, no action is taken. If the startup is a TPM Reset
1734*5c591343SA. Cody Schuffelen //  or a TPM Restart, then this function will:
1735*5c591343SA. Cody Schuffelen //  a) clear read/write lock;
1736*5c591343SA. Cody Schuffelen //  b) reset NV Index data that has TPMA_NV_CLEAR_STCLEAR SET; and
1737*5c591343SA. Cody Schuffelen //  c) set the lower bits in orderly counters to 1 for a non-orderly startup
1738*5c591343SA. Cody Schuffelen //
1739*5c591343SA. Cody Schuffelen //  It is a prerequisite that NV be available for writing before this
1740*5c591343SA. Cody Schuffelen //  function is called.
1741*5c591343SA. Cody Schuffelen BOOL
NvEntityStartup(STARTUP_TYPE type)1742*5c591343SA. Cody Schuffelen NvEntityStartup(
1743*5c591343SA. Cody Schuffelen     STARTUP_TYPE     type           // IN: start up type
1744*5c591343SA. Cody Schuffelen     )
1745*5c591343SA. Cody Schuffelen {
1746*5c591343SA. Cody Schuffelen     NV_REF               iter = NV_REF_INIT;
1747*5c591343SA. Cody Schuffelen     NV_RAM_REF           ramIter = NV_RAM_REF_INIT;
1748*5c591343SA. Cody Schuffelen     NV_REF               currentAddr;        // offset points to the current entity
1749*5c591343SA. Cody Schuffelen     NV_RAM_REF           currentRamAddr;
1750*5c591343SA. Cody Schuffelen     TPM_HANDLE           nvHandle;
1751*5c591343SA. Cody Schuffelen     TPMA_NV              attributes;
1752*5c591343SA. Cody Schuffelen //
1753*5c591343SA. Cody Schuffelen     // Restore RAM index data
1754*5c591343SA. Cody Schuffelen     NvRead(s_indexOrderlyRam, NV_INDEX_RAM_DATA, sizeof(s_indexOrderlyRam));
1755*5c591343SA. Cody Schuffelen 
1756*5c591343SA. Cody Schuffelen     // Initialize the max NV counter value
1757*5c591343SA. Cody Schuffelen     NvSetMaxCount(NvGetMaxCount());
1758*5c591343SA. Cody Schuffelen 
1759*5c591343SA. Cody Schuffelen     // If recovering from state save, do nothing else
1760*5c591343SA. Cody Schuffelen     if(type == SU_RESUME)
1761*5c591343SA. Cody Schuffelen         return TRUE;
1762*5c591343SA. Cody Schuffelen     // Iterate all the NV Index to clear the locks
1763*5c591343SA. Cody Schuffelen     while((currentAddr = NvNextIndex(&nvHandle, &iter)) != 0)
1764*5c591343SA. Cody Schuffelen     {
1765*5c591343SA. Cody Schuffelen         attributes = NvReadNvIndexAttributes(currentAddr);
1766*5c591343SA. Cody Schuffelen 
1767*5c591343SA. Cody Schuffelen         // If this is an orderly index, defer processing until loop below
1768*5c591343SA. Cody Schuffelen         if(IS_ATTRIBUTE(attributes, TPMA_NV, ORDERLY))
1769*5c591343SA. Cody Schuffelen             continue;
1770*5c591343SA. Cody Schuffelen         // Set the attributes appropriate for this startup type
1771*5c591343SA. Cody Schuffelen         attributes = NvSetStartupAttributes(attributes, type);
1772*5c591343SA. Cody Schuffelen         NvWriteNvIndexAttributes(currentAddr, attributes);
1773*5c591343SA. Cody Schuffelen     }
1774*5c591343SA. Cody Schuffelen     // Iterate all the orderly indexes to clear the locks and initialize counters
1775*5c591343SA. Cody Schuffelen     while((currentRamAddr = NvRamNext(&ramIter, NULL)) != 0)
1776*5c591343SA. Cody Schuffelen     {
1777*5c591343SA. Cody Schuffelen         attributes = NvReadRamIndexAttributes(currentRamAddr);
1778*5c591343SA. Cody Schuffelen 
1779*5c591343SA. Cody Schuffelen         attributes = NvSetStartupAttributes(attributes, type);
1780*5c591343SA. Cody Schuffelen 
1781*5c591343SA. Cody Schuffelen         // update attributes in RAM
1782*5c591343SA. Cody Schuffelen         NvWriteRamIndexAttributes(currentRamAddr, attributes);
1783*5c591343SA. Cody Schuffelen 
1784*5c591343SA. Cody Schuffelen         // Set the lower bits in an orderly counter to 1 for a non-orderly startup
1785*5c591343SA. Cody Schuffelen         if(IsNvCounterIndex(attributes)
1786*5c591343SA. Cody Schuffelen            && (g_prevOrderlyState == SU_NONE_VALUE))
1787*5c591343SA. Cody Schuffelen         {
1788*5c591343SA. Cody Schuffelen             UINT64      counter;
1789*5c591343SA. Cody Schuffelen //
1790*5c591343SA. Cody Schuffelen             // Read the counter value last saved to NV.
1791*5c591343SA. Cody Schuffelen             counter = BYTE_ARRAY_TO_UINT64(currentRamAddr + sizeof(NV_RAM_HEADER));
1792*5c591343SA. Cody Schuffelen 
1793*5c591343SA. Cody Schuffelen             // Set the lower bits of counter to 1's
1794*5c591343SA. Cody Schuffelen             counter |= MAX_ORDERLY_COUNT;
1795*5c591343SA. Cody Schuffelen 
1796*5c591343SA. Cody Schuffelen             // Write back to RAM
1797*5c591343SA. Cody Schuffelen             // NOTE: Do not want to force a write to NV here. The counter value will
1798*5c591343SA. Cody Schuffelen             // stay in RAM until the next shutdown or rollover.
1799*5c591343SA. Cody Schuffelen             UINT64_TO_BYTE_ARRAY(counter, currentRamAddr + sizeof(NV_RAM_HEADER));
1800*5c591343SA. Cody Schuffelen         }
1801*5c591343SA. Cody Schuffelen     }
1802*5c591343SA. Cody Schuffelen     return TRUE;
1803*5c591343SA. Cody Schuffelen }
1804*5c591343SA. Cody Schuffelen 
1805*5c591343SA. Cody Schuffelen //*** NvCapGetCounterAvail()
1806*5c591343SA. Cody Schuffelen // This function returns an estimate of the number of additional counter type
1807*5c591343SA. Cody Schuffelen // NV indexes that can be defined.
1808*5c591343SA. Cody Schuffelen UINT32
NvCapGetCounterAvail(void)1809*5c591343SA. Cody Schuffelen NvCapGetCounterAvail(
1810*5c591343SA. Cody Schuffelen     void
1811*5c591343SA. Cody Schuffelen     )
1812*5c591343SA. Cody Schuffelen {
1813*5c591343SA. Cody Schuffelen     UINT32          availNVSpace;
1814*5c591343SA. Cody Schuffelen     UINT32          availRAMSpace;
1815*5c591343SA. Cody Schuffelen     UINT32          persistentNum = NvCapGetPersistentNumber();
1816*5c591343SA. Cody Schuffelen     UINT32          reserved = sizeof(NV_LIST_TERMINATOR);
1817*5c591343SA. Cody Schuffelen //
1818*5c591343SA. Cody Schuffelen     // Get the available space in NV storage
1819*5c591343SA. Cody Schuffelen     availNVSpace = NvGetFreeBytes();
1820*5c591343SA. Cody Schuffelen 
1821*5c591343SA. Cody Schuffelen     if(persistentNum < MIN_EVICT_OBJECTS)
1822*5c591343SA. Cody Schuffelen     {
1823*5c591343SA. Cody Schuffelen         // Some space has to be reserved for evict object. Adjust availNVSpace.
1824*5c591343SA. Cody Schuffelen         reserved += (MIN_EVICT_OBJECTS - persistentNum) * NV_EVICT_OBJECT_SIZE;
1825*5c591343SA. Cody Schuffelen         if(reserved > availNVSpace)
1826*5c591343SA. Cody Schuffelen             availNVSpace = 0;
1827*5c591343SA. Cody Schuffelen         else
1828*5c591343SA. Cody Schuffelen             availNVSpace -= reserved;
1829*5c591343SA. Cody Schuffelen     }
1830*5c591343SA. Cody Schuffelen     // Compute the available space in RAM
1831*5c591343SA. Cody Schuffelen     availRAMSpace = (int)(RAM_ORDERLY_END - NvRamGetEnd());
1832*5c591343SA. Cody Schuffelen 
1833*5c591343SA. Cody Schuffelen     // Return the min of counter number in NV and in RAM
1834*5c591343SA. Cody Schuffelen     if(availNVSpace / NV_INDEX_COUNTER_SIZE
1835*5c591343SA. Cody Schuffelen         > availRAMSpace / NV_RAM_INDEX_COUNTER_SIZE)
1836*5c591343SA. Cody Schuffelen         return availRAMSpace / NV_RAM_INDEX_COUNTER_SIZE;
1837*5c591343SA. Cody Schuffelen     else
1838*5c591343SA. Cody Schuffelen         return availNVSpace / NV_INDEX_COUNTER_SIZE;
1839*5c591343SA. Cody Schuffelen }
1840*5c591343SA. Cody Schuffelen 
1841*5c591343SA. Cody Schuffelen //*** NvFindHandle()
1842*5c591343SA. Cody Schuffelen // this function returns the offset in NV memory of the entity associated
1843*5c591343SA. Cody Schuffelen // with the input handle.  A value of zero indicates that handle does not
1844*5c591343SA. Cody Schuffelen //  exist reference an existing persistent object or defined NV Index.
1845*5c591343SA. Cody Schuffelen NV_REF
NvFindHandle(TPM_HANDLE handle)1846*5c591343SA. Cody Schuffelen NvFindHandle(
1847*5c591343SA. Cody Schuffelen     TPM_HANDLE       handle
1848*5c591343SA. Cody Schuffelen     )
1849*5c591343SA. Cody Schuffelen {
1850*5c591343SA. Cody Schuffelen     NV_REF           addr;
1851*5c591343SA. Cody Schuffelen     NV_REF           iter = NV_REF_INIT;
1852*5c591343SA. Cody Schuffelen     TPM_HANDLE       nextHandle;
1853*5c591343SA. Cody Schuffelen //
1854*5c591343SA. Cody Schuffelen     while((addr = NvNext(&iter, &nextHandle)) != 0)
1855*5c591343SA. Cody Schuffelen     {
1856*5c591343SA. Cody Schuffelen         if(nextHandle == handle)
1857*5c591343SA. Cody Schuffelen             break;
1858*5c591343SA. Cody Schuffelen     }
1859*5c591343SA. Cody Schuffelen     return addr;
1860*5c591343SA. Cody Schuffelen }
1861*5c591343SA. Cody Schuffelen 
1862*5c591343SA. Cody Schuffelen //** NV Max Counter
1863*5c591343SA. Cody Schuffelen //*** Introduction
1864*5c591343SA. Cody Schuffelen // The TPM keeps track of the highest value of a deleted counter index. When an
1865*5c591343SA. Cody Schuffelen // index is deleted, this value is updated if the deleted counter index is greater
1866*5c591343SA. Cody Schuffelen // than the previous value. When a new index is created and first incremented, it
1867*5c591343SA. Cody Schuffelen // will get a value that is at least one greater than any other index than any
1868*5c591343SA. Cody Schuffelen // previously deleted index. This insures that it is not possible to roll back an
1869*5c591343SA. Cody Schuffelen // index.
1870*5c591343SA. Cody Schuffelen //
1871*5c591343SA. Cody Schuffelen // The highest counter value is kept in NV in a special end-of-list marker. This
1872*5c591343SA. Cody Schuffelen // marker is only updated when an index is deleted. Otherwise it just moves.
1873*5c591343SA. Cody Schuffelen //
1874*5c591343SA. Cody Schuffelen // When the TPM starts up, it searches NV for the end of list marker and initializes
1875*5c591343SA. Cody Schuffelen // an in memory value (s_maxCounter).
1876*5c591343SA. Cody Schuffelen 
1877*5c591343SA. Cody Schuffelen //*** NvReadMaxCount()
1878*5c591343SA. Cody Schuffelen // This function returns the max NV counter value.
1879*5c591343SA. Cody Schuffelen //
1880*5c591343SA. Cody Schuffelen UINT64
NvReadMaxCount(void)1881*5c591343SA. Cody Schuffelen NvReadMaxCount(
1882*5c591343SA. Cody Schuffelen     void
1883*5c591343SA. Cody Schuffelen     )
1884*5c591343SA. Cody Schuffelen {
1885*5c591343SA. Cody Schuffelen     return s_maxCounter;
1886*5c591343SA. Cody Schuffelen }
1887*5c591343SA. Cody Schuffelen 
1888*5c591343SA. Cody Schuffelen //*** NvUpdateMaxCount()
1889*5c591343SA. Cody Schuffelen // This function updates the max counter value to NV memory. This is just staging
1890*5c591343SA. Cody Schuffelen // for the actual write that will occur when the NV index memory is modified.
1891*5c591343SA. Cody Schuffelen //
1892*5c591343SA. Cody Schuffelen void
NvUpdateMaxCount(UINT64 count)1893*5c591343SA. Cody Schuffelen NvUpdateMaxCount(
1894*5c591343SA. Cody Schuffelen     UINT64           count
1895*5c591343SA. Cody Schuffelen     )
1896*5c591343SA. Cody Schuffelen {
1897*5c591343SA. Cody Schuffelen     if(count > s_maxCounter)
1898*5c591343SA. Cody Schuffelen         s_maxCounter = count;
1899*5c591343SA. Cody Schuffelen }
1900*5c591343SA. Cody Schuffelen 
1901*5c591343SA. Cody Schuffelen //*** NvSetMaxCount()
1902*5c591343SA. Cody Schuffelen // This function is used at NV initialization time to set the initial value of
1903*5c591343SA. Cody Schuffelen // the maximum counter.
1904*5c591343SA. Cody Schuffelen void
NvSetMaxCount(UINT64 value)1905*5c591343SA. Cody Schuffelen NvSetMaxCount(
1906*5c591343SA. Cody Schuffelen     UINT64          value
1907*5c591343SA. Cody Schuffelen     )
1908*5c591343SA. Cody Schuffelen {
1909*5c591343SA. Cody Schuffelen     s_maxCounter = value;
1910*5c591343SA. Cody Schuffelen }
1911*5c591343SA. Cody Schuffelen 
1912*5c591343SA. Cody Schuffelen //*** NvGetMaxCount()
1913*5c591343SA. Cody Schuffelen // Function to get the NV max counter value from the end-of-list marker
1914*5c591343SA. Cody Schuffelen UINT64
NvGetMaxCount(void)1915*5c591343SA. Cody Schuffelen NvGetMaxCount(
1916*5c591343SA. Cody Schuffelen     void
1917*5c591343SA. Cody Schuffelen     )
1918*5c591343SA. Cody Schuffelen {
1919*5c591343SA. Cody Schuffelen     NV_REF               iter = NV_REF_INIT;
1920*5c591343SA. Cody Schuffelen     NV_REF               currentAddr;
1921*5c591343SA. Cody Schuffelen     UINT64               maxCount;
1922*5c591343SA. Cody Schuffelen //
1923*5c591343SA. Cody Schuffelen     // Find the end of list marker and initialize the NV Max Counter value.
1924*5c591343SA. Cody Schuffelen     while((currentAddr = NvNext(&iter, NULL )) != 0);
1925*5c591343SA. Cody Schuffelen     // 'iter' should be pointing at the end of list marker so read in the current
1926*5c591343SA. Cody Schuffelen     // value of the s_maxCounter.
1927*5c591343SA. Cody Schuffelen     NvRead(&maxCount, iter + sizeof(UINT32), sizeof(maxCount));
1928*5c591343SA. Cody Schuffelen 
1929*5c591343SA. Cody Schuffelen     return maxCount;
1930*5c591343SA. Cody Schuffelen }
1931