#ifndef FURIX_ARCH_X86_64_IO_H #define FURIX_ARCH_X86_64_IO_H #include struct desc_ptr { uint16_t limit; uint64_t base; } __attribute__((packed)); /* * CR4.PAE is required for the 4-level page tables long mode uses. CR4.PSE is * NOT needed there: in long mode 2 MiB pages come from PAE on its own. * * CR4.FSGSBASE is never set on this CPU model, see percpu.c. */ #define CR4_PAE (1u << 5) #define CR4_FSGSBASE (1u << 16) /* implemented in arch/x86_64/asm.S, so no inline asm elsewhere */ uint8_t inb(uint16_t port); void outb(uint16_t port, uint8_t value); void cpu_cli(void); void cpu_sti(void); void cpu_hlt(void); /* mask interrupts, returning the prior EFLAGS word to pass back to restore */ uint64_t cpu_irq_save(void); void cpu_irq_restore(uint64_t flags); uint32_t cpu_irqs_enabled(void); uint64_t rdmsr(uint32_t msr); void wrmsr(uint32_t msr, uint64_t value); void swapgs(void); uint32_t read_cr4(void); void write_cr4(uint32_t value); void wrgsbase(uint64_t value); uint64_t rdfsbase(void); uint64_t read_cr2(void); uint64_t read_cr3(void); /* result of the last cpuid() call: {eax, ebx, ecx, edx} */ extern uint64_t cpuid_out[4]; void cpuid(uint32_t leaf); void lgdt(const struct desc_ptr *ptr); void lidt(const struct desc_ptr *ptr); void ltr(uint16_t selector); void reload_cs(uint16_t selector); void load_data_segments(uint16_t selector); void gs_store(uint64_t value); uint64_t gs_load(void); /* * atomics, implemented in asm.S because they need `lock` prefixes that are * awkward and error-prone as inline asm (and cannot be written as a plain C * `+=` without the compiler knowing the access is shared). * * fetch_add returns the value BEFORE the addition, so it doubles as a * completion index. the u32 form is deliberate: a 64-bit add is not atomic on * a 32-bit target and 32 bits is what the counters here need. */ uint32_t atomic_fetch_add_u32(volatile uint32_t *ptr, uint32_t value); /* returns the value read, having set *ptr to 1. nonzero means "lost the race" */ uint8_t atomic_test_and_set_u8(volatile uint8_t *ptr); /* a volatile load; x86 makes an aligned 32-bit load atomic anyway */ uint32_t atomic_load_u32(const volatile uint32_t *ptr); #endif /* FURIX_ARCH_X86_64_IO_H */