Commit | Line | Data |
---|---|---|
1cac41cb MB |
1 | /* |
2 | * Copyright (c) 2014 Samsung Electronics Co., Ltd. | |
3 | * | |
4 | * This program is free software; you can redistribute it and/or modify | |
5 | * it under the terms of the GNU General Public License as published by | |
6 | * the Free Software Foundation; either version 2 of the License, or | |
7 | * (at your option) any later version. | |
8 | * | |
9 | * This program is distributed in the hope that it will be useful, | |
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
12 | * GNU General Public License for more details. | |
13 | * | |
14 | * You should have received a copy of the GNU General Public License along | |
15 | * with this program; if not, write to the Free Software Foundation, Inc., | |
16 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | |
17 | * | |
18 | */ | |
19 | ||
20 | #include <linux/kernel.h> | |
21 | #include <linux/module.h> | |
22 | #include <linux/types.h> | |
23 | #include <asm/cacheflush.h> | |
24 | #include <asm/irqflags.h> | |
25 | #include <linux/fs.h> | |
26 | #include <asm/tlbflush.h> | |
27 | #include <linux/init.h> | |
28 | #include <asm/io.h> | |
29 | ||
30 | #include <linux/rkp.h> | |
31 | #include <linux/vmm.h> | |
32 | #include "ld.h" | |
33 | ||
34 | #define VMM_32BIT_SMC_CALL_MAGIC 0x82000400 | |
35 | #define VMM_64BIT_SMC_CALL_MAGIC 0xC2000400 | |
36 | ||
37 | #define VMM_STACK_OFFSET 0x2000 | |
38 | ||
39 | #define VMM_MODE_AARCH32 0 | |
40 | #define VMM_MODE_AARCH64 1 | |
41 | ||
42 | struct vmm_elf_info { | |
43 | void *base, *text_head, *bss; //VA only | |
44 | size_t size, text_head_size, bss_size; | |
45 | }; | |
46 | ||
47 | extern char _svmm; | |
48 | extern char _evmm; | |
49 | extern char _vmm_disable; | |
50 | ||
51 | char * __initdata vmm; | |
52 | size_t __initdata vmm_size; | |
53 | ||
54 | int __init vmm_disable(void) | |
55 | { | |
56 | _vmm_goto_EL2(VMM_64BIT_SMC_CALL_MAGIC, (void *)virt_to_phys(&_vmm_disable), | |
57 | VMM_STACK_OFFSET, VMM_MODE_AARCH64, NULL, 0); | |
58 | ||
59 | RKP_LOGA("%s\n", __FUNCTION__); | |
60 | return 0; | |
61 | } | |
62 | ||
63 | int __init vmm_entry(struct vmm_elf_info *vei) | |
64 | { | |
65 | /* | |
66 | * 1. get entry point pa. (.text.head section) | |
67 | * 2. ask el3 to bring us there. | |
68 | */ | |
69 | ||
70 | int status; | |
71 | void *entry = (void *)virt_to_phys(vei->text_head); | |
72 | ||
73 | flush_cache_all(); | |
74 | ||
75 | /* santiy check */ | |
76 | RKP_LOGA("entry point=%p\n", entry); | |
77 | status = _vmm_goto_EL2(VMM_64BIT_SMC_CALL_MAGIC, entry, | |
78 | VMM_STACK_OFFSET, VMM_MODE_AARCH64, | |
79 | (void *)RKP_VMM_START, RKP_VMM_SIZE); | |
80 | ||
81 | RKP_LOGA("status=%d\n", status); | |
82 | return 0; | |
83 | } | |
84 | ||
85 | int __init vmm_init(void) | |
86 | { | |
87 | /* | |
88 | * 1. copy vmm.elf from kimage to reserved area. | |
89 | * 2. wipe out vmm.elf on kimage. | |
90 | * 3. get .bss and .text.head section. | |
91 | * 4. zero out .bss on coped vmm.elf | |
92 | * 5. call vmm_entry | |
93 | */ | |
94 | ||
95 | int ret = 0; | |
96 | struct vmm_elf_info vmm_reserved = { | |
97 | .base = (void *)phys_to_virt(RKP_VMM_START), | |
98 | .size = RKP_VMM_SIZE | |
99 | }; | |
100 | struct vmm_elf_info vmm_kimage = { | |
101 | .base = &_svmm, | |
102 | .size = (size_t)(&_evmm - &_svmm) | |
103 | }; | |
104 | ||
105 | /* copy elf to reserved area and terminate one on kimage */ | |
106 | BUG_ON(vmm_kimage.size > vmm_reserved.size); | |
107 | memcpy(vmm_reserved.base, vmm_kimage.base, vmm_kimage.size); | |
108 | memset(vmm_kimage.base, 0, vmm_kimage.size); | |
109 | ||
110 | /* get .bss and .text.head info*/ | |
111 | if (ld_get_sect(vmm_reserved.base, ".bss", &vmm_reserved.bss, &vmm_reserved.bss_size)) { | |
112 | RKP_LOGA("Can't fine .bss section from vmm_reserved.base=%p\n", | |
113 | vmm_reserved.base); | |
114 | return -1; | |
115 | } | |
116 | ||
117 | if (ld_get_sect(vmm_reserved.base, ".text.head", | |
118 | &vmm_reserved.text_head, &vmm_reserved.text_head_size)) { | |
119 | RKP_LOGA("Can't find .text.head section from vmm_reserved.base=%p\n", | |
120 | vmm_reserved.base); | |
121 | return -1; | |
122 | } | |
123 | ||
124 | /* zero out bss */ | |
125 | memset(vmm_reserved.bss, 0, vmm_reserved.bss_size); | |
126 | ||
127 | /* sanity check */ | |
128 | RKP_LOGA("vmm_reserved\n" | |
129 | " .base=%p .size=%lu\n" | |
130 | " .bss=%p .bss_size=%lu\n" | |
131 | " .text_head=%p .text_head_size=%lu\n", | |
132 | vmm_reserved.base, | |
133 | vmm_reserved.size, | |
134 | vmm_reserved.bss, | |
135 | vmm_reserved.bss_size, | |
136 | vmm_reserved.text_head, | |
137 | vmm_reserved.text_head_size); | |
138 | RKP_LOGA("vmm_kimage\n" | |
139 | ".base=%p .size=%lu\n", | |
140 | vmm_kimage.base, vmm_kimage.size); | |
141 | RKP_LOGA("vmm_start=%x, vmm_size=%lu\n", RKP_VMM_START, RKP_VMM_SIZE); | |
142 | ||
143 | /* jump */ | |
144 | ret = vmm_entry(&vmm_reserved); | |
145 | BUG_ON(ret != 0); | |
146 | ||
147 | return 0; | |
148 | } | |
149 | EXPORT_SYMBOL(vmm_init); |