Zig Inline Assembly

I have this comptime assembly in zig and I want use a externally defined constant variable TRAPFRAME. I keep getting an error that the operand needs to be a 64bit constant. I know the value will be less than 64 bits and the way around is disabling the riscv hints but that requires manipulating the LLVM or clang and you cant do that in zig build

 <inline asm>:22:24: operand must be a constant 64-bit integer
        li         a0, TRAPFRAME

Thanks for the help

export const TRAPFRAME: u64 = 0x6696969;

comptime {
    asm (
        \\        .section   trampsec
        \\        .globl     trampoline
        \\trampoline:
        \\        .align     4
        \\        .globl     uservec
        \\      
        \\uservec:
        \\#
        \\# trap.c sets stvec to point here, so
        \\# traps from user space start here,
        \\# in supervisor mode, but with a
        \\# user page table.
        \\#
        \\
        \\# save user a0 in sscratch so
        \\# a0 can be used to get at TRAPFRAME.
        \\        csrw       sscratch, a0
        \\
        \\# each process has a separate p->trapframe memory area,
        \\# but it's mapped to the same virtual address
        \\# (TRAPFRAME) in every process's user page table.
        \\        li         a0, TRAPFRAME
        \\
        \\# save the user registers in TRAPFRAME
        \\        sd         ra, 40(a0)
        \\        sd         sp, 48(a0)
        \\        sd         gp, 56(a0)
        \\        sd         tp, 64(a0)
        \\        sd         t0, 72(a0)
        \\        sd         t1, 80(a0)
        \\        sd         t2, 88(a0)
        \\        sd         s0, 96(a0)
        \\        sd         s1, 104(a0)
        \\        sd         a1, 120(a0)
        \\        sd         a2, 128(a0)
        \\        sd         a3, 136(a0)
        \\        sd         a4, 144(a0)
        \\        sd         a5, 152(a0)
        \\        sd         a6, 160(a0)
        \\        sd         a7, 168(a0)
        \\        sd         s2, 176(a0)
        \\        sd         s3, 184(a0)
        \\        sd         s4, 192(a0)
        \\        sd         s5, 200(a0)
        \\        sd         s6, 208(a0)
        \\        sd         s7, 216(a0)
        \\        sd         s8, 224(a0)
        \\        sd         s9, 232(a0)
        \\        sd         s10, 240(a0)
        \\        sd         s11, 248(a0)
        \\        sd         t3, 256(a0)
        \\        sd         t4, 264(a0)
        \\        sd         t5, 272(a0)
        \\        sd         t6, 280(a0)
        \\
        \\# save the user a0 in p->trapframe->a0
        \\        csrr       t0, sscratch
        \\        sd         t0, 112(a0)
        \\
        \\# initialize kernel stack pointer, from p->trapframe->kernel_sp
        \\        ld         sp, 8(a0)
        \\
        \\# make tp hold the current hartid, from p->trapframe->kernel_hartid
        \\        ld         tp, 32(a0)
        \\
        \\# load the address of usertrap(), from p->trapframe->kernel_trap
        \\        ld         t0, 16(a0)
        \\
        \\
        \\# fetch the kernel page table address, from p->trapframe->kernel_satp.
        \\        ld         t1, 0(a0)
        \\
        \\# wait for any previous memory operations to complete, so that
        \\# they use the user page table.
        \\        sfence.vma zero, zero
        \\
        \\# install the kernel page table.
        \\        csrw       satp, t1
        \\
        \\# flush now-stale user entries from the TLB.
        \\        sfence.vma zero, zero
        \\
        \\# jump to usertrap(), which does not return
        \\        jr         t0
        \\
        \\        .globl     userret
        \\userret:
        \\# userret(pagetable)
        \\# called by usertrapret() in trap.c to
        \\# switch from kernel to user.
        \\# a0: user page table, for satp.
        \\
        \\# switch to the user page table.
        \\        sfence.vma zero, zero
        \\        csrw       satp, a0
        \\        sfence.vma zero, zero
        \\
        \\        li         a0, TRAPFRAME
        \\
        \\# restore all but a0 from TRAPFRAME
        \\        ld         ra, 40(a0)
        \\        ld         sp, 48(a0)
        \\        ld         gp, 56(a0)
        \\        ld         tp, 64(a0)
        \\        ld         t0, 72(a0)
        \\        ld         t1, 80(a0)
        \\        ld         t2, 88(a0)
        \\        ld         s0, 96(a0)
        \\        ld         s1, 104(a0)
        \\        ld         a1, 120(a0)
        \\        ld         a2, 128(a0)
        \\        ld         a3, 136(a0)
        \\        ld         a4, 144(a0)
        \\        ld         a5, 152(a0)
        \\        ld         a6, 160(a0)
        \\        ld         a7, 168(a0)
        \\        ld         s2, 176(a0)
        \\        ld         s3, 184(a0)
        \\        ld         s4, 192(a0)
        \\        ld         s5, 200(a0)
        \\        ld         s6, 208(a0)
        \\        ld         s7, 216(a0)
        \\        ld         s8, 224(a0)
        \\        ld         s9, 232(a0)
        \\        ld         s10, 240(a0)
        \\        ld         s11, 248(a0)
        \\        ld         t3, 256(a0)
        \\        ld         t4, 264(a0)
        \\        ld         t5, 272(a0)
        \\        ld         t6, 280(a0)
        \\
        \\# restore user a0
        \\        ld         a0, 112(a0)
        \\
        \\# return to user mode and user pc.
        \\# usertrapret() set up sstatus and sepc.
        \\        sret
    );
}

Hello @csirak Welcome to ziggit :slight_smile:

I am guessing that it is mips assembly and that li means load immediate value to a register.
The problem is that I am getting a different error when trying with zig v0.12.0 and the following code:

const TRAPFRAME: u64 = 0x6696969;
export fn mips() void {
    asm volatile (
        \\ li a0, TRAPFRAME
    );
}
error: <inline asm>:1:6: invalid operand for instruction
         li a0, TRAPFRAME
            ^

that error needs a different fix:

const TRAPFRAME: u64 = 0x6696969;
export fn mips() void {
    asm volatile (
        \\ li $a0, TRAPFRAME
    );
}

see: Compiler Explorer

1 Like

this is riscv assembly

Looks like a bug to me.
As a workaround \\ li a0, 0x6696969 is accepted.

yea the issue is that trap frame value is defined at comptime but yea for now that my solution

Yeah also encounter this issue while trying to implement xv6-riscv with zig (0.13.0)

It seems for unknown reason the TRAPFRAME variable is not “expose” to trampoline.S(deleting the assembly line with TRAPFRAME would give the same error), mean while exposing a function can build without error.

Just for people who are also encountering this issue, you can try below tricks to get around this issue

yea i had a static value so i could pass it in