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__ */
|