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) {...@@ -18,7 +18,7 @@ pub usingnamespace switch (builtin.arch) {
18 .i386 => @import("linux/i386.zig"),18 .i386 => @import("linux/i386.zig"),
19 .x86_64 => @import("linux/x86_64.zig"),19 .x86_64 => @import("linux/x86_64.zig"),
20 .aarch64 => @import("linux/arm64.zig"),20 .aarch64 => @import("linux/arm64.zig"),
21 .arm => @import("linux/arm-eabi.zig"),21 .arm, .thumb => @import("linux/arm-eabi.zig"),
22 .riscv64 => @import("linux/riscv64.zig"),22 .riscv64 => @import("linux/riscv64.zig"),
23 .sparcv9 => @import("linux/sparc64.zig"),23 .sparcv9 => @import("linux/sparc64.zig"),
24 .mips, .mipsel => @import("linux/mips.zig"),24 .mips, .mipsel => @import("linux/mips.zig"),
lib/std/os/linux.zig+1
...@@ -23,6 +23,7 @@ pub usingnamespace switch (builtin.arch) {...@@ -23,6 +23,7 @@ pub usingnamespace switch (builtin.arch) {
23 .x86_64 => @import("linux/x86_64.zig"),23 .x86_64 => @import("linux/x86_64.zig"),
24 .aarch64 => @import("linux/arm64.zig"),24 .aarch64 => @import("linux/arm64.zig"),
25 .arm => @import("linux/arm-eabi.zig"),25 .arm => @import("linux/arm-eabi.zig"),
26 .thumb => @import("linux/thumb.zig"),
26 .riscv64 => @import("linux/riscv64.zig"),27 .riscv64 => @import("linux/riscv64.zig"),
27 .sparcv9 => @import("linux/sparc64.zig"),28 .sparcv9 => @import("linux/sparc64.zig"),
28 .mips, .mipsel => @import("linux/mips.zig"),29 .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 {...@@ -53,7 +53,7 @@ const TLSVariant = enum {
53};53};
5454
55const tls_variant = switch (builtin.arch) {55const 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,
57 .x86_64, .i386, .sparcv9 => TLSVariant.VariantII,57 .x86_64, .i386, .sparcv9 => TLSVariant.VariantII,
58 else => @compileError("undefined tls_variant for this architecture"),58 else => @compileError("undefined tls_variant for this architecture"),
59};59};
...@@ -62,7 +62,7 @@ const tls_variant = switch (builtin.arch) {...@@ -62,7 +62,7 @@ const tls_variant = switch (builtin.arch) {
62const tls_tcb_size = switch (builtin.arch) {62const tls_tcb_size = switch (builtin.arch) {
63 // ARM EABI mandates enough space for two pointers: the first one points to63 // ARM EABI mandates enough space for two pointers: the first one points to
64 // the DTV while the second one is unspecified but reserved64 // 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),
66 // One pointer-sized word that points either to the DTV or the TCB itself66 // One pointer-sized word that points either to the DTV or the TCB itself
67 else => @sizeOf(usize),67 else => @sizeOf(usize),
68};68};
...@@ -150,7 +150,7 @@ pub fn setThreadPointer(addr: usize) void {...@@ -150,7 +150,7 @@ pub fn setThreadPointer(addr: usize) void {
150 : [addr] "r" (addr)150 : [addr] "r" (addr)
151 );151 );
152 },152 },
153 .arm => {153 .arm, .thumb => {
154 const rc = std.os.linux.syscall1(.set_tls, addr);154 const rc = std.os.linux.syscall1(.set_tls, addr);
155 assert(rc == 0);155 assert(rc == 0);
156 },156 },
lib/std/special/c.zig+1-1
...@@ -385,7 +385,7 @@ fn clone() callconv(.Naked) void {...@@ -385,7 +385,7 @@ fn clone() callconv(.Naked) void {
385 \\ svc #0385 \\ svc #0
386 );386 );
387 },387 },
388 .arm => {388 .arm, .thumb => {
389 // __clone(func, stack, flags, arg, ptid, tls, ctid)389 // __clone(func, stack, flags, arg, ptid, tls, ctid)
390 // r0, r1, r2, r3, +0, +4, +8390 // r0, r1, r2, r3, +0, +4, +8
391391
lib/std/start.zig+1-1
...@@ -176,7 +176,7 @@ fn _start() callconv(.Naked) noreturn {...@@ -176,7 +176,7 @@ fn _start() callconv(.Naked) noreturn {
176 : [argc] "={esp}" (-> [*]usize)176 : [argc] "={esp}" (-> [*]usize)
177 );177 );
178 },178 },
179 .aarch64, .aarch64_be, .arm, .armeb => {179 .aarch64, .aarch64_be, .arm, .armeb, .thumb => {
180 argc_argv_ptr = asm volatile (180 argc_argv_ptr = asm volatile (
181 \\ mov fp, #0181 \\ mov fp, #0
182 \\ mov lr, #0182 \\ mov lr, #0
lib/std/zig/system.zig+9
...@@ -349,6 +349,15 @@ pub const NativeTargetInfo = struct {...@@ -349,6 +349,15 @@ pub const NativeTargetInfo = struct {
349 }349 }
350 }350 }
351 },351 },
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 },
352 else => {},361 else => {},
353 }362 }
354 cross_target.updateCpuFeatures(&result.target.cpu.features);363 cross_target.updateCpuFeatures(&result.target.cpu.features);
test/stage1/behavior/align.zig+3
...@@ -141,6 +141,7 @@ fn alignedBig() align(16) i32 {...@@ -141,6 +141,7 @@ fn alignedBig() align(16) i32 {
141test "@alignCast functions" {141test "@alignCast functions" {
142 // function alignment is a compile error on wasm32/wasm64142 // function alignment is a compile error on wasm32/wasm64
143 if (builtin.arch == .wasm32 or builtin.arch == .wasm64) return error.SkipZigTest;143 if (builtin.arch == .wasm32 or builtin.arch == .wasm64) return error.SkipZigTest;
144 if (builtin.arch == .thumb) return error.SkipZigTest;
144145
145 expect(fnExpectsOnly1(simple4) == 0x19);146 expect(fnExpectsOnly1(simple4) == 0x19);
146}147}
...@@ -157,6 +158,7 @@ fn simple4() align(4) i32 {...@@ -157,6 +158,7 @@ fn simple4() align(4) i32 {
157test "generic function with align param" {158test "generic function with align param" {
158 // function alignment is a compile error on wasm32/wasm64159 // function alignment is a compile error on wasm32/wasm64
159 if (builtin.arch == .wasm32 or builtin.arch == .wasm64) return error.SkipZigTest;160 if (builtin.arch == .wasm32 or builtin.arch == .wasm64) return error.SkipZigTest;
161 if (builtin.arch == .thumb) return error.SkipZigTest;
160162
161 expect(whyWouldYouEverDoThis(1) == 0x1);163 expect(whyWouldYouEverDoThis(1) == 0x1);
162 expect(whyWouldYouEverDoThis(4) == 0x1);164 expect(whyWouldYouEverDoThis(4) == 0x1);
...@@ -338,6 +340,7 @@ test "align(@alignOf(T)) T does not force resolution of T" {...@@ -338,6 +340,7 @@ test "align(@alignOf(T)) T does not force resolution of T" {
338test "align(N) on functions" {340test "align(N) on functions" {
339 // function alignment is a compile error on wasm32/wasm64341 // function alignment is a compile error on wasm32/wasm64
340 if (builtin.arch == .wasm32 or builtin.arch == .wasm64) return error.SkipZigTest;342 if (builtin.arch == .wasm32 or builtin.arch == .wasm64) return error.SkipZigTest;
343 if (builtin.arch == .thumb) return error.SkipZigTest;
341344
342 expect((@ptrToInt(overaligned_fn) & (0x1000 - 1)) == 0);345 expect((@ptrToInt(overaligned_fn) & (0x1000 - 1)) == 0);
343}346}
test/stage1/behavior/async_fn.zig+3
...@@ -110,6 +110,9 @@ test "calling an inferred async function" {...@@ -110,6 +110,9 @@ test "calling an inferred async function" {
110}110}
111111
112test "@frameSize" {112test "@frameSize" {
113 if (builtin.arch == .thumb or builtin.arch == .thumbeb)
114 return error.SkipZigTest;
115
113 const S = struct {116 const S = struct {
114 fn doTheTest() void {117 fn doTheTest() void {
115 {118 {
test/stage1/behavior/atomics.zig+3-2
...@@ -149,9 +149,10 @@ fn testAtomicStore() void {...@@ -149,9 +149,10 @@ fn testAtomicStore() void {
149}149}
150150
151test "atomicrmw with floats" {151test "atomicrmw with floats" {
152 if (builtin.arch == .aarch64 or builtin.arch == .arm or builtin.arch == .riscv64) {152 switch (builtin.arch) {
153 // https://github.com/ziglang/zig/issues/4457153 // https://github.com/ziglang/zig/issues/4457
154 return error.SkipZigTest;154 .aarch64, .arm, .thumb, .riscv64 => return error.SkipZigTest,
155 else => {},
155 }156 }
156 testAtomicRmwFloat();157 testAtomicRmwFloat();
157 comptime testAtomicRmwFloat();158 comptime testAtomicRmwFloat();