summaryrefslogtreecommitdiff
path: root/lib/sbi/sbi_hart_protection.c
blob: c4c149c8bd86d0cdcf7a107526de6c86e2a44010 (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
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
/*
 * SPDX-License-Identifier: BSD-2-Clause
 *
 * Copyright (c) 2025 Ventana Micro Systems Inc.
 */

#include <sbi/sbi_console.h>
#include <sbi/sbi_error.h>
#include <sbi/sbi_hart_protection.h>
#include <sbi/sbi_scratch.h>
#include <sbi/sbi_string.h>

static SBI_LIST_HEAD(hart_protection_list);

static struct sbi_hart_protection *__hart_memory_protection_best(void)
{
	struct sbi_hart_protection *pos;

	sbi_list_for_each_entry(pos, &hart_protection_list, head) {
		if (pos->type == SBI_HART_PROTECTION_TYPE_MEMORY)
			return pos;
	}

	return NULL;
}

void sbi_hart_protection_get_str(char *out_str, int out_str_size)
{
	bool memory_protect_done = false;
	struct sbi_hart_protection *pos;
	int offset = 0;

	if (!out_str || out_str_size <= 0)
		return;
	sbi_memset(out_str, 0, out_str_size);

	sbi_list_for_each_entry(pos, &hart_protection_list, head) {
		if (pos->type == SBI_HART_PROTECTION_TYPE_MEMORY) {
			if (memory_protect_done)
				continue;
			memory_protect_done = true;
		}
		sbi_snprintf(out_str + offset, out_str_size - offset, "%s,", pos->name);
		offset = offset + sbi_strlen(pos->name) + 1;
	}

	if (offset)
		out_str[offset - 1] = '\0';
	else
		sbi_strncpy(out_str, "none", out_str_size);
}

int sbi_hart_protection_register(struct sbi_hart_protection *hprot)
{
	struct sbi_hart_protection *pos = NULL;
	bool found_pos = false;

	if (!hprot)
		return SBI_EINVAL;
	if (hprot->type >= SBI_HART_PROTECTION_TYPE_MAX)
		return SBI_EINVAL;

	sbi_list_for_each_entry(pos, &hart_protection_list, head) {
		if (hprot->rating > pos->rating) {
			found_pos = true;
			break;
		}
	}

	if (found_pos)
		sbi_list_add_tail(&hprot->head, &pos->head);
	else
		sbi_list_add_tail(&hprot->head, &hart_protection_list);

	return 0;
}

void sbi_hart_protection_unregister(struct sbi_hart_protection *hprot)
{
	if (!hprot)
		return;

	sbi_list_del(&hprot->head);
}

static int __hart_protection_configure(struct sbi_scratch *scratch,
				       struct sbi_hart_protection *hprot,
				       struct sbi_domain *dom)
{
	if (!hprot)
		return 0;
	if (!hprot->configure)
		return SBI_ENOSYS;

	return hprot->configure(scratch, dom);
}

static void __hart_protection_unconfigure(struct sbi_scratch *scratch,
					  struct sbi_hart_protection *hprot,
					  struct sbi_domain *dom)
{
	if (!hprot || !hprot->unconfigure)
		return;

	hprot->unconfigure(scratch, dom);
}

int sbi_hart_protection_configure(struct sbi_scratch *scratch,
				  struct sbi_domain *dom)
{
	bool do_configure, memory_protect_done = false;
	struct sbi_hart_protection *hprot;
	int ret;

	sbi_list_for_each_entry(hprot, &hart_protection_list, head) {
		do_configure = false;
		switch (hprot->type) {
		case SBI_HART_PROTECTION_TYPE_MEMORY:
			do_configure = !memory_protect_done;
			memory_protect_done = true;
			break;
		case SBI_HART_PROTECTION_TYPE_ID:
			do_configure = true;
			break;
		default:
			break;
		}
		if (!do_configure)
			continue;

		ret = __hart_protection_configure(scratch, hprot, dom);
		if (ret)
			return ret;
	}

	return 0;
}

void sbi_hart_protection_unconfigure(struct sbi_scratch *scratch,
				     struct sbi_domain *dom)
{

	bool do_unconfigure, memory_protect_done = false;
	struct sbi_hart_protection *hprot;

	sbi_list_for_each_entry(hprot, &hart_protection_list, head) {
		do_unconfigure = false;
		switch (hprot->type) {
		case SBI_HART_PROTECTION_TYPE_MEMORY:
			do_unconfigure = !memory_protect_done;
			memory_protect_done = true;
			break;
		case SBI_HART_PROTECTION_TYPE_ID:
			do_unconfigure = true;
			break;
		default:
			break;
		}
		if (!do_unconfigure)
			continue;

		__hart_protection_unconfigure(scratch, hprot, dom);
	}
}

int sbi_hart_protection_reconfigure(struct sbi_scratch *scratch,
				    struct sbi_domain *current_dom,
				    struct sbi_domain *next_dom)
{
	bool do_reconfigure, memory_protect_done = false;
	struct sbi_hart_protection *hprot;
	int ret;

	sbi_list_for_each_entry(hprot, &hart_protection_list, head) {
		do_reconfigure = false;
		switch (hprot->type) {
		case SBI_HART_PROTECTION_TYPE_MEMORY:
			do_reconfigure = !memory_protect_done;
			memory_protect_done = true;
			break;
		case SBI_HART_PROTECTION_TYPE_ID:
			do_reconfigure = true;
			break;
		default:
			break;
		}
		if (!do_reconfigure)
			continue;

		__hart_protection_unconfigure(scratch, hprot, current_dom);
		ret = __hart_protection_configure(scratch, hprot, next_dom);
		if (ret)
			return ret;
	}

	return 0;
}

int sbi_hart_protection_map_range(unsigned long base, unsigned long size)
{
	struct sbi_hart_protection *hprot = __hart_memory_protection_best();

	if (!hprot || !hprot->map_range)
		return 0;

	return hprot->map_range(sbi_scratch_thishart_ptr(), base, size);
}

int sbi_hart_protection_unmap_range(unsigned long base, unsigned long size)
{
	struct sbi_hart_protection *hprot = __hart_memory_protection_best();

	if (!hprot || !hprot->unmap_range)
		return 0;

	return hprot->unmap_range(sbi_scratch_thishart_ptr(), base, size);
}