Skip to content

Commit

Permalink
std: Initial bringup for Linux on Thumb2
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
LemonBoy committed May 4, 2021
1 parent 4bf093f commit afbcb62
Show file tree
Hide file tree
Showing 10 changed files with 193 additions and 8 deletions.
2 changes: 1 addition & 1 deletion lib/std/os/bits/linux.zig
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ pub usingnamespace switch (builtin.arch) {
.i386 => @import("linux/i386.zig"),
.x86_64 => @import("linux/x86_64.zig"),
.aarch64 => @import("linux/arm64.zig"),
.arm => @import("linux/arm-eabi.zig"),
.arm, .thumb => @import("linux/arm-eabi.zig"),
.riscv64 => @import("linux/riscv64.zig"),
.sparcv9 => @import("linux/sparc64.zig"),
.mips, .mipsel => @import("linux/mips.zig"),
Expand Down
1 change: 1 addition & 0 deletions lib/std/os/linux.zig
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ pub usingnamespace switch (builtin.arch) {
.x86_64 => @import("linux/x86_64.zig"),
.aarch64 => @import("linux/arm64.zig"),
.arm => @import("linux/arm-eabi.zig"),
.thumb => @import("linux/thumb.zig"),
.riscv64 => @import("linux/riscv64.zig"),
.sparcv9 => @import("linux/sparc64.zig"),
.mips, .mipsel => @import("linux/mips.zig"),
Expand Down
168 changes: 168 additions & 0 deletions lib/std/os/linux/thumb.zig
Original file line number Diff line number Diff line change
@@ -0,0 +1,168 @@
// SPDX-License-Identifier: MIT
// Copyright (c) 2015-2021 Zig Contributors
// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
// The MIT license requires this copyright notice to be included in all copies
// and substantial portions of the software.
usingnamespace @import("../bits.zig");

// The syscall interface is identical to the ARM one but we're facing an extra
// challenge: r7, the register where the syscall number is stored, may be
// reserved for the frame pointer.
// Save and restore r7 around the syscall without touching the stack pointer not
// to break the frame chain.

pub fn syscall0(number: SYS) usize {
@setRuntimeSafety(false);

var buf: [2]usize = .{ @enumToInt(number), undefined };
return asm volatile (
\\ str r7, [%[tmp], #4]
\\ ldr r7, [%[tmp]]
\\ svc #0
\\ ldr r7, [%[tmp], #4]
: [ret] "={r0}" (-> usize)
: [tmp] "{r1}" (buf)
: "memory"
);
}

pub fn syscall1(number: SYS, arg1: usize) usize {
@setRuntimeSafety(false);

var buf: [2]usize = .{ @enumToInt(number), undefined };
return asm volatile (
\\ str r7, [%[tmp], #4]
\\ ldr r7, [%[tmp]]
\\ svc #0
\\ ldr r7, [%[tmp], #4]
: [ret] "={r0}" (-> usize)
: [tmp] "{r1}" (buf),
[arg1] "{r0}" (arg1)
: "memory"
);
}

pub fn syscall2(number: SYS, arg1: usize, arg2: usize) usize {
@setRuntimeSafety(false);

var buf: [2]usize = .{ @enumToInt(number), undefined };
return asm volatile (
\\ str r7, [%[tmp], #4]
\\ ldr r7, [%[tmp]]
\\ svc #0
\\ ldr r7, [%[tmp], #4]
: [ret] "={r0}" (-> usize)
: [tmp] "{r2}" (buf),
[arg1] "{r0}" (arg1),
[arg2] "{r1}" (arg2)
: "memory"
);
}

pub fn syscall3(number: SYS, arg1: usize, arg2: usize, arg3: usize) usize {
@setRuntimeSafety(false);

var buf: [2]usize = .{ @enumToInt(number), undefined };
return asm volatile (
\\ str r7, [%[tmp], #4]
\\ ldr r7, [%[tmp]]
\\ svc #0
\\ ldr r7, [%[tmp], #4]
: [ret] "={r0}" (-> usize)
: [tmp] "{r3}" (buf),
[arg1] "{r0}" (arg1),
[arg2] "{r1}" (arg2),
[arg3] "{r2}" (arg3)
: "memory"
);
}

pub fn syscall4(number: SYS, arg1: usize, arg2: usize, arg3: usize, arg4: usize) usize {
@setRuntimeSafety(false);

var buf: [2]usize = .{ @enumToInt(number), undefined };
return asm volatile (
\\ str r7, [%[tmp], #4]
\\ ldr r7, [%[tmp]]
\\ svc #0
\\ ldr r7, [%[tmp], #4]
: [ret] "={r0}" (-> usize)
: [tmp] "{r4}" (buf),
[arg1] "{r0}" (arg1),
[arg2] "{r1}" (arg2),
[arg3] "{r2}" (arg3),
[arg4] "{r3}" (arg4)
: "memory"
);
}

pub fn syscall5(number: SYS, arg1: usize, arg2: usize, arg3: usize, arg4: usize, arg5: usize) usize {
@setRuntimeSafety(false);

var buf: [2]usize = .{ @enumToInt(number), undefined };
return asm volatile (
\\ str r7, [%[tmp], #4]
\\ ldr r7, [%[tmp]]
\\ svc #0
\\ ldr r7, [%[tmp], #4]
: [ret] "={r0}" (-> usize)
: [tmp] "{r5}" (buf),
[arg1] "{r0}" (arg1),
[arg2] "{r1}" (arg2),
[arg3] "{r2}" (arg3),
[arg4] "{r3}" (arg4),
[arg5] "{r4}" (arg5)
: "memory"
);
}

pub fn syscall6(
number: SYS,
arg1: usize,
arg2: usize,
arg3: usize,
arg4: usize,
arg5: usize,
arg6: usize,
) usize {
@setRuntimeSafety(false);

var buf: [2]usize = .{ @enumToInt(number), undefined };
return asm volatile (
\\ str r7, [%[tmp], #4]
\\ ldr r7, [%[tmp]]
\\ svc #0
\\ ldr r7, [%[tmp], #4]
: [ret] "={r0}" (-> usize)
: [tmp] "{r6}" (buf),
[arg1] "{r0}" (arg1),
[arg2] "{r1}" (arg2),
[arg3] "{r2}" (arg3),
[arg4] "{r3}" (arg4),
[arg5] "{r4}" (arg5),
[arg6] "{r5}" (arg6)
: "memory"
);
}

/// This matches the libc clone function.
pub extern fn clone(func: fn (arg: usize) callconv(.C) u8, stack: usize, flags: u32, arg: usize, ptid: *i32, tls: usize, ctid: *i32) usize;

pub fn restore() callconv(.Naked) void {
return asm volatile (
\\ mov r7, %[number]
\\ svc #0
:
: [number] "I" (@enumToInt(SYS.sigreturn))
);
}

pub fn restore_rt() callconv(.Naked) void {
return asm volatile (
\\ mov r7, %[number]
\\ svc #0
:
: [number] "I" (@enumToInt(SYS.rt_sigreturn))
: "memory"
);
}
6 changes: 3 additions & 3 deletions lib/std/os/linux/tls.zig
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ const TLSVariant = enum {
};

const tls_variant = switch (builtin.arch) {
.arm, .armeb, .aarch64, .aarch64_be, .riscv32, .riscv64, .mips, .mipsel, .powerpc, .powerpc64, .powerpc64le => TLSVariant.VariantI,
.arm, .armeb, .thumb, .aarch64, .aarch64_be, .riscv32, .riscv64, .mips, .mipsel, .powerpc, .powerpc64, .powerpc64le => TLSVariant.VariantI,
.x86_64, .i386, .sparcv9 => TLSVariant.VariantII,
else => @compileError("undefined tls_variant for this architecture"),
};
Expand All @@ -62,7 +62,7 @@ const tls_variant = switch (builtin.arch) {
const tls_tcb_size = switch (builtin.arch) {
// ARM EABI mandates enough space for two pointers: the first one points to
// the DTV while the second one is unspecified but reserved
.arm, .armeb, .aarch64, .aarch64_be => 2 * @sizeOf(usize),
.arm, .armeb, .thumb, .aarch64, .aarch64_be => 2 * @sizeOf(usize),
// One pointer-sized word that points either to the DTV or the TCB itself
else => @sizeOf(usize),
};
Expand Down Expand Up @@ -150,7 +150,7 @@ pub fn setThreadPointer(addr: usize) void {
: [addr] "r" (addr)
);
},
.arm => {
.arm, .thumb => {
const rc = std.os.linux.syscall1(.set_tls, addr);
assert(rc == 0);
},
Expand Down
2 changes: 1 addition & 1 deletion lib/std/special/c.zig
Original file line number Diff line number Diff line change
Expand Up @@ -385,7 +385,7 @@ fn clone() callconv(.Naked) void {
\\ svc #0
);
},
.arm => {
.arm, .thumb => {
// __clone(func, stack, flags, arg, ptid, tls, ctid)
// r0, r1, r2, r3, +0, +4, +8

Expand Down
2 changes: 1 addition & 1 deletion lib/std/start.zig
Original file line number Diff line number Diff line change
Expand Up @@ -176,7 +176,7 @@ fn _start() callconv(.Naked) noreturn {
: [argc] "={esp}" (-> [*]usize)
);
},
.aarch64, .aarch64_be, .arm, .armeb => {
.aarch64, .aarch64_be, .arm, .armeb, .thumb => {
argc_argv_ptr = asm volatile (
\\ mov fp, #0
\\ mov lr, #0
Expand Down
9 changes: 9 additions & 0 deletions lib/std/zig/system.zig
Original file line number Diff line number Diff line change
Expand Up @@ -349,6 +349,15 @@ pub const NativeTargetInfo = struct {
}
}
},
.arm, .armeb => {
// XXX What do we do if the target has the noarm feature?
// What do we do if the user specifies +thumb_mode?
},
.thumb, .thumbeb => {
result.target.cpu.features.addFeature(
@enumToInt(std.Target.arm.Feature.thumb_mode),
);
},
else => {},
}
cross_target.updateCpuFeatures(&result.target.cpu.features);
Expand Down
3 changes: 3 additions & 0 deletions test/stage1/behavior/align.zig
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,7 @@ fn alignedBig() align(16) i32 {
test "@alignCast functions" {
// function alignment is a compile error on wasm32/wasm64
if (builtin.arch == .wasm32 or builtin.arch == .wasm64) return error.SkipZigTest;
if (builtin.arch == .thumb) return error.SkipZigTest;

expect(fnExpectsOnly1(simple4) == 0x19);
}
Expand All @@ -157,6 +158,7 @@ fn simple4() align(4) i32 {
test "generic function with align param" {
// function alignment is a compile error on wasm32/wasm64
if (builtin.arch == .wasm32 or builtin.arch == .wasm64) return error.SkipZigTest;
if (builtin.arch == .thumb) return error.SkipZigTest;

expect(whyWouldYouEverDoThis(1) == 0x1);
expect(whyWouldYouEverDoThis(4) == 0x1);
Expand Down Expand Up @@ -338,6 +340,7 @@ test "align(@alignOf(T)) T does not force resolution of T" {
test "align(N) on functions" {
// function alignment is a compile error on wasm32/wasm64
if (builtin.arch == .wasm32 or builtin.arch == .wasm64) return error.SkipZigTest;
if (builtin.arch == .thumb) return error.SkipZigTest;

expect((@ptrToInt(overaligned_fn) & (0x1000 - 1)) == 0);
}
Expand Down
3 changes: 3 additions & 0 deletions test/stage1/behavior/async_fn.zig
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,9 @@ test "calling an inferred async function" {
}

test "@frameSize" {
if (builtin.arch == .thumb or builtin.arch == .thumbeb)
return error.SkipZigTest;

const S = struct {
fn doTheTest() void {
{
Expand Down
5 changes: 3 additions & 2 deletions test/stage1/behavior/atomics.zig
Original file line number Diff line number Diff line change
Expand Up @@ -149,9 +149,10 @@ fn testAtomicStore() void {
}

test "atomicrmw with floats" {
if (builtin.arch == .aarch64 or builtin.arch == .arm or builtin.arch == .riscv64) {
switch (builtin.arch) {
// https://github.com/ziglang/zig/issues/4457
return error.SkipZigTest;
.aarch64, .arm, .thumb, .riscv64 => return error.SkipZigTest,
else => {},
}
testAtomicRmwFloat();
comptime testAtomicRmwFloat();
Expand Down

0 comments on commit afbcb62

Please sign in to comment.