aboutsummaryrefslogtreecommitdiff
path: root/libstb/secvar/storage/fakenv_ops.c
blob: 64d5d51ea2c1302ec3b54110c371aec428be7729 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
// SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
/* Copyright 2020 IBM Corp. */
#include <skiboot.h>
#include "secboot_tpm.h"

/* Offset into the SECBOOT PNOR partition to write "TPMNV" data */
static size_t fakenv_offset = sizeof(struct secboot);

struct fake_tpmnv {
	struct {
		struct secboot_header header;
		char vars[1024]; // Hardcode the size to 1024 for now
	} vars;
	struct tpmnv_control control;
	int defined[2];
} __attribute__((packed));

static struct fake_tpmnv fakenv = {0};
static int tpm_ready = 0;


static inline void *nv_index_address(int index)
{
	switch (index) {
	case SECBOOT_TPMNV_VARS_INDEX:
		return &fakenv.vars;
	case SECBOOT_TPMNV_CONTROL_INDEX:
		return &fakenv.control;
	default:
		return 0;
	}
}


static int tpm_init(void)
{
	int rc;

	if (tpm_ready)
		return 0;

	rc = flash_secboot_read(&fakenv, fakenv_offset, sizeof(struct fake_tpmnv));
	if (rc)
		return rc;

	tpm_ready = 1;

	return 0;
}

static int fakenv_read(TPMI_RH_NV_INDEX nvIndex, void *buf,
		       size_t bufsize,  uint16_t off)
{
	if (tpm_init())
		return OPAL_INTERNAL_ERROR;

	memcpy(buf, nv_index_address(nvIndex) + off, bufsize);

	return 0;
}

static int fakenv_write(TPMI_RH_NV_INDEX nvIndex, void *buf,
			size_t bufsize, uint16_t off)
{
	if (tpm_init())
		return OPAL_INTERNAL_ERROR;

	memcpy(nv_index_address(nvIndex) + off, buf, bufsize);

	/* Just write the whole NV struct for now */
	return flash_secboot_write(fakenv_offset, &fakenv, sizeof(struct fake_tpmnv));
}

static int fakenv_definespace(TPMI_RH_NV_INDEX nvIndex, uint16_t dataSize)
{
	if (tpm_init())
		return OPAL_INTERNAL_ERROR;

	(void) dataSize;

	switch (nvIndex) {
	case SECBOOT_TPMNV_VARS_INDEX:
		fakenv.defined[0] = 1;
		return 0;
	case SECBOOT_TPMNV_CONTROL_INDEX:
		fakenv.defined[1] = 1;
		return 0;
	}

	return OPAL_INTERNAL_ERROR;
}

static int fakenv_writelock(TPMI_RH_NV_INDEX nvIndex)
{
	if (tpm_init())
		return OPAL_INTERNAL_ERROR;

	(void) nvIndex;

	return 0;
}

static int fakenv_get_defined_indices(TPMI_RH_NV_INDEX **indices, size_t *count)
{
	if (tpm_init())
		return OPAL_INTERNAL_ERROR;

	*indices = zalloc(sizeof(fakenv.defined));
	if (*indices == NULL)
		return OPAL_NO_MEM;

	*count = 0;

	if (fakenv.defined[0]) {
		*indices[0] = SECBOOT_TPMNV_VARS_INDEX;
		(*count)++;
	}
	if (fakenv.defined[1]) {
		*indices[1] = SECBOOT_TPMNV_CONTROL_INDEX;
		(*count)++;
	}

	return 0;
}

static int fakenv_undefinespace(TPMI_RH_NV_INDEX index)
{
	if (tpm_init())
		return OPAL_INTERNAL_ERROR;

	switch (index) {
	case SECBOOT_TPMNV_VARS_INDEX:
		fakenv.defined[0] = 0;
		memset(&fakenv.vars, 0, sizeof(fakenv.vars));
		return 0;
	case SECBOOT_TPMNV_CONTROL_INDEX:
		fakenv.defined[1] = 0;
		memset(&fakenv.control, 0, sizeof(fakenv.control));
		return 0;
	}

	return -1;
}

static int fakenv_readpublic(TPMI_RH_NV_INDEX index, TPMS_NV_PUBLIC *nv_public,
			     TPM2B_NAME *nv_name)
{
	if (tpm_init())
		return OPAL_INTERNAL_ERROR;

	(void) nv_public;

	switch (index) {
	case SECBOOT_TPMNV_VARS_INDEX:
		memcpy(&nv_name->t.name, tpmnv_vars_name, sizeof(TPM2B_NAME));
		break;
	case SECBOOT_TPMNV_CONTROL_INDEX:
		memcpy(&nv_name->t.name, tpmnv_control_name, sizeof(TPM2B_NAME));
		break;
	default:
		return OPAL_INTERNAL_ERROR;
	}

	return 0;
}

struct tpmnv_ops_s tpmnv_ops = {
	.read = fakenv_read,
	.write = fakenv_write,
	.writelock = fakenv_writelock,
	.definespace = fakenv_definespace,
	.getindices = fakenv_get_defined_indices,
	.undefinespace = fakenv_undefinespace,
	.readpublic = fakenv_readpublic,
};