diff options
author | 2025-03-08 22:04:20 +0800 | |
---|---|---|
committer | 2025-03-08 22:04:20 +0800 | |
commit | a07bb8fd1299070229f0e8f3dcb57ffd5ef9870a (patch) | |
tree | 84f21bd0bf7071bc5fc7dd989e77d7ceb5476682 /arch/mips/tools | |
download | ohosKernel-a07bb8fd1299070229f0e8f3dcb57ffd5ef9870a.tar.gz ohosKernel-a07bb8fd1299070229f0e8f3dcb57ffd5ef9870a.zip |
Initial commit: OpenHarmony-v4.0-ReleaseOpenHarmony-v4.0-Release
Diffstat (limited to 'arch/mips/tools')
-rw-r--r-- | arch/mips/tools/.gitignore | 3 | ||||
-rw-r--r-- | arch/mips/tools/Makefile | 10 | ||||
-rw-r--r-- | arch/mips/tools/elf-entry.c | 103 | ||||
-rwxr-xr-x | arch/mips/tools/generic-board-config.sh | 84 | ||||
-rw-r--r-- | arch/mips/tools/loongson3-llsc-check.c | 309 |
5 files changed, 509 insertions, 0 deletions
diff --git a/arch/mips/tools/.gitignore b/arch/mips/tools/.gitignore new file mode 100644 index 000000000..794817dfb --- /dev/null +++ b/arch/mips/tools/.gitignore | |||
@@ -0,0 +1,3 @@ | |||
1 | # SPDX-License-Identifier: GPL-2.0-only | ||
2 | elf-entry | ||
3 | loongson3-llsc-check | ||
diff --git a/arch/mips/tools/Makefile b/arch/mips/tools/Makefile new file mode 100644 index 000000000..b851e5dcc --- /dev/null +++ b/arch/mips/tools/Makefile | |||
@@ -0,0 +1,10 @@ | |||
1 | # SPDX-License-Identifier: GPL-2.0 | ||
2 | hostprogs := elf-entry | ||
3 | PHONY += elf-entry | ||
4 | elf-entry: $(obj)/elf-entry | ||
5 | @: | ||
6 | |||
7 | hostprogs += loongson3-llsc-check | ||
8 | PHONY += loongson3-llsc-check | ||
9 | loongson3-llsc-check: $(obj)/loongson3-llsc-check | ||
10 | @: | ||
diff --git a/arch/mips/tools/elf-entry.c b/arch/mips/tools/elf-entry.c new file mode 100644 index 000000000..dbd14ff05 --- /dev/null +++ b/arch/mips/tools/elf-entry.c | |||
@@ -0,0 +1,103 @@ | |||
1 | // SPDX-License-Identifier: GPL-2.0 | ||
2 | #include <byteswap.h> | ||
3 | #include <elf.h> | ||
4 | #include <endian.h> | ||
5 | #include <inttypes.h> | ||
6 | #include <stdint.h> | ||
7 | #include <stdio.h> | ||
8 | #include <stdlib.h> | ||
9 | #include <string.h> | ||
10 | |||
11 | #ifdef be32toh | ||
12 | /* If libc provides [bl]e{32,64}toh() then we'll use them */ | ||
13 | #elif BYTE_ORDER == LITTLE_ENDIAN | ||
14 | # define be32toh(x) bswap_32(x) | ||
15 | # define le32toh(x) (x) | ||
16 | # define be64toh(x) bswap_64(x) | ||
17 | # define le64toh(x) (x) | ||
18 | #elif BYTE_ORDER == BIG_ENDIAN | ||
19 | # define be32toh(x) (x) | ||
20 | # define le32toh(x) bswap_32(x) | ||
21 | # define be64toh(x) (x) | ||
22 | # define le64toh(x) bswap_64(x) | ||
23 | #endif | ||
24 | |||
25 | __attribute__((noreturn)) | ||
26 | static void die(const char *msg) | ||
27 | { | ||
28 | fputs(msg, stderr); | ||
29 | exit(EXIT_FAILURE); | ||
30 | } | ||
31 | |||
32 | int main(int argc, const char *argv[]) | ||
33 | { | ||
34 | uint64_t entry; | ||
35 | size_t nread; | ||
36 | FILE *file; | ||
37 | union { | ||
38 | Elf32_Ehdr ehdr32; | ||
39 | Elf64_Ehdr ehdr64; | ||
40 | } hdr; | ||
41 | |||
42 | if (argc != 2) | ||
43 | die("Usage: elf-entry <elf-file>\n"); | ||
44 | |||
45 | file = fopen(argv[1], "r"); | ||
46 | if (!file) { | ||
47 | perror("Unable to open input file"); | ||
48 | return EXIT_FAILURE; | ||
49 | } | ||
50 | |||
51 | nread = fread(&hdr, 1, sizeof(hdr), file); | ||
52 | if (nread != sizeof(hdr)) { | ||
53 | perror("Unable to read input file"); | ||
54 | fclose(file); | ||
55 | return EXIT_FAILURE; | ||
56 | } | ||
57 | |||
58 | if (memcmp(hdr.ehdr32.e_ident, ELFMAG, SELFMAG)) { | ||
59 | fclose(file); | ||
60 | die("Input is not an ELF\n"); | ||
61 | } | ||
62 | |||
63 | switch (hdr.ehdr32.e_ident[EI_CLASS]) { | ||
64 | case ELFCLASS32: | ||
65 | switch (hdr.ehdr32.e_ident[EI_DATA]) { | ||
66 | case ELFDATA2LSB: | ||
67 | entry = le32toh(hdr.ehdr32.e_entry); | ||
68 | break; | ||
69 | case ELFDATA2MSB: | ||
70 | entry = be32toh(hdr.ehdr32.e_entry); | ||
71 | break; | ||
72 | default: | ||
73 | fclose(file); | ||
74 | die("Invalid ELF encoding\n"); | ||
75 | } | ||
76 | |||
77 | /* Sign extend to form a canonical address */ | ||
78 | entry = (int64_t)(int32_t)entry; | ||
79 | break; | ||
80 | |||
81 | case ELFCLASS64: | ||
82 | switch (hdr.ehdr32.e_ident[EI_DATA]) { | ||
83 | case ELFDATA2LSB: | ||
84 | entry = le64toh(hdr.ehdr64.e_entry); | ||
85 | break; | ||
86 | case ELFDATA2MSB: | ||
87 | entry = be64toh(hdr.ehdr64.e_entry); | ||
88 | break; | ||
89 | default: | ||
90 | fclose(file); | ||
91 | die("Invalid ELF encoding\n"); | ||
92 | } | ||
93 | break; | ||
94 | |||
95 | default: | ||
96 | fclose(file); | ||
97 | die("Invalid ELF class\n"); | ||
98 | } | ||
99 | |||
100 | printf("0x%016" PRIx64 "\n", entry); | ||
101 | fclose(file); | ||
102 | return EXIT_SUCCESS; | ||
103 | } | ||
diff --git a/arch/mips/tools/generic-board-config.sh b/arch/mips/tools/generic-board-config.sh new file mode 100755 index 000000000..dfa5f31f5 --- /dev/null +++ b/arch/mips/tools/generic-board-config.sh | |||
@@ -0,0 +1,84 @@ | |||
1 | #!/bin/sh | ||
2 | # SPDX-License-Identifier: GPL-2.0-or-later | ||
3 | # | ||
4 | # Copyright (C) 2017 Imagination Technologies | ||
5 | # Author: Paul Burton <paul.burton@mips.com> | ||
6 | # | ||
7 | # This script merges configuration fragments for boards supported by the | ||
8 | # generic MIPS kernel. It checks each for requirements specified using | ||
9 | # formatted comments, and then calls merge_config.sh to merge those | ||
10 | # fragments which have no unmet requirements. | ||
11 | # | ||
12 | # An example of requirements in your board config fragment might be: | ||
13 | # | ||
14 | # # require CONFIG_CPU_MIPS32_R2=y | ||
15 | # # require CONFIG_CPU_LITTLE_ENDIAN=y | ||
16 | # | ||
17 | # This would mean that your board is only included in kernels which are | ||
18 | # configured for little endian MIPS32r2 CPUs, and not for example in kernels | ||
19 | # configured for 64 bit or big endian systems. | ||
20 | # | ||
21 | |||
22 | srctree="$1" | ||
23 | objtree="$2" | ||
24 | ref_cfg="$3" | ||
25 | cfg="$4" | ||
26 | boards_origin="$5" | ||
27 | shift 5 | ||
28 | |||
29 | # Only print Skipping... lines if the user explicitly specified BOARDS=. In the | ||
30 | # general case it only serves to obscure the useful output about what actually | ||
31 | # was included. | ||
32 | case ${boards_origin} in | ||
33 | "command line") | ||
34 | print_skipped=1 | ||
35 | ;; | ||
36 | environment*) | ||
37 | print_skipped=1 | ||
38 | ;; | ||
39 | *) | ||
40 | print_skipped=0 | ||
41 | ;; | ||
42 | esac | ||
43 | |||
44 | for board in $@; do | ||
45 | board_cfg="${srctree}/arch/mips/configs/generic/board-${board}.config" | ||
46 | if [ ! -f "${board_cfg}" ]; then | ||
47 | echo "WARNING: Board config '${board_cfg}' not found" | ||
48 | continue | ||
49 | fi | ||
50 | |||
51 | # For each line beginning with # require, cut out the field following | ||
52 | # it & search for that in the reference config file. If the requirement | ||
53 | # is not found then the subshell will exit with code 1, and we'll | ||
54 | # continue on to the next board. | ||
55 | grep -E '^# require ' "${board_cfg}" | \ | ||
56 | cut -d' ' -f 3- | \ | ||
57 | while read req; do | ||
58 | case ${req} in | ||
59 | *=y) | ||
60 | # If we require something =y then we check that a line | ||
61 | # containing it is present in the reference config. | ||
62 | grep -Eq "^${req}\$" "${ref_cfg}" && continue | ||
63 | ;; | ||
64 | *=n) | ||
65 | # If we require something =n then we just invert that | ||
66 | # check, considering the requirement met if there isn't | ||
67 | # a line containing the value =y in the reference | ||
68 | # config. | ||
69 | grep -Eq "^${req/%=n/=y}\$" "${ref_cfg}" || continue | ||
70 | ;; | ||
71 | *) | ||
72 | echo "WARNING: Unhandled requirement '${req}'" | ||
73 | ;; | ||
74 | esac | ||
75 | |||
76 | [ ${print_skipped} -eq 1 ] && echo "Skipping ${board_cfg}" | ||
77 | exit 1 | ||
78 | done || continue | ||
79 | |||
80 | # Merge this board config fragment into our final config file | ||
81 | ${srctree}/scripts/kconfig/merge_config.sh \ | ||
82 | -m -O ${objtree} ${cfg} ${board_cfg} \ | ||
83 | | grep -Ev '^(#|Using)' | ||
84 | done | ||
diff --git a/arch/mips/tools/loongson3-llsc-check.c b/arch/mips/tools/loongson3-llsc-check.c new file mode 100644 index 000000000..bdbc7b432 --- /dev/null +++ b/arch/mips/tools/loongson3-llsc-check.c | |||
@@ -0,0 +1,309 @@ | |||
1 | // SPDX-License-Identifier: GPL-2.0-only | ||
2 | #include <byteswap.h> | ||
3 | #include <elf.h> | ||
4 | #include <endian.h> | ||
5 | #include <errno.h> | ||
6 | #include <fcntl.h> | ||
7 | #include <inttypes.h> | ||
8 | #include <stdbool.h> | ||
9 | #include <stdio.h> | ||
10 | #include <stdlib.h> | ||
11 | #include <string.h> | ||
12 | #include <sys/mman.h> | ||
13 | #include <sys/types.h> | ||
14 | #include <sys/stat.h> | ||
15 | #include <unistd.h> | ||
16 | |||
17 | #ifdef be32toh | ||
18 | /* If libc provides le{16,32,64}toh() then we'll use them */ | ||
19 | #elif BYTE_ORDER == LITTLE_ENDIAN | ||
20 | # define le16toh(x) (x) | ||
21 | # define le32toh(x) (x) | ||
22 | # define le64toh(x) (x) | ||
23 | #elif BYTE_ORDER == BIG_ENDIAN | ||
24 | # define le16toh(x) bswap_16(x) | ||
25 | # define le32toh(x) bswap_32(x) | ||
26 | # define le64toh(x) bswap_64(x) | ||
27 | #endif | ||
28 | |||
29 | /* MIPS opcodes, in bits 31:26 of an instruction */ | ||
30 | #define OP_SPECIAL 0x00 | ||
31 | #define OP_REGIMM 0x01 | ||
32 | #define OP_BEQ 0x04 | ||
33 | #define OP_BNE 0x05 | ||
34 | #define OP_BLEZ 0x06 | ||
35 | #define OP_BGTZ 0x07 | ||
36 | #define OP_BEQL 0x14 | ||
37 | #define OP_BNEL 0x15 | ||
38 | #define OP_BLEZL 0x16 | ||
39 | #define OP_BGTZL 0x17 | ||
40 | #define OP_LL 0x30 | ||
41 | #define OP_LLD 0x34 | ||
42 | #define OP_SC 0x38 | ||
43 | #define OP_SCD 0x3c | ||
44 | |||
45 | /* Bits 20:16 of OP_REGIMM instructions */ | ||
46 | #define REGIMM_BLTZ 0x00 | ||
47 | #define REGIMM_BGEZ 0x01 | ||
48 | #define REGIMM_BLTZL 0x02 | ||
49 | #define REGIMM_BGEZL 0x03 | ||
50 | #define REGIMM_BLTZAL 0x10 | ||
51 | #define REGIMM_BGEZAL 0x11 | ||
52 | #define REGIMM_BLTZALL 0x12 | ||
53 | #define REGIMM_BGEZALL 0x13 | ||
54 | |||
55 | /* Bits 5:0 of OP_SPECIAL instructions */ | ||
56 | #define SPECIAL_SYNC 0x0f | ||
57 | |||
58 | static void usage(FILE *f) | ||
59 | { | ||
60 | fprintf(f, "Usage: loongson3-llsc-check /path/to/vmlinux\n"); | ||
61 | } | ||
62 | |||
63 | static int se16(uint16_t x) | ||
64 | { | ||
65 | return (int16_t)x; | ||
66 | } | ||
67 | |||
68 | static bool is_ll(uint32_t insn) | ||
69 | { | ||
70 | switch (insn >> 26) { | ||
71 | case OP_LL: | ||
72 | case OP_LLD: | ||
73 | return true; | ||
74 | |||
75 | default: | ||
76 | return false; | ||
77 | } | ||
78 | } | ||
79 | |||
80 | static bool is_sc(uint32_t insn) | ||
81 | { | ||
82 | switch (insn >> 26) { | ||
83 | case OP_SC: | ||
84 | case OP_SCD: | ||
85 | return true; | ||
86 | |||
87 | default: | ||
88 | return false; | ||
89 | } | ||
90 | } | ||
91 | |||
92 | static bool is_sync(uint32_t insn) | ||
93 | { | ||
94 | /* Bits 31:11 should all be zeroes */ | ||
95 | if (insn >> 11) | ||
96 | return false; | ||
97 | |||
98 | /* Bits 5:0 specify the SYNC special encoding */ | ||
99 | if ((insn & 0x3f) != SPECIAL_SYNC) | ||
100 | return false; | ||
101 | |||
102 | return true; | ||
103 | } | ||
104 | |||
105 | static bool is_branch(uint32_t insn, int *off) | ||
106 | { | ||
107 | switch (insn >> 26) { | ||
108 | case OP_BEQ: | ||
109 | case OP_BEQL: | ||
110 | case OP_BNE: | ||
111 | case OP_BNEL: | ||
112 | case OP_BGTZ: | ||
113 | case OP_BGTZL: | ||
114 | case OP_BLEZ: | ||
115 | case OP_BLEZL: | ||
116 | *off = se16(insn) + 1; | ||
117 | return true; | ||
118 | |||
119 | case OP_REGIMM: | ||
120 | switch ((insn >> 16) & 0x1f) { | ||
121 | case REGIMM_BGEZ: | ||
122 | case REGIMM_BGEZL: | ||
123 | case REGIMM_BGEZAL: | ||
124 | case REGIMM_BGEZALL: | ||
125 | case REGIMM_BLTZ: | ||
126 | case REGIMM_BLTZL: | ||
127 | case REGIMM_BLTZAL: | ||
128 | case REGIMM_BLTZALL: | ||
129 | *off = se16(insn) + 1; | ||
130 | return true; | ||
131 | |||
132 | default: | ||
133 | return false; | ||
134 | } | ||
135 | |||
136 | default: | ||
137 | return false; | ||
138 | } | ||
139 | } | ||
140 | |||
141 | static int check_ll(uint64_t pc, uint32_t *code, size_t sz) | ||
142 | { | ||
143 | ssize_t i, max, sc_pos; | ||
144 | int off; | ||
145 | |||
146 | /* | ||
147 | * Every LL must be preceded by a sync instruction in order to ensure | ||
148 | * that instruction reordering doesn't allow a prior memory access to | ||
149 | * execute after the LL & cause erroneous results. | ||
150 | */ | ||
151 | if (!is_sync(le32toh(code[-1]))) { | ||
152 | fprintf(stderr, "%" PRIx64 ": LL not preceded by sync\n", pc); | ||
153 | return -EINVAL; | ||
154 | } | ||
155 | |||
156 | /* Find the matching SC instruction */ | ||
157 | max = sz / 4; | ||
158 | for (sc_pos = 0; sc_pos < max; sc_pos++) { | ||
159 | if (is_sc(le32toh(code[sc_pos]))) | ||
160 | break; | ||
161 | } | ||
162 | if (sc_pos >= max) { | ||
163 | fprintf(stderr, "%" PRIx64 ": LL has no matching SC\n", pc); | ||
164 | return -EINVAL; | ||
165 | } | ||
166 | |||
167 | /* | ||
168 | * Check branches within the LL/SC loop target sync instructions, | ||
169 | * ensuring that speculative execution can't generate memory accesses | ||
170 | * due to instructions outside of the loop. | ||
171 | */ | ||
172 | for (i = 0; i < sc_pos; i++) { | ||
173 | if (!is_branch(le32toh(code[i]), &off)) | ||
174 | continue; | ||
175 | |||
176 | /* | ||
177 | * If the branch target is within the LL/SC loop then we don't | ||
178 | * need to worry about it. | ||
179 | */ | ||
180 | if ((off >= -i) && (off <= sc_pos)) | ||
181 | continue; | ||
182 | |||
183 | /* If the branch targets a sync instruction we're all good... */ | ||
184 | if (is_sync(le32toh(code[i + off]))) | ||
185 | continue; | ||
186 | |||
187 | /* ...but if not, we have a problem */ | ||
188 | fprintf(stderr, "%" PRIx64 ": Branch target not a sync\n", | ||
189 | pc + (i * 4)); | ||
190 | return -EINVAL; | ||
191 | } | ||
192 | |||
193 | return 0; | ||
194 | } | ||
195 | |||
196 | static int check_code(uint64_t pc, uint32_t *code, size_t sz) | ||
197 | { | ||
198 | int err = 0; | ||
199 | |||
200 | if (sz % 4) { | ||
201 | fprintf(stderr, "%" PRIx64 ": Section size not a multiple of 4\n", | ||
202 | pc); | ||
203 | err = -EINVAL; | ||
204 | sz -= (sz % 4); | ||
205 | } | ||
206 | |||
207 | if (is_ll(le32toh(code[0]))) { | ||
208 | fprintf(stderr, "%" PRIx64 ": First instruction in section is an LL\n", | ||
209 | pc); | ||
210 | err = -EINVAL; | ||
211 | } | ||
212 | |||
213 | #define advance() ( \ | ||
214 | code++, \ | ||
215 | pc += 4, \ | ||
216 | sz -= 4 \ | ||
217 | ) | ||
218 | |||
219 | /* | ||
220 | * Skip the first instructionm allowing check_ll to look backwards | ||
221 | * unconditionally. | ||
222 | */ | ||
223 | advance(); | ||
224 | |||
225 | /* Now scan through the code looking for LL instructions */ | ||
226 | for (; sz; advance()) { | ||
227 | if (is_ll(le32toh(code[0]))) | ||
228 | err |= check_ll(pc, code, sz); | ||
229 | } | ||
230 | |||
231 | return err; | ||
232 | } | ||
233 | |||
234 | int main(int argc, char *argv[]) | ||
235 | { | ||
236 | int vmlinux_fd, status, err, i; | ||
237 | const char *vmlinux_path; | ||
238 | struct stat st; | ||
239 | Elf64_Ehdr *eh; | ||
240 | Elf64_Shdr *sh; | ||
241 | void *vmlinux; | ||
242 | |||
243 | status = EXIT_FAILURE; | ||
244 | |||
245 | if (argc < 2) { | ||
246 | usage(stderr); | ||
247 | goto out_ret; | ||
248 | } | ||
249 | |||
250 | vmlinux_path = argv[1]; | ||
251 | vmlinux_fd = open(vmlinux_path, O_RDONLY); | ||
252 | if (vmlinux_fd == -1) { | ||
253 | perror("Unable to open vmlinux"); | ||
254 | goto out_ret; | ||
255 | } | ||
256 | |||
257 | err = fstat(vmlinux_fd, &st); | ||
258 | if (err) { | ||
259 | perror("Unable to stat vmlinux"); | ||
260 | goto out_close; | ||
261 | } | ||
262 | |||
263 | vmlinux = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, vmlinux_fd, 0); | ||
264 | if (vmlinux == MAP_FAILED) { | ||
265 | perror("Unable to mmap vmlinux"); | ||
266 | goto out_close; | ||
267 | } | ||
268 | |||
269 | eh = vmlinux; | ||
270 | if (memcmp(eh->e_ident, ELFMAG, SELFMAG)) { | ||
271 | fprintf(stderr, "vmlinux is not an ELF?\n"); | ||
272 | goto out_munmap; | ||
273 | } | ||
274 | |||
275 | if (eh->e_ident[EI_CLASS] != ELFCLASS64) { | ||
276 | fprintf(stderr, "vmlinux is not 64b?\n"); | ||
277 | goto out_munmap; | ||
278 | } | ||
279 | |||
280 | if (eh->e_ident[EI_DATA] != ELFDATA2LSB) { | ||
281 | fprintf(stderr, "vmlinux is not little endian?\n"); | ||
282 | goto out_munmap; | ||
283 | } | ||
284 | |||
285 | for (i = 0; i < le16toh(eh->e_shnum); i++) { | ||
286 | sh = vmlinux + le64toh(eh->e_shoff) + (i * le16toh(eh->e_shentsize)); | ||
287 | |||
288 | if (sh->sh_type != SHT_PROGBITS) | ||
289 | continue; | ||
290 | if (!(sh->sh_flags & SHF_EXECINSTR)) | ||
291 | continue; | ||
292 | |||
293 | err = check_code(le64toh(sh->sh_addr), | ||
294 | vmlinux + le64toh(sh->sh_offset), | ||
295 | le64toh(sh->sh_size)); | ||
296 | if (err) | ||
297 | goto out_munmap; | ||
298 | } | ||
299 | |||
300 | status = EXIT_SUCCESS; | ||
301 | out_munmap: | ||
302 | munmap(vmlinux, st.st_size); | ||
303 | out_close: | ||
304 | close(vmlinux_fd); | ||
305 | out_ret: | ||
306 | fprintf(stdout, "loongson3-llsc-check returns %s\n", | ||
307 | status ? "failure" : "success"); | ||
308 | return status; | ||
309 | } | ||