summaryrefslogtreecommitdiff
path: root/src/arch/arm64/include/arch/smc.h
blob: 90cbdcd412c50290ba3162d2e85070dc2b48953a (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
/*
 * This file is part of the coreboot project.
 *
 * Copyright 2014 Google Inc.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; version 2 of the License.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 */

#ifndef __ARCH_SMC_H__
#define __ARCH_SMC_H__

#include <stdint.h>

enum {
	FUNC_ID_CALL_TYPE_SHIFT = 31,
	FUNC_ID_CALL_TYPE_MASK = (1 << FUNC_ID_CALL_TYPE_SHIFT),
	FUNC_ID_FASTCALL = (1 << FUNC_ID_CALL_TYPE_SHIFT),
	FUNC_ID_STDCALL = (0 << FUNC_ID_CALL_TYPE_SHIFT),

	FUNC_ID_CALL_CONVENTION_SHIFT = 30,
	FUNC_ID_CALL_CONVENTION_MASK = (1 << FUNC_ID_CALL_CONVENTION_SHIFT),
	FUNC_ID_SMC32 = (0 << FUNC_ID_CALL_CONVENTION_SHIFT),
	FUNC_ID_SMC64 = (1 << FUNC_ID_CALL_CONVENTION_SHIFT),

	FUNC_ID_ENTITY_SHIFT = 24,
	FUNC_ID_ENTITY_MASK = (0x3f << FUNC_ID_ENTITY_SHIFT),

	FUNC_ID_FUNC_NUMBER_SHIFT = 0,
	FUNC_ID_FUNC_NUMBER_MASK = (0xffff << FUNC_ID_FUNC_NUMBER_SHIFT),

	FUNC_ID_MASK = FUNC_ID_CALL_TYPE_MASK | FUNC_ID_CALL_CONVENTION_MASK |
	               FUNC_ID_ENTITY_MASK | FUNC_ID_FUNC_NUMBER_MASK,

	SMC_NUM_ARGS = 8, /* The last is optional hypervisor id. */
	SMC_NUM_RESULTS = 4,

	SMC_UNKNOWN_FUNC = 0xffffffff,
};

#define SMC_FUNC(entity, number, call_convention, call_type) \
	((call_type) | (call_convention) | \
		((entity) << FUNC_ID_ENTITY_SHIFT) | (number))

#define SMC_FUNC_FAST(entity, number, call_convention) \
	SMC_FUNC((entity), (number), (call_convention), FUNC_ID_FASTCALL)

#define SMC_FUNC_FAST32(entity, number) \
	SMC_FUNC_FAST((entity), (number), FUNC_ID_SMC32)

#define SMC_FUNC_FAST64(entity, number) \
	SMC_FUNC_FAST((entity), (number), FUNC_ID_SMC64)

struct smc_call {
	uint64_t args[SMC_NUM_ARGS];
	uint64_t results[SMC_NUM_RESULTS];
};

/* SMC immediate value needs to be 0. */
/* Check mod AARCHx mode against calling convention. */

static inline uint64_t smc64_arg(const struct smc_call *smc, unsigned i)
{
	return smc->args[i];
}

static inline uint32_t smc32_arg(const struct smc_call *smc, unsigned i)
{
	return smc64_arg(smc, i);
}

static inline void smc64_result(struct smc_call *smc, unsigned i, uint64_t v)
{
	smc->results[i] = v;
}

static inline void smc32_result(struct smc_call *smc, unsigned i, uint32_t v)
{
	uint64_t v64 = v;
	smc64_result(smc, i, v64);
}

static inline void smc32_return(struct smc_call *smc, int32_t v)
{
	smc32_result(smc, 0, v);
}

static inline uint32_t smc_hypervisor_id(const struct smc_call *smc)
{
	/* Set in W7 */
	return smc32_arg(smc, 7);
}

static inline uint32_t smc_session_id(const struct smc_call *smc)
{
	/* Set in W6 */
	return smc32_arg(smc, 6);
}

static inline uint32_t smc_function_id(const struct smc_call *smc)
{
	/* Function ID in W0. */
	return smc32_arg(smc, 0)  & FUNC_ID_MASK;
}

/* Initialize the SMC layer. */
void smc_init(void);

/* Register a handler for a given function range, inclusive. */
int smc_register_range(uint32_t min, uint32_t max, int (*)(struct smc_call *));

#endif /* __ARCH_SMC_H__ */