perf: Use a user_data blob for perf_event (XCC)
[akaros.git] / kern / arch / x86 / arch.h
index 0efd46d..20efdf9 100644 (file)
-#ifndef ROS_INC_ARCH_H
-#define ROS_INC_ARCH_H
+#pragma once
 
 #include <ros/arch/arch.h>
 #include <ros/common.h>
 #include <arch/x86.h>
-#include <arch/apic.h>
 
 /* Arch Constants */
 #define ARCH_CL_SIZE                            64
-/* Top of the kernel virtual mapping area (KERNBASE) */
-/* For sanity reasons, I don't plan to map the top page */
-#define KERN_VMAP_TOP                          0xfffff000
-
-static __inline void breakpoint(void) __attribute__((always_inline));
-static __inline void invlpg(void *SNT addr) __attribute__((always_inline));
-static __inline void tlbflush(void) __attribute__((always_inline));
-static __inline void icache_flush_page(void* va, void* kva) __attribute__((always_inline));
-static __inline uint64_t read_tsc(void) __attribute__((always_inline));
-static __inline uint64_t read_tsc_serialized(void) __attribute__((always_inline));
-static __inline void enable_irq(void) __attribute__((always_inline));
-static __inline void disable_irq(void) __attribute__((always_inline));
-static __inline void enable_irqsave(int8_t* state) __attribute__((always_inline));
-static __inline void disable_irqsave(int8_t* state) __attribute__((always_inline));
-static __inline void cpu_relax(void) __attribute__((always_inline));
-static __inline void cpu_halt(void) __attribute__((always_inline));
-static __inline void clflush(uintptr_t* addr) __attribute__((always_inline));
-static __inline int irq_is_enabled(void) __attribute__((always_inline));
-static __inline int get_hw_coreid(uint32_t coreid);
-static __inline int hw_core_id(void) __attribute__((always_inline));
-static __inline int get_os_coreid(int hw_coreid);
-static __inline int core_id(void) __attribute__((always_inline));
-static __inline void cache_flush(void) __attribute__((always_inline));
-static __inline void reboot(void) __attribute__((always_inline)) __attribute__((noreturn));
+
+/* Used by arch/bitops.h.  Everyone else (so far) does it manually, but maybe
+ * other Linux code will use this.  We need to say both inline and apply the
+ * attrib, o/w newer gcc's complain. */
+#define __always_inline inline __attribute__((always_inline))
+
+static inline void breakpoint(void) __attribute__((always_inline));
+static inline void icache_flush_page(void *va, void *kva)
+              __attribute__((always_inline));
+static inline uint64_t read_tsc(void) __attribute__((always_inline));
+static inline uint64_t read_tscp(void) __attribute__((always_inline));
+static inline uint64_t read_tsc_serialized(void) __attribute__((always_inline));
+static inline void enable_irq(void) __attribute__((always_inline));
+static inline void disable_irq(void) __attribute__((always_inline));
+static inline void enable_irqsave(int8_t *state) __attribute__((always_inline));
+static inline void disable_irqsave(int8_t *state)
+              __attribute__((always_inline));
+static inline void cpu_relax(void) __attribute__((always_inline));
+static inline void cpu_halt(void) __attribute__((always_inline));
+static inline void clflush(uintptr_t* addr) __attribute__((always_inline));
+static inline int irq_is_enabled(void) __attribute__((always_inline));
+static inline void cache_flush(void) __attribute__((always_inline));
+static inline void reboot(void)
+              __attribute__((always_inline)) __attribute__((noreturn));
+static inline void prefetch(void *addr);
+static inline void prefetchw(void *addr);
+static inline void swap_gs(void);
 
 /* in trap.c */
 void send_ipi(uint32_t os_coreid, uint8_t vector);
 /* in cpuinfo.c */
 void print_cpuinfo(void);
-void show_mapping(uintptr_t start, size_t size);
-
-/* declared in smp.c */
-int hw_coreid_lookup[MAX_NUM_CPUS];
-int os_coreid_lookup[MAX_NUM_CPUS];
+void show_mapping(pgdir_t pgdir, uintptr_t start, size_t size);
+int vendor_id(char *);
+/* pmap.c */
+void invlpg(void *addr);
+void tlbflush(void);
+void tlb_flush_global(void);
 
-static __inline void
-breakpoint(void)
+static inline void breakpoint(void)
 {
-       __asm __volatile("int3");
+       asm volatile("int3");
 }
 
-static __inline void 
-invlpg(void *addr)
-{ 
-       __asm __volatile("invlpg (%0)" : : "r" (addr) : "memory");
-}  
-
-static __inline void
-tlbflush(void)
-{
-       uint32_t cr3;
-       __asm __volatile("movl %%cr3,%0" : "=r" (cr3));
-       __asm __volatile("movl %0,%%cr3" : : "r" (cr3));
-}
-
-static __inline void
-icache_flush_page(void* va, void* kva)
+static inline void icache_flush_page(void *va, void *kva)
 {
        // x86 handles self-modifying code (mostly) without SW support
 }
 
-static __inline uint64_t
-read_tsc(void)
+static inline uint64_t read_tsc(void)
 {
-       uint64_t tsc;
-       __asm __volatile("rdtsc" : "=A" (tsc));
-       return tsc;
+       uint32_t edx, eax;
+       asm volatile("rdtsc" : "=d"(edx), "=a"(eax));
+       return (uint64_t)edx << 32 | eax;
 }
 
 /* non-core-id reporting style (it is in ecx) */
-static __inline uint64_t
-read_tscp(void)
+static inline uint64_t read_tscp(void)
 {
-       uint64_t tsc;
-       __asm __volatile("rdtscp" : "=A" (tsc) : : "ecx");
-       return tsc;
+       uint32_t edx, eax;
+       asm volatile("rdtscp" : "=d"(edx), "=a"(eax) : : X86_REG_CX);
+       return (uint64_t)edx << 32 | eax;
 }
 
+static inline void mwait(void *eax)
+{
+       asm volatile("xorq %%rcx, %%rcx;"
+                    "xorq %%rdx, %%rdx;"
+                    "monitor;"
+                                /* this is racy, generically.  we never check if the write to
+                                 * the monitored address happened already. */
+                    "movq $0, %%rax;"  /* c-state hint.  this is C1 */
+                    "mwait;"
+                    : : "a"(eax));
+}
 /* Check out k/a/x86/rdtsc_test.c for more info */
-static __inline uint64_t 
-read_tsc_serialized(void)
+static inline uint64_t read_tsc_serialized(void)
 {
-       asm volatile("lfence"); /* mfence on amd */
+       asm volatile("lfence" ::: "memory");    /* mfence on amd? */
        return read_tsc();
 }
 
-static __inline void
-enable_irq(void)
+static inline void enable_irq(void)
 {
        asm volatile("sti");
 }
 
-static __inline void
-disable_irq(void)
+static inline void disable_irq(void)
 {
        asm volatile("cli");
 }
 
-static __inline void
-enable_irqsave(int8_t* state)
+static inline void enable_irqsave(int8_t *state)
 {
        // *state tracks the number of nested enables and disables
        // initial value of state: 0 = first run / no favorite
@@ -126,82 +117,79 @@ enable_irqsave(int8_t* state)
                (*state)++;
 }
 
-static __inline void
-disable_irqsave(int8_t* state)
+static inline void disable_irqsave(int8_t *state)
 {
        if ((*state == 0) && irq_is_enabled())
                disable_irq();
-       else 
+       else
                (*state)--;
 }
 
-static __inline void
-cpu_relax(void)
+static inline void cpu_relax(void)
 {
        __cpu_relax();
 }
 
-/* This doesn't atomically enable interrupts and then halt, like we want, so
- * x86 needs to use a custom helper in the irq handler in trap.c. */
-static __inline void
-cpu_halt(void)
+/* This atomically enables interrupts and halts.  sti does not take effect until
+ * after the *next* instruction */
+static inline void cpu_halt(void)
 {
        asm volatile("sti; hlt" : : : "memory");
 }
 
-static __inline void
-clflush(uintptr_t* addr)
+static inline void clflush(uintptr_t* addr)
 {
        asm volatile("clflush %0" : : "m"(*addr));
 }
 
-static __inline int
-irq_is_enabled(void)
+static inline int irq_is_enabled(void)
 {
-       return read_eflags() & FL_IF;
+       return read_flags() & FL_IF;
 }
 
-/* os_coreid -> hw_coreid */
-static __inline int
-get_hw_coreid(uint32_t coreid)
+static inline void cache_flush(void)
 {
-       return hw_coreid_lookup[coreid];
+       wbinvd();
 }
 
-static __inline int
-hw_core_id(void)
+static inline void reboot(void)
 {
-       return lapic_get_id();
+       uint8_t cf9 = inb(0xcf9) & ~6;
+       outb(0x92, 0x3);
+       outb(0xcf9, cf9 | 2);
+       outb(0xcf9, cf9 | 6);
+       asm volatile ("mov $0, %"X86_REG_SP"; int $0");
+       while (1);
 }
 
-/* hw_coreid -> os_coreid */
-static __inline int
-get_os_coreid(int hw_coreid)
+static inline void prefetch(void *addr)
 {
-       return os_coreid_lookup[hw_coreid];
+       asm volatile("prefetchnta (%0)" : : "r"(addr));
 }
 
-/* core_id() returns the OS core number, not to be confused with the
- * hardware-specific core identifier (such as the lapic id) returned by
- * hw_core_id() */
-static __inline int
-core_id(void)
+static inline void prefetchw(void *addr)
 {
-       return get_os_coreid(hw_core_id());
+       asm volatile("prefetchw (%0)" : : "r"(addr));
 }
 
-static __inline void
-cache_flush(void)
+/* Guest VMs have a maximum physical address they can use.  Guest
+ * physical addresses are mapped into this MCP 1:1, but limited to
+ * this max address *in hardware*.  I.e., the MCP process can address
+ * more memory than the VMMCP can.  This is great; it means that
+ * keeping VM management stuff separate from the VM is trivial: just
+ * map it above max_vm_address. There's no need, as in other systems,
+ * to tweak the page table or root pointer to protect management
+ * memory from VM memory.
+ *
+ * TODO: read a register the first time this is called and save it
+ * away.  But this is more than enough for now.
+ */
+static inline uint64_t max_guest_pa(void)
 {
-       wbinvd();
+       return (1ULL<<40) - 1;
 }
 
-static __inline void
-reboot(void)
+static inline void swap_gs(void)
 {
-       outb(0x92, 0x3);
-       asm volatile ("movl $0, %esp; int $0");
-       while(1);
+       asm volatile ("swapgs");
 }
-
-#endif /* !ROS_INC_ARCH_H */