De-x86-ify IncludeOS for upcoming ARM support

#2352 · open · 2 comments

View on GitHub ↗

torgeiru

Lots of the code assumes x86 for example PCI driver code (port IO) and there are many `asm volatile`. I think we should switch from these to intrinsics and C++-standard. I must probably help with PCI driver code. Here is a comprehensive references of assembly instructions: ```log api/smp_utils: asm("mfence"); api/smp_utils: asm("pause; nop;"); api/debug: asm("mov $0,%eax ; 0: ; test %eax,%eax ; jz 0b"); } api/smp: asm("movl %%gs:(0x0), %0" : "=r" (cpuid)); api/smp: asm("movl %%fs:(0x0), %0" : "=r" (cpuid)); api/arch/x86_64.hpp: asm("rdtsc" : "=a"(lo), "=d"(hi)); api/arch/i686.hpp: asm("rdtsc" : "=A" (ret)); lib/LiveUpdate/src/hotswap.cpp:asm(".org 0x8000"); test/integration/mod/gsl/service.cpp: THEN("span saves us from complete embarrasment") { test/integration/stl/coroutines/service.cpp: asm("pause"); test/integration/kernel/fiber/fiber_smp.cpp: asm("pause"); test/integration/kernel/fiber/fiber_smp.cpp: asm("pause"); test/integration/kernel/fiber/fiber_smp.cpp: asm("pause"); test/integration/kernel/fiber/fiber_smp.cpp: asm("hlt"); test/integration/kernel/fiber/fiber_smp.cpp: asm("pause"); test/integration/kernel/fiber/fiber_smp.cpp: asm("pause"); test/integration/kernel/fiber/fiber_smp.cpp: asm("pause"); test/integration/kernel/exception/service.cpp: //asm ("movl $0, %eax"); test/integration/kernel/exception/service.cpp: //asm ("idivl %eax"); test/integration/kernel/exception/service.cpp: asm ("movq $0, %rax"); test/integration/kernel/exception/service.cpp: asm ("idivq %rax"); src/platform/x86_nano/platform.cpp: while (1) asm("cli; hlt;"); src/platform/x86_nano/platform.cpp: asm("hlt"); src/platform/x86_pc/init_libc.hpp:#define LL_ASSERT(X) if (!(X)) { kprint("Early assertion failed: " #X "\n"); asm("cli;hlt"); } src/platform/x86_pc/boot/bootloader.asm: %include "boot/disk_read_lba.asm" src/platform/x86_pc/smp.cpp: asm("movl %%gs:(0x0), %0" : "=r" (cpuid)); src/platform/x86_pc/smp.cpp: asm("movl %%fs:(0x0), %0" : "=r" (cpuid)); src/platform/x86_pc/acpi.cpp: asm("cli"); src/platform/x86_pc/acpi.cpp: while (true) asm ("cli; hlt"); src/platform/x86_pc/start.asm: db `Panic: OS returned to x86 start.asm. Halting\n`,0x0 src/platform/x86_pc/pit.cpp: asm("hlt"); src/platform/x86_pc/idt.cpp: asm ("sgdtq %0" : : "m" (* &gdt)); src/platform/x86_pc/idt.cpp: asm ("sidtq %0" : : "m" (* &idt)); src/platform/aarch64_vm/init_libc.hpp:#define LL_ASSERT(X) if (!(X)) { kprint("Early assertion failed: " #X "\n"); asm("hlt 0xf000"); } src/platform/aarch64_vm/platform.cpp:// while (1) asm("hlt #0xf000;"); src/platform/aarch64_vm/serial1.cpp: /* init UART (38400 8N1) */ //maybe stick in asm as a function instead src/platform/aarch64_vm/serial1.cpp: //unsure if this becomes sane or not. look at asm but should be exactly the same as the above comment src/platform/aarch64_vm/start_aarch64.asm://exception.asm src/platform/aarch64_vm/start.asm: db `Panic: OS returned to x86 start.asm. Halting\n`,0x0 src/platform/kvm/kvmclock.cpp: asm("mfence" ::: "memory"); src/platform/kvm/kvmclock.cpp: asm("mfence" ::: "memory"); src/platform/kvm/kvmclock.cpp: asm("mfence" ::: "memory"); src/platform/kvm/kvmclock.cpp: asm("mfence" ::: "memory"); src/platform/kvm/pv_eoi.cpp: asm("btr %2, %0; setc %1" : "+m"(PER_CPU(exitless_eoi).eoi_word), "=rm"(reg) : "r"(0)); src/platform/kvm/bsd_pvclock.hpp: __asm__ ( src/platform/kvm/bsd_pvclock.hpp: __asm__ ( src/chainload/service.cpp: asm("cli"); src/chainload/hotswap.cpp:asm(".org 0x2000"); src/drivers/vga_emergency.cpp: asm("sti"); src/drivers/e1000.cpp: asm("pause"); src/drivers/e1000.cpp: asm("pause"); src/drivers/ide.cpp: while (((ret = hw::inb(IDE_STATUS)) & IDE_BUSY) == IDE_BUSY) asm("pause"); api/smp_utils: asm volatile("mfence"); api/hw/pci.hpp: asm volatile("inb %1,%0" : "=a"(ret) : "Nd"(port)); api/hw/pci.hpp: asm volatile("inw %1,%0" : "=a"(ret) : "Nd"(port)); api/hw/pci.hpp: asm volatile("inl %1,%0" : "=a"(ret) : "Nd"(port)); api/hw/pci.hpp: asm volatile ("outb %0,%1" :: "a"(data), "Nd"(port)); api/hw/pci.hpp: asm volatile ("outw %0,%1" :: "a" (data), "Nd"(port)); api/hw/pci.hpp: asm volatile ("outl %0,%1" :: "a" (data), "Nd"(port)); api/hw/ioport.hpp: asm volatile("inb %1,%0" : "=a"(ret) : "Nd"(port)); api/hw/ioport.hpp: asm volatile("inw %1,%0" : "=a"(ret) : "Nd"(port)); api/hw/ioport.hpp: asm volatile("inl %1,%0" : "=a"(ret) : "Nd"(port)); api/hw/ioport.hpp: asm volatile ("outb %0,%1" :: "a"(data), "Nd"(port)); api/hw/ioport.hpp: asm volatile ("outw %0,%1" :: "a" (data), "Nd"(port)); api/hw/ioport.hpp: asm volatile ("outl %0,%1" :: "a" (data), "Nd"(port)); api/arch/x86_64.hpp: __asm volatile("lfence" ::: "memory"); api/arch/x86_64.hpp: __asm volatile("mfence" ::: "memory"); api/arch/aarch64.hpp: asm volatile("isb;mrs %0, pmccntr_el0" : "=r"(ret)); api/arch/x86/cpu.hpp: asm volatile ( api/arch/x86/cpu.hpp: asm volatile("rdmsr" : "=A" (v) : "c" (addr)); api/arch/x86/cpu.hpp: asm volatile("wrmsr" : : "a" (eax), "d"(edx), "c" (addr)); api/arch/x86/cpu.hpp: asm volatile("wrmsr" : : "a" (eax), "d"(edx), "c" (addr)); api/arch/x86/cpu.hpp: asm volatile("wrmsr" : : "A" (value), "c" (addr)); api/arch/x86/gdt.hpp: asm volatile("movw %%ax, %%fs" : : "a"(entry * 0x8)); api/arch/x86/gdt.hpp: asm volatile("movw %%ax, %%gs" : : "a"(entry * 0x8)); api/arch/i686.hpp: __asm volatile("lfence" ::: "memory"); api/arch/i686.hpp: __asm volatile("mfence" ::: "memory"); api/arch.hpp: asm volatile("" ::: "memory"); lib/LiveUpdate/src/update.cpp: asm volatile("cli"); lib/LiveUpdate/src/update.cpp: asm volatile("sti"); lib/LiveUpdate/src/hotswap.cpp: asm volatile("jmp *%2" : : "a" (SOFT_RESET_MAGIC), "b" (reset_data), "c" (start)); lib/LiveUpdate/src/hotswap.cpp: asm volatile( test/integration/kernel/fiber/service.cpp: asm volatile ("mov %%rsp, %0" :"=r"(stack)); test/integration/kernel/fiber/service.cpp: asm volatile ("mov %%esp, %0" :"=r"(stack)); test/integration/kernel/fiber/service.cpp: asm volatile ("mov %%rbp, %0" :"=r"(base)); test/integration/kernel/fiber/service.cpp: asm volatile ("mov %%ebp, %0" :"=r"(base)); test/integration/kernel/fiber/fiber_smp.cpp: asm volatile ("mov %%rsp, %0" :"=r"(stack)); test/integration/kernel/fiber/fiber_smp.cpp: asm volatile ("mov %%esp, %0" :"=r"(stack)); test/integration/util/tar/tar_example/l1_f2/virtio.hpp: asm volatile("mfence" ::: "memory"); test/integration/util/tar_gz/tar_example/l1_f2/virtio.hpp: asm volatile("mfence" ::: "memory"); src/platform/x86_pc/os.cpp: asm volatile("hlt"); src/platform/x86_pc/os.cpp: asm volatile( src/platform/x86_pc/platform.cpp: asm volatile("sti"); src/platform/x86_pc/rand.cpp: asm volatile("cpuid" ::: "memory", "eax", "ebx", "ecx", "edx"); src/platform/x86_pc/apic_revenant.cpp: asm volatile("sti"); src/platform/x86_pc/idt.cpp: asm volatile ("lidt %0" : : "m"(idt_reg)); src/platform/x86_solo5/os.cpp: asm volatile( src/platform/x86_solo5/os.cpp: asm volatile("hlt"); src/platform/x86_solo5/platform.cpp: asm volatile("cli; hlt"); src/platform/aarch64_vm/os.cpp: asm volatile("wfi" :::"memory"); src/platform/aarch64_vm/os.cpp: //asm volatile("hlt #0xf000"); src/platform/aarch64_vm/os.cpp: asm volatile( src/platform/aarch64_vm/serial1.cpp: /*asm volatile("ldr x4, =%0" :: "r"(UART_BASE)); // UART base src/platform/aarch64_vm/serial1.cpp: asm volatile("mov w5, #0x10"); src/platform/aarch64_vm/serial1.cpp: asm volatile("str w5, [x4, #0x24]"); src/platform/aarch64_vm/serial1.cpp: asm volatile("mov w5, #0xc300"); src/platform/aarch64_vm/serial1.cpp: asm volatile("orr w5, w5, #0x0001"); src/platform/aarch64_vm/serial1.cpp: asm volatile("str w5, [x4, #0x30]");*/ src/chainload/hotswap.cpp: asm volatile("jmp *%0" : : "r" (start), "a" (magic), "b" (bootinfo)); src/chainload/hotswap.cpp: asm volatile (".global __hotswap_end;\n__hotswap_end:"); src/kernel/cpuid.cpp: asm volatile ("cpuid" src/kernel/scoped_profiler.cpp: asm volatile ("lfence\n\t" src/kernel/scoped_profiler.cpp: asm volatile ("mfence\n\t" src/kernel/scoped_profiler.cpp: asm volatile ("lfence\n\t" src/kernel/scoped_profiler.cpp: asm volatile ("mfence\n\t" src/arch/aarch64/cpu.cpp: asm volatile("mrs %0, CurrentEL": "=r" (el)::); src/arch/aarch64/cpu.cpp: asm volatile("msr DAIFClr,%0" ::"i"(DAIF_FIQ_BIT): "memory"); src/arch/aarch64/cpu.cpp: asm volatile("msr DAIFClr,%0" ::"i"(DAIF_IRQ_BIT) : "memory"); src/arch/aarch64/cpu.cpp: asm volatile("msr DAIFClr,%0" ::"i"(DAIF_ABT_BIT) : "memory"); src/arch/aarch64/cpu.cpp: asm volatile("msr DAIFClr,%0" ::"i"(DAIF_DBG_BIT): "memory"); src/arch/aarch64/cpu.cpp: asm volatile("msr DAIFSet,%0" ::"i"(DAIF_FIQ_BIT): "memory"); src/arch/aarch64/cpu.cpp: asm volatile("msr DAIFSet,%0" ::"i"(DAIF_IRQ_BIT) : "memory"); src/arch/aarch64/cpu.cpp: asm volatile("msr DAIFSet,%0" ::"i"(DAIF_ABT_BIT) : "memory"); src/arch/aarch64/cpu.cpp: asm volatile("msr DAIFSet,%0" ::"i"(DAIF_DBG_BIT): "memory"); src/arch/aarch64/cpu.cpp: asm volatile("msr DAIFSet,%0" :: "i"(DAIF_FIQ_BIT|DAIF_IRQ_BIT|DAIF_ABT_BIT|DAIF_DBG_BIT) : "memory"); src/arch/aarch64/cpu.cpp: asm volatile("wfi" : : : "memory"); src/arch/aarch64/cpu.cpp: asm volatile("mrs %0 , DAIF" : "=r"(daif)::"memory"); src/arch/aarch64/cpu.cpp: asm volatile("msr DAIF, %0 " : :"r"(daif):"memory"); src/arch/aarch64/cpu.cpp: //asm volatile("msr daifset, %0\n\t" :: "r"(irq):"memory"); src/arch/aarch64/cpu.cpp: asm volatile("mrs %0 , DAIF" : "=r"(daif)::"memory"); src/arch/aarch64/cpu.cpp: asm volatile("msr DAIF, %0" : :"r"(daif):"memory"); src/arch/aarch64/timer.cpp: asm volatile ("msr cntfrq_el0, %0" :: "r"(freq)); src/arch/aarch64/timer.cpp: asm volatile ("mrs %0, cntfrq_el0" : "=r"(ret)); src/arch/aarch64/timer.cpp: asm volatile ("msr cntp_tval_el0, %0" :: "r"(count)); src/arch/aarch64/timer.cpp: asm volatile("mrs %0, cntvct_el0" : "=r" (cntvct_el0) : : "memory"); src/arch/aarch64/timer.cpp: asm volatile("mrs %0, cntv_cval_el0" : "=r" (cntvct_el0) : : "memory"); src/arch/aarch64/timer.cpp: asm volatile("msr cntv_cval_el0 , %0" :: "r" (compare) : "memory"); src/arch/aarch64/timer.cpp: asm volatile("msr cntv_ctl_el0 , %0" :: "r" (val) : "memory"); src/arch/aarch64/timer.cpp: asm volatile("mrs %0, cntv_ctl_el0" : "=r" (ctl) : : "memory"); src/arch/aarch64/timer.cpp: asm volatile ("mrs %0, cntp_tval_el0" : "=r"(ret)); src/arch/aarch64/timer.cpp: asm volatile("msr cntp_ctl_el0, %0" :: "r"(control): "memory"); src/arch/aarch64/timer.cpp: asm volatile ("mrs %0, cntp_ctl_el0" : "=r"(ret) :: "memory"); src/arch/x86_64/init_paging.cpp: asm volatile ("mov %%rax, %%cr3;" :: "a" (pdir)); src/arch/x86_64/paging.cpp: asm volatile("invlpg (%0)" ::"r" (pageaddr) : "memory"); ```

Comments

torgeiru

@elstr-512 do you have any plans on this?

alfreb

A worthy goal. Note that many of these will be privileged so there won't exist intrinsics for them. The goals should be: 1. If there is a C++ standard way of doing it, that should be used, if it's guaranteed to be safe at the point where it's needed, e.g. everything the C++ call depends on such as allocation and exception support are ready. 2. If there's no C++ standard way but there is a compiler intrinsic, that should be used. 3. If there's no compiler intrinsic for it, for example because it's privileged, the inline asm should be placed in the arch specific arch library, e.g. src/arch/ or api/arch/. It can also be ok to have this in a specific platform, since platforms are arch specific, but it's probably nicer if we make our own inline "intrinsic like" wrapper for it so that it can be reused by other platforms in a consistent way. For integration tests, if the test is specific to a target arch, inline asm can be fine - we use it for example to trigger CPU exceptions at one point, which can be hard to get the compiler to do as it will try not to.