summaryrefslogtreecommitdiff
path: root/src/drivers/smmstore/smi.c
blob: 4f7b4bdac0a4091744c0d84180f4723a3b1efdd1 (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
/* SPDX-License-Identifier: GPL-2.0-only */

#include <console/console.h>
#include <commonlib/region.h>
#include <cpu/x86/smm.h>
#include <smmstore.h>
#include <stddef.h>
#include <stdint.h>

/*
 * Check that the given range is legal.
 *
 * Legal means:
 *  - not pointing into SMRAM
 *
 * returns 0 on success, -1 on failure
 */
static int range_check(void *start, size_t size)
{
	if (smm_points_to_smram(start, size))
		return -1;

	return 0;
}

static uint32_t smmstorev1_exec(uint8_t command, void *param)
{
	uint32_t ret = SMMSTORE_RET_FAILURE;

	switch (command) {
	case SMMSTORE_CMD_READ: {
		printk(BIOS_DEBUG, "Reading from SMM store\n");
		struct smmstore_params_read *params = param;

		if (range_check(params, sizeof(*params)) != 0)
			break;

		if (range_check(params->buf, params->bufsize) != 0)
			break;

		if (smmstore_read_region(params->buf, &params->bufsize) == 0)
			ret = SMMSTORE_RET_SUCCESS;
		break;
	}

	case SMMSTORE_CMD_APPEND: {
		printk(BIOS_DEBUG, "Appending into SMM store\n");
		struct smmstore_params_append *params = param;

		if (range_check(params, sizeof(*params)) != 0)
			break;
		if (range_check(params->key, params->keysize) != 0)
			break;
		if (range_check(params->val, params->valsize) != 0)
			break;

		if (smmstore_append_data(params->key, params->keysize,
					 params->val, params->valsize) == 0)
			ret = SMMSTORE_RET_SUCCESS;
		break;
	}

	case SMMSTORE_CMD_CLEAR: {
		if (smmstore_clear_region() == 0)
			ret = SMMSTORE_RET_SUCCESS;
		break;
	}
	default:
		printk(BIOS_DEBUG,
		       "Unknown SMM store v1 command: 0x%02x\n", command);
		ret = SMMSTORE_RET_UNSUPPORTED;
		break;
	}

	return ret;
}

static uint32_t smmstorev2_exec(uint8_t command, void *param)
{
	uint32_t ret = SMMSTORE_RET_FAILURE;
	static bool initialized = false;

	if (!initialized) {
		uintptr_t base;
		size_t size;
		smm_get_smmstore_com_buffer(&base, &size);

		if (smmstore_init((void *)base, size))
			return SMMSTORE_RET_FAILURE;
		initialized = true;
	}

	switch (command) {
	case SMMSTORE_CMD_RAW_READ: {
		printk(BIOS_DEBUG, "Raw read from SMM store, param = %p\n", param);
		struct smmstore_params_raw_read *params = param;

		if (range_check(params, sizeof(*params)) != 0)
			break;

		if (smmstore_rawread_region(params->block_id, params->bufoffset,
					    params->bufsize) == 0)
			ret = SMMSTORE_RET_SUCCESS;
		break;
	}
	case SMMSTORE_CMD_RAW_WRITE: {
		printk(BIOS_DEBUG, "Raw write to SMM store, param = %p\n", param);
		struct smmstore_params_raw_write *params = param;

		if (range_check(params, sizeof(*params)) != 0)
			break;

		if (smmstore_rawwrite_region(params->block_id, params->bufoffset,
					     params->bufsize) == 0)
			ret = SMMSTORE_RET_SUCCESS;
		break;
	}
	case SMMSTORE_CMD_RAW_CLEAR: {
		printk(BIOS_DEBUG, "Raw clear SMM store, param = %p\n", param);
		struct smmstore_params_raw_clear *params = param;

		if (range_check(params, sizeof(*params)) != 0)
			break;

		if (smmstore_rawclear_region(params->block_id) == 0)
			ret = SMMSTORE_RET_SUCCESS;
		break;
	}
	default:
		printk(BIOS_DEBUG,
			"Unknown SMM store v2 command: 0x%02x\n", command);
		ret = SMMSTORE_RET_UNSUPPORTED;
		break;
	}

	return ret;
}

uint32_t smmstore_exec(uint8_t command, void *param)
{
	if (command != SMMSTORE_CMD_CLEAR && !param)
		return SMMSTORE_RET_FAILURE;

	if (CONFIG(SMMSTORE_V2))
		return smmstorev2_exec(command, param);
	else
		return smmstorev1_exec(command, param);
}