trusty-mem.c
3.08 KB
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
/*
* Copyright (C) 2015 Google, Inc.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* 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.
*
*/
#include <linux/types.h>
#include <linux/printk.h>
#include <linux/trusty/trusty.h>
#include <linux/trusty/smcall.h>
static int get_mem_attr(struct page *page, pgprot_t pgprot)
{
#if defined(CONFIG_ARM64)
uint64_t mair;
uint attr_index = (pgprot_val(pgprot) & PTE_ATTRINDX_MASK) >> 2;
asm ("mrs %0, mair_el1\n" : "=&r" (mair));
return (mair >> (attr_index * 8)) & 0xff;
#elif defined(CONFIG_ARM_LPAE)
uint32_t mair;
uint attr_index = ((pgprot_val(pgprot) & L_PTE_MT_MASK) >> 2);
if (attr_index >= 4) {
attr_index -= 4;
asm volatile("mrc p15, 0, %0, c10, c2, 1\n" : "=&r" (mair));
} else {
asm volatile("mrc p15, 0, %0, c10, c2, 0\n" : "=&r" (mair));
}
return (mair >> (attr_index * 8)) & 0xff;
#elif defined(CONFIG_ARM)
/* check memory type */
switch (pgprot_val(pgprot) & L_PTE_MT_MASK) {
case L_PTE_MT_WRITEALLOC:
/* Normal: write back write allocate */
return 0xFF;
case L_PTE_MT_BUFFERABLE:
/* Normal: non-cacheble */
return 0x44;
case L_PTE_MT_WRITEBACK:
/* Normal: writeback, read allocate */
return 0xEE;
case L_PTE_MT_WRITETHROUGH:
/* Normal: write through */
return 0xAA;
case L_PTE_MT_UNCACHED:
/* strongly ordered */
return 0x00;
case L_PTE_MT_DEV_SHARED:
case L_PTE_MT_DEV_NONSHARED:
/* device */
return 0x04;
default:
return -EINVAL;
}
#else
return 0;
#endif
}
int trusty_encode_page_info(struct ns_mem_page_info *inf,
struct page *page, pgprot_t pgprot)
{
int mem_attr;
uint64_t pte;
if (!inf || !page)
return -EINVAL;
/* get physical address */
pte = (uint64_t) page_to_phys(page);
/* get memory attributes */
mem_attr = get_mem_attr(page, pgprot);
if (mem_attr < 0)
return mem_attr;
/* add other attributes */
#if defined(CONFIG_ARM64) || defined(CONFIG_ARM_LPAE)
pte |= pgprot_val(pgprot);
#elif defined(CONFIG_ARM)
if (pgprot_val(pgprot) & L_PTE_USER)
pte |= (1 << 6);
if (pgprot_val(pgprot) & L_PTE_RDONLY)
pte |= (1 << 7);
if (pgprot_val(pgprot) & L_PTE_SHARED)
pte |= (3 << 8); /* inner sharable */
#endif
inf->attr = (pte & 0x0000FFFFFFFFFFFFull) | ((uint64_t)mem_attr << 48);
return 0;
}
int trusty_call32_mem_buf(struct device *dev, u32 smcnr,
struct page *page, u32 size,
pgprot_t pgprot)
{
int ret;
struct ns_mem_page_info pg_inf;
if (!dev || !page)
return -EINVAL;
ret = trusty_encode_page_info(&pg_inf, page, pgprot);
if (ret)
return ret;
if (SMC_IS_FASTCALL(smcnr)) {
return trusty_fast_call32(dev, smcnr,
(u32)pg_inf.attr,
(u32)(pg_inf.attr >> 32), size);
} else {
return trusty_std_call32(dev, smcnr,
(u32)pg_inf.attr,
(u32)(pg_inf.attr >> 32), size);
}
}