authorgravatar for thatlemon@gmail.comLemonBoy <thatlemon@gmail.com> 2021-05-04 18:52:53+02:00
committergravatar for thatlemon@gmail.comLemonBoy <thatlemon@gmail.com> 2021-05-04 18:52:53+02:00
logafbcb6209dbe6812679324aab564884085b8cf44
treea540fa8c049e94c1e19adfd1e17a85c7e80ca2f6
parent4bf093f1a00e481d923452955ab9c394c30b8694

std: Initial bringup for Linux on Thumb2

There are some small problems here and there, mostly due to the pointers having the lsb set and disrupting the fn alignment tests and the `@FrameSize` implementation.

10 files changed, 193 insertions(+), 8 deletions(-)

lib/std/os/bits/linux.zig+1-1
......@@ -18,7 +18,7 @@ pub usingnamespace switch (builtin.arch) {
1818 .i386 => @import("linux/i386.zig"),
1919 .x86_64 => @import("linux/x86_64.zig"),
2020 .aarch64 => @import("linux/arm64.zig"),
21 .arm => @import("linux/arm-eabi.zig"),
21 .arm, .thumb => @import("linux/arm-eabi.zig"),
2222 .riscv64 => @import("linux/riscv64.zig"),
2323 .sparcv9 => @import("linux/sparc64.zig"),
2424 .mips, .mipsel => @import("linux/mips.zig"),
lib/std/os/linux.zig+1
......@@ -23,6 +23,7 @@ pub usingnamespace switch (builtin.arch) {
2323 .x86_64 => @import("linux/x86_64.zig"),
2424 .aarch64 => @import("linux/arm64.zig"),
2525 .arm => @import("linux/arm-eabi.zig"),
26 .thumb => @import("linux/thumb.zig"),
2627 .riscv64 => @import("linux/riscv64.zig"),
2728 .sparcv9 => @import("linux/sparc64.zig"),
2829 .mips, .mipsel => @import("linux/mips.zig"),
lib/std/os/linux/thumb.zig created+168
......@@ -0,0 +1,168 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2021 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
6usingnamespace @import("../bits.zig");
7
8// The syscall interface is identical to the ARM one but we're facing an extra
9// challenge: r7, the register where the syscall number is stored, may be
10// reserved for the frame pointer.
11// Save and restore r7 around the syscall without touching the stack pointer not
12// to break the frame chain.
13
14pub fn syscall0(number: SYS) usize {
15 @setRuntimeSafety(false);
16
17 var buf: [2]usize = .{ @enumToInt(number), undefined };
18 return asm volatile (
19 \\ str r7, [%[tmp], #4]
20 \\ ldr r7, [%[tmp]]
21 \\ svc #0
22 \\ ldr r7, [%[tmp], #4]
23 : [ret] "={r0}" (-> usize)
24 : [tmp] "{r1}" (buf)
25 : "memory"
26 );
27}
28
29pub fn syscall1(number: SYS, arg1: usize) usize {
30 @setRuntimeSafety(false);
31
32 var buf: [2]usize = .{ @enumToInt(number), undefined };
33 return asm volatile (
34 \\ str r7, [%[tmp], #4]
35 \\ ldr r7, [%[tmp]]
36 \\ svc #0
37 \\ ldr r7, [%[tmp], #4]
38 : [ret] "={r0}" (-> usize)
39 : [tmp] "{r1}" (buf),
40 [arg1] "{r0}" (arg1)
41 : "memory"
42 );
43}
44
45pub fn syscall2(number: SYS, arg1: usize, arg2: usize) usize {
46 @setRuntimeSafety(false);
47
48 var buf: [2]usize = .{ @enumToInt(number), undefined };
49 return asm volatile (
50 \\ str r7, [%[tmp], #4]
51 \\ ldr r7, [%[tmp]]
52 \\ svc #0
53 \\ ldr r7, [%[tmp], #4]
54 : [ret] "={r0}" (-> usize)
55 : [tmp] "{r2}" (buf),
56 [arg1] "{r0}" (arg1),
57 [arg2] "{r1}" (arg2)
58 : "memory"
59 );
60}
61
62pub fn syscall3(number: SYS, arg1: usize, arg2: usize, arg3: usize) usize {
63 @setRuntimeSafety(false);
64
65 var buf: [2]usize = .{ @enumToInt(number), undefined };
66 return asm volatile (
67 \\ str r7, [%[tmp], #4]
68 \\ ldr r7, [%[tmp]]
69 \\ svc #0
70 \\ ldr r7, [%[tmp], #4]
71 : [ret] "={r0}" (-> usize)
72 : [tmp] "{r3}" (buf),
73 [arg1] "{r0}" (arg1),
74 [arg2] "{r1}" (arg2),
75 [arg3] "{r2}" (arg3)
76 : "memory"
77 );
78}
79
80pub fn syscall4(number: SYS, arg1: usize, arg2: usize, arg3: usize, arg4: usize) usize {
81 @setRuntimeSafety(false);
82
83 var buf: [2]usize = .{ @enumToInt(number), undefined };
84 return asm volatile (
85 \\ str r7, [%[tmp], #4]
86 \\ ldr r7, [%[tmp]]
87 \\ svc #0
88 \\ ldr r7, [%[tmp], #4]
89 : [ret] "={r0}" (-> usize)
90 : [tmp] "{r4}" (buf),
91 [arg1] "{r0}" (arg1),
92 [arg2] "{r1}" (arg2),
93 [arg3] "{r2}" (arg3),
94 [arg4] "{r3}" (arg4)
95 : "memory"
96 );
97}
98
99pub fn syscall5(number: SYS, arg1: usize, arg2: usize, arg3: usize, arg4: usize, arg5: usize) usize {
100 @setRuntimeSafety(false);
101
102 var buf: [2]usize = .{ @enumToInt(number), undefined };
103 return asm volatile (
104 \\ str r7, [%[tmp], #4]
105 \\ ldr r7, [%[tmp]]
106 \\ svc #0
107 \\ ldr r7, [%[tmp], #4]
108 : [ret] "={r0}" (-> usize)
109 : [tmp] "{r5}" (buf),
110 [arg1] "{r0}" (arg1),
111 [arg2] "{r1}" (arg2),
112 [arg3] "{r2}" (arg3),
113 [arg4] "{r3}" (arg4),
114 [arg5] "{r4}" (arg5)
115 : "memory"
116 );
117}
118
119pub fn syscall6(
120 number: SYS,
121 arg1: usize,
122 arg2: usize,
123 arg3: usize,
124 arg4: usize,
125 arg5: usize,
126 arg6: usize,
127) usize {
128 @setRuntimeSafety(false);
129
130 var buf: [2]usize = .{ @enumToInt(number), undefined };
131 return asm volatile (
132 \\ str r7, [%[tmp], #4]
133 \\ ldr r7, [%[tmp]]
134 \\ svc #0
135 \\ ldr r7, [%[tmp], #4]
136 : [ret] "={r0}" (-> usize)
137 : [tmp] "{r6}" (buf),
138 [arg1] "{r0}" (arg1),
139 [arg2] "{r1}" (arg2),
140 [arg3] "{r2}" (arg3),
141 [arg4] "{r3}" (arg4),
142 [arg5] "{r4}" (arg5),
143 [arg6] "{r5}" (arg6)
144 : "memory"
145 );
146}
147
148/// This matches the libc clone function.
149pub extern fn clone(func: fn (arg: usize) callconv(.C) u8, stack: usize, flags: u32, arg: usize, ptid: *i32, tls: usize, ctid: *i32) usize;
150
151pub fn restore() callconv(.Naked) void {
152 return asm volatile (
153 \\ mov r7, %[number]
154 \\ svc #0
155 :
156 : [number] "I" (@enumToInt(SYS.sigreturn))
157 );
158}
159
160pub fn restore_rt() callconv(.Naked) void {
161 return asm volatile (
162 \\ mov r7, %[number]
163 \\ svc #0
164 :
165 : [number] "I" (@enumToInt(SYS.rt_sigreturn))
166 : "memory"
167 );
168}
lib/std/os/linux/tls.zig+3-3
......@@ -53,7 +53,7 @@ const TLSVariant = enum {
5353};
5454
5555const tls_variant = switch (builtin.arch) {
56 .arm, .armeb, .aarch64, .aarch64_be, .riscv32, .riscv64, .mips, .mipsel, .powerpc, .powerpc64, .powerpc64le => TLSVariant.VariantI,
56 .arm, .armeb, .thumb, .aarch64, .aarch64_be, .riscv32, .riscv64, .mips, .mipsel, .powerpc, .powerpc64, .powerpc64le => TLSVariant.VariantI,
5757 .x86_64, .i386, .sparcv9 => TLSVariant.VariantII,
5858 else => @compileError("undefined tls_variant for this architecture"),
5959};
......@@ -62,7 +62,7 @@ const tls_variant = switch (builtin.arch) {
6262const tls_tcb_size = switch (builtin.arch) {
6363 // ARM EABI mandates enough space for two pointers: the first one points to
6464 // the DTV while the second one is unspecified but reserved
65 .arm, .armeb, .aarch64, .aarch64_be => 2 * @sizeOf(usize),
65 .arm, .armeb, .thumb, .aarch64, .aarch64_be => 2 * @sizeOf(usize),
6666 // One pointer-sized word that points either to the DTV or the TCB itself
6767 else => @sizeOf(usize),
6868};
......@@ -150,7 +150,7 @@ pub fn setThreadPointer(addr: usize) void {
150150 : [addr] "r" (addr)
151151 );
152152 },
153 .arm => {
153 .arm, .thumb => {
154154 const rc = std.os.linux.syscall1(.set_tls, addr);
155155 assert(rc == 0);
156156 },
lib/std/special/c.zig+1-1
......@@ -385,7 +385,7 @@ fn clone() callconv(.Naked) void {
385385 \\ svc #0
386386 );
387387 },
388 .arm => {
388 .arm, .thumb => {
389389 // __clone(func, stack, flags, arg, ptid, tls, ctid)
390390 // r0, r1, r2, r3, +0, +4, +8
391391
lib/std/start.zig+1-1
......@@ -176,7 +176,7 @@ fn _start() callconv(.Naked) noreturn {
176176 : [argc] "={esp}" (-> [*]usize)
177177 );
178178 },
179 .aarch64, .aarch64_be, .arm, .armeb => {
179 .aarch64, .aarch64_be, .arm, .armeb, .thumb => {
180180 argc_argv_ptr = asm volatile (
181181 \\ mov fp, #0
182182 \\ mov lr, #0
lib/std/zig/system.zig+9
......@@ -349,6 +349,15 @@ pub const NativeTargetInfo = struct {
349349 }
350350 }
351351 },
352 .arm, .armeb => {
353 // XXX What do we do if the target has the noarm feature?
354 // What do we do if the user specifies +thumb_mode?
355 },
356 .thumb, .thumbeb => {
357 result.target.cpu.features.addFeature(
358 @enumToInt(std.Target.arm.Feature.thumb_mode),
359 );
360 },
352361 else => {},
353362 }
354363 cross_target.updateCpuFeatures(&result.target.cpu.features);
test/stage1/behavior/align.zig+3
......@@ -141,6 +141,7 @@ fn alignedBig() align(16) i32 {
141141test "@alignCast functions" {
142142 // function alignment is a compile error on wasm32/wasm64
143143 if (builtin.arch == .wasm32 or builtin.arch == .wasm64) return error.SkipZigTest;
144 if (builtin.arch == .thumb) return error.SkipZigTest;
144145
145146 expect(fnExpectsOnly1(simple4) == 0x19);
146147}
......@@ -157,6 +158,7 @@ fn simple4() align(4) i32 {
157158test "generic function with align param" {
158159 // function alignment is a compile error on wasm32/wasm64
159160 if (builtin.arch == .wasm32 or builtin.arch == .wasm64) return error.SkipZigTest;
161 if (builtin.arch == .thumb) return error.SkipZigTest;
160162
161163 expect(whyWouldYouEverDoThis(1) == 0x1);
162164 expect(whyWouldYouEverDoThis(4) == 0x1);
......@@ -338,6 +340,7 @@ test "align(@alignOf(T)) T does not force resolution of T" {
338340test "align(N) on functions" {
339341 // function alignment is a compile error on wasm32/wasm64
340342 if (builtin.arch == .wasm32 or builtin.arch == .wasm64) return error.SkipZigTest;
343 if (builtin.arch == .thumb) return error.SkipZigTest;
341344
342345 expect((@ptrToInt(overaligned_fn) & (0x1000 - 1)) == 0);
343346}
test/stage1/behavior/async_fn.zig+3
......@@ -110,6 +110,9 @@ test "calling an inferred async function" {
110110}
111111
112112test "@frameSize" {
113 if (builtin.arch == .thumb or builtin.arch == .thumbeb)
114 return error.SkipZigTest;
115
113116 const S = struct {
114117 fn doTheTest() void {
115118 {
test/stage1/behavior/atomics.zig+3-2
......@@ -149,9 +149,10 @@ fn testAtomicStore() void {
149149}
150150
151151test "atomicrmw with floats" {
152 if (builtin.arch == .aarch64 or builtin.arch == .arm or builtin.arch == .riscv64) {
152 switch (builtin.arch) {
153153 // https://github.com/ziglang/zig/issues/4457
154 return error.SkipZigTest;
154 .aarch64, .arm, .thumb, .riscv64 => return error.SkipZigTest,
155 else => {},
155156 }
156157 testAtomicRmwFloat();
157158 comptime testAtomicRmwFloat();