aboutsummaryrefslogtreecommitdiffstats
path: root/arch/mips/tools
diff options
context:
space:
mode:
authorWe-unite <3205135446@qq.com>2025-03-08 22:04:20 +0800
committerWe-unite <3205135446@qq.com>2025-03-08 22:04:20 +0800
commita07bb8fd1299070229f0e8f3dcb57ffd5ef9870a (patch)
tree84f21bd0bf7071bc5fc7dd989e77d7ceb5476682 /arch/mips/tools
downloadohosKernel-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/.gitignore3
-rw-r--r--arch/mips/tools/Makefile10
-rw-r--r--arch/mips/tools/elf-entry.c103
-rwxr-xr-xarch/mips/tools/generic-board-config.sh84
-rw-r--r--arch/mips/tools/loongson3-llsc-check.c309
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
2elf-entry
3loongson3-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
2hostprogs := elf-entry
3PHONY += elf-entry
4elf-entry: $(obj)/elf-entry
5 @:
6
7hostprogs += loongson3-llsc-check
8PHONY += loongson3-llsc-check
9loongson3-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))
26static void die(const char *msg)
27{
28 fputs(msg, stderr);
29 exit(EXIT_FAILURE);
30}
31
32int 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
22srctree="$1"
23objtree="$2"
24ref_cfg="$3"
25cfg="$4"
26boards_origin="$5"
27shift 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.
32case ${boards_origin} in
33"command line")
34 print_skipped=1
35 ;;
36environment*)
37 print_skipped=1
38 ;;
39*)
40 print_skipped=0
41 ;;
42esac
43
44for 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)'
84done
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
58static void usage(FILE *f)
59{
60 fprintf(f, "Usage: loongson3-llsc-check /path/to/vmlinux\n");
61}
62
63static int se16(uint16_t x)
64{
65 return (int16_t)x;
66}
67
68static 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
80static 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
92static 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
105static 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
141static 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
196static 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
234int 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;
301out_munmap:
302 munmap(vmlinux, st.st_size);
303out_close:
304 close(vmlinux_fd);
305out_ret:
306 fprintf(stdout, "loongson3-llsc-check returns %s\n",
307 status ? "failure" : "success");
308 return status;
309}