1 // SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
2 /* Copyright 2020 IBM Corp. */
3 #include <skiboot.h>
4 #include "secboot_tpm.h"
5 
6 /* Offset into the SECBOOT PNOR partition to write "TPMNV" data */
7 static size_t fakenv_offset = sizeof(struct secboot);
8 
9 struct fake_tpmnv {
10 	struct {
11 		struct secboot_header header;
12 		char vars[2048]; // Hardcode the size to 2048 for now
13 	} vars;
14 	struct tpmnv_control control;
15 	int defined[2];
16 } __attribute__((packed));
17 
18 static struct fake_tpmnv fakenv;
19 static int tpm_ready;
20 
21 
nv_index_address(int index)22 static inline void *nv_index_address(int index)
23 {
24 	switch (index) {
25 	case SECBOOT_TPMNV_VARS_INDEX:
26 		return &fakenv.vars;
27 	case SECBOOT_TPMNV_CONTROL_INDEX:
28 		return &fakenv.control;
29 	default:
30 		return 0;
31 	}
32 }
33 
34 
tpm_init(void)35 static int tpm_init(void)
36 {
37 	int rc;
38 
39 	if (tpm_ready)
40 		return 0;
41 
42 	rc = flash_secboot_read(&fakenv, fakenv_offset, sizeof(struct fake_tpmnv));
43 	if (rc)
44 		return rc;
45 
46 	tpm_ready = 1;
47 
48 	return 0;
49 }
50 
fakenv_read(TPMI_RH_NV_INDEX nvIndex,void * buf,size_t bufsize,uint16_t off)51 static int fakenv_read(TPMI_RH_NV_INDEX nvIndex, void *buf,
52 		       size_t bufsize,  uint16_t off)
53 {
54 	if (tpm_init())
55 		return OPAL_INTERNAL_ERROR;
56 
57 	memcpy(buf, nv_index_address(nvIndex) + off, bufsize);
58 
59 	return 0;
60 }
61 
fakenv_write(TPMI_RH_NV_INDEX nvIndex,void * buf,size_t bufsize,uint16_t off)62 static int fakenv_write(TPMI_RH_NV_INDEX nvIndex, void *buf,
63 			size_t bufsize, uint16_t off)
64 {
65 	if (tpm_init())
66 		return OPAL_INTERNAL_ERROR;
67 
68 	memcpy(nv_index_address(nvIndex) + off, buf, bufsize);
69 
70 	/* Just write the whole NV struct for now */
71 	return flash_secboot_write(fakenv_offset, &fakenv, sizeof(struct fake_tpmnv));
72 }
73 
fakenv_definespace(TPMI_RH_NV_INDEX nvIndex,uint16_t dataSize)74 static int fakenv_definespace(TPMI_RH_NV_INDEX nvIndex, uint16_t dataSize)
75 {
76 	if (tpm_init())
77 		return OPAL_INTERNAL_ERROR;
78 
79 	(void) dataSize;
80 
81 	switch (nvIndex) {
82 	case SECBOOT_TPMNV_VARS_INDEX:
83 		fakenv.defined[0] = 1;
84 		return 0;
85 	case SECBOOT_TPMNV_CONTROL_INDEX:
86 		fakenv.defined[1] = 1;
87 		return 0;
88 	}
89 
90 	return OPAL_INTERNAL_ERROR;
91 }
92 
fakenv_writelock(TPMI_RH_NV_INDEX nvIndex)93 static int fakenv_writelock(TPMI_RH_NV_INDEX nvIndex)
94 {
95 	if (tpm_init())
96 		return OPAL_INTERNAL_ERROR;
97 
98 	(void) nvIndex;
99 
100 	return 0;
101 }
102 
fakenv_get_defined_indices(TPMI_RH_NV_INDEX ** indices,size_t * count)103 static int fakenv_get_defined_indices(TPMI_RH_NV_INDEX **indices, size_t *count)
104 {
105 	if (tpm_init())
106 		return OPAL_INTERNAL_ERROR;
107 
108 	*indices = zalloc(sizeof(fakenv.defined));
109 	if (*indices == NULL)
110 		return OPAL_NO_MEM;
111 
112 	*count = 0;
113 
114 	if (fakenv.defined[0]) {
115 		*indices[0] = SECBOOT_TPMNV_VARS_INDEX;
116 		(*count)++;
117 	}
118 	if (fakenv.defined[1]) {
119 		*indices[1] = SECBOOT_TPMNV_CONTROL_INDEX;
120 		(*count)++;
121 	}
122 
123 	return 0;
124 }
125 
fakenv_undefinespace(TPMI_RH_NV_INDEX index)126 static int fakenv_undefinespace(TPMI_RH_NV_INDEX index)
127 {
128 	if (tpm_init())
129 		return OPAL_INTERNAL_ERROR;
130 
131 	switch (index) {
132 	case SECBOOT_TPMNV_VARS_INDEX:
133 		fakenv.defined[0] = 0;
134 		memset(&fakenv.vars, 0, sizeof(fakenv.vars));
135 		return 0;
136 	case SECBOOT_TPMNV_CONTROL_INDEX:
137 		fakenv.defined[1] = 0;
138 		memset(&fakenv.control, 0, sizeof(fakenv.control));
139 		return 0;
140 	}
141 
142 	return -1;
143 }
144 
fakenv_readpublic(TPMI_RH_NV_INDEX index,TPMS_NV_PUBLIC * nv_public,TPM2B_NAME * nv_name)145 static int fakenv_readpublic(TPMI_RH_NV_INDEX index, TPMS_NV_PUBLIC *nv_public,
146 			     TPM2B_NAME *nv_name)
147 {
148 	if (tpm_init())
149 		return OPAL_INTERNAL_ERROR;
150 
151 	(void) nv_public;
152 
153 	switch (index) {
154 	case SECBOOT_TPMNV_VARS_INDEX:
155 		memcpy(&nv_name->t.name, tpmnv_vars_name, sizeof(TPM2B_NAME));
156 		break;
157 	case SECBOOT_TPMNV_CONTROL_INDEX:
158 		memcpy(&nv_name->t.name, tpmnv_control_name, sizeof(TPM2B_NAME));
159 		break;
160 	default:
161 		return OPAL_INTERNAL_ERROR;
162 	}
163 
164 	return 0;
165 }
166 
167 struct tpmnv_ops_s tpmnv_ops = {
168 	.read = fakenv_read,
169 	.write = fakenv_write,
170 	.writelock = fakenv_writelock,
171 	.definespace = fakenv_definespace,
172 	.getindices = fakenv_get_defined_indices,
173 	.undefinespace = fakenv_undefinespace,
174 	.readpublic = fakenv_readpublic,
175 };
176