diff options
Diffstat (limited to '')
-rw-r--r-- | include/x86/ops.h | 443 |
1 files changed, 443 insertions, 0 deletions
diff --git a/include/x86/ops.h b/include/x86/ops.h new file mode 100644 index 0000000..ad795b9 --- /dev/null +++ b/include/x86/ops.h @@ -0,0 +1,443 @@ +/** +** @file ops.h +** +** @author Warren R. Carithers +** +** @brief Inline escapes to assembly for efficiency +** +** Inspiration from: +** Martins Mozeiko, https://gist.github.com/mmozeiko/f68ad2546bd6ab953315 +** MIT's xv6, https://github.com/mit-pdos/xv6-public +** +** Note: normally, GCC doesn't inline unless the optimization level is +** over 1. This can be forced by adding +** +** __attribute__((always_inline)) +** +** after the parameter list on each declaration. This is enabled by +** defining the compile-time CPP symbol FORCE_INLINING. +*/ + +#ifndef OPS_H_ +#define OPS_H_ + +#include <common.h> + +#ifndef ASM_SRC + +// control "forced" inlining +#ifdef FORCE_INLINING +#define OPSINLINED __attribute__((always_inline)) +#else +#define OPSINLINED /* no-op */ +#endif /* FORCE_INLINING */ + +/**************************** +** Data movement +****************************/ + +/** +** Block move functions +** +** Variations: movsb(), movsl(), movsq() +** +** Description: Copy from source buffer to destination buffer +** +** @param dst Destination buffer +** @param src Source buffer +** @param len Byte count +*/ +static inline void +movsb( void* dst, const void* src, uint32_t len ) OPSINLINED +{ + __asm__ __volatile__( "cld; rep movsb" + : "+D"(dst), "+S"(src), "+c"(len) + : : "memory" ); +} + +static inline void +movsw( void* dst, const void* src, uint32_t len ) OPSINLINED +{ + __asm__ __volatile__( "cld; rep movsw" + : "+D"(dst), "+S"(src), "+c"(len) + : : "memory" ); +} + +static inline void +movsl( void* dst, const void* src, uint32_t len ) OPSINLINED +{ + __asm__ __volatile__( "cld; rep movsl" + : "+D"(dst), "+S"(src), "+c"(len) + : : "memory" ); +} + +static inline void +movsq( void* dst, const void* src, uint32_t len ) OPSINLINED +{ + __asm__ __volatile__( "cld; rep movsq" + : "+D"(dst), "+S"(src), "+c"(len) + : : "memory" ); +} + +/** +** Block store functions +** +** Variations: stosb(), stosw(), stosl() +** +** Description: Store a specific value into destination buffer +** +** @param dst Destination buffer +** @param val Data to copy +** @param len Byte count +*/ +static inline void +stosb( void *dst, uint8_t val, uint32_t len ) OPSINLINED +{ + __asm__ __volatile__( "cld; rep stosb" + : "=D" (dst), "=c" (len) + : "0" (dst), "1" (len), "a" (val) + : "memory", "cc" ); +} + +static inline void +stosw( void *dst, uint16_t val, uint32_t len ) OPSINLINED +{ + __asm__ __volatile__( "cld; rep stos2" + : "=D" (dst), "=c" (len) + : "0" (dst), "1" (len), "a" (val) + : "memory", "cc" ); +} + +static inline void +stosl( void *dst, uint32_t val, uint32_t len ) OPSINLINED +{ + __asm__ __volatile__( "cld; rep stosl" + : "=D" (dst), "=c" (len) + : "0" (dst), "1" (len), "a" (val) + : "memory", "cc" ); +} + +/**************************** +** Special register access +****************************/ + +/** +** Register read functions +** +** Variations: r_cr0(), r_cr2(), r_cr3(), r_cr4(), r_eflags(), +** r_ebp(), r_esp() +** +** Description: Reads the register indicated by its name +** +** @return Contents of the register +*/ +static inline uint32_t +r_cr0( void ) OPSINLINED +{ + uint32_t val; + __asm__ __volatile__( "movl %%cr0,%0" : "=r" (val) ); + return val; +} + +static inline uint32_t +r_cr2( void ) OPSINLINED +{ + uint32_t val; + __asm__ __volatile__( "movl %%cr2,%0" : "=r" (val) ); + return val; +} + +static inline uint32_t +r_cr3( void ) OPSINLINED +{ + uint32_t val; + __asm__ __volatile__( "movl %%cr3,%0" : "=r" (val) ); + return val; +} + +static inline uint32_t +r_cr4( void ) OPSINLINED +{ + uint32_t val; + __asm__ __volatile__( "movl %%cr4,%0" : "=r" (val) ); + return val; +} + +static inline uint32_t +r_eflags(void) OPSINLINED +{ + uint32_t val; + __asm__ __volatile__( "pushfl; popl %0" : "=r" (val) ); + return val; +} + +static inline uint32_t +r_ebp(void) OPSINLINED +{ + uint32_t val; + __asm__ __volatile__( "movl %%ebp,%0" : "=r" (val) ); + return val; +} + +static inline uint32_t +r_esp(void) OPSINLINED +{ + uint32_t val; + __asm__ __volatile__( "movl %%esp,%0" : "=r" (val) ); + return val; +} + +/** +** Register write functions +** +** Variations: w_cr0(), w_cr2(), w_cr3(), w_cr4(), w_eflags() +** +** Description: Writes a value into the CR indicated by its name +*/ +static inline void +w_cr0( uint32_t val ) OPSINLINED +{ + __asm__ __volatile__( "movl %0,%%cr0" : : "r" (val) ); +} + +static inline void +w_cr2( uint32_t val ) OPSINLINED +{ + __asm__ __volatile__( "movl %0,%%cr2" : : "r" (val) ); +} + +static inline void +w_cr3( uint32_t val ) OPSINLINED +{ + __asm__ __volatile__( "movl %0,%%cr3" : : "r" (val) ); +} + +static inline void +w_cr4( uint32_t val ) OPSINLINED +{ + __asm__ __volatile__( "movl %0,%%cr4" : : "r" (val) ); +} + +static inline void +w_eflags(uint32_t eflags) OPSINLINED +{ + __asm__ __volatile__( "pushl %0; popfl" : : "r" (eflags) ); +} + +/** +** Descriptor table load functions +** +** Variations: w_gdt(), w_idt() +** +** Description: Load an address into the specified processor register +** +** @param addr The value to be loaded into the register +*/ +static inline void +w_gdt( void *addr ) OPSINLINED +{ + __asm__ __volatile__( "lgdt (%0)" : : "r" (addr) ); +} + +static inline void +w_idt( void *addr ) OPSINLINED +{ + __asm__ __volatile__( "lidt (%0)" : : "r" (addr) ); +} + +/** +** CPU ID access +** +** Description: Retrieve CPUID information +** +** @param op Value to be placed into %eax for the operation +** @param ap Pointer to where %eax contents should be saved, or NULL +** @param bp Pointer to where %ebx contents should be saved, or NULL +** @param cp Pointer to where %ecx contents should be saved, or NULL +** @param dp Pointer to where %edx contents should be saved, or NULL +*/ +static inline void +cpuid( uint32_t op, uint32_t *ap, uint32_t *bp, + uint32_t *cp, uint32_t *dp ) OPSINLINED +{ + uint32_t eax, ebx, ecx, edx; + __asm__ __volatile__( "cpuid" + : "=a" (eax), "=b" (ebx), "=c" (ecx), "=d" (edx) + : "a" (op) ); + + if( ap ) *ap = eax; + if( bp ) *bp = ebx; + if( cp ) *cp = ecx; + if( dp ) *dp = edx; +} + +/**************************** +** TLB management +****************************/ + +/** +** TLB invalidation for one page +** +** Description: Invalidate the TLB entry for an address +** +** @param addr An address within the page to be flushed +*/ +static inline void +invlpg( uint32_t addr ) OPSINLINED +{ + __asm__ __volatile__( "invlpg (%0)" : : "r" (addr) : "memory" ); +} + +/** +** TLB invalidation for all pages +** +** Description: Flush all entries from the TLB +** +** We do this by changing CR3. +*/ +static inline void +flushtlb( void ) OPSINLINED +{ + uint32_t cr3; + __asm__ __volatile__( "movl %%cr3,%0" : "=r" (cr3) ); + __asm__ __volatile__( "movl %0,%%cr2" : : "r" (cr3) ); +} + +/**************************** +** I/O instructions +****************************/ + +/** +** Name: inN +** +** Variations: inb(), inw(), inl() +** +** Description: Read some amount of data from the supplied I/O port +** +** @param port The i/o port to read from +** +** @return The data read from the specified port +*/ +static inline uint8_t +inb( int port ) OPSINLINED +{ + uint8_t data; + __asm__ __volatile__( "inb %w1,%0" : "=a" (data) : "d" (port) ); + return data; +} + +static inline uint16_t +inw( int port ) OPSINLINED +{ + uint16_t data; + __asm__ __volatile__( "inw %w1,%0" : "=a" (data) : "d" (port) ); + return data; +} + +static inline uint32_t +inl( int port ) OPSINLINED +{ + uint32_t data; + __asm__ __volatile__( "inl %w1,%0" : "=a" (data) : "d" (port) ); + return data; +} + +/** +** Name: outN +** +** Variations: outb(), outw(), outl() +** +** Description: Write some data to the specified I/O port +** +** @param port The i/o port to write to +** @param data The data to be written to the port +** +** @return The data read from the specified port +*/ +static inline void +outb( int port, uint8_t data ) OPSINLINED +{ + __asm__ __volatile__( "outb %0,%w1" : : "a" (data), "d" (port) ); +} + +static inline void +outw( int port, uint16_t data ) OPSINLINED +{ + __asm__ __volatile__( "outw %0,%w1" : : "a" (data), "d" (port) ); +} + +static inline void +outl( int port, uint32_t data ) OPSINLINED +{ + __asm__ __volatile__( "outl %0,%w1" : : "a" (data), "d" (port) ); +} + +/**************************** +** Miscellaneous instructions +****************************/ + +/** +** Name: breakpoint +** +** Description: Cause a breakpoint interrupt for debugging purposes +*/ +static inline void +breakpoint( void ) OPSINLINED +{ + __asm__ __volatile__( "int3" ); +} + +/** +** Name: get_ra +** +** Description: Get the return address for the calling function +** (i.e., where whoever called us will go back to) +** +** @return The address the calling routine will return to as a uint32_t +*/ +static inline uint32_t +get_ra( void ) OPSINLINED +{ + uint32_t val; + __asm__ __volatile__( "movl 4(%%ebp),%0" : "=r" (val) ); + return val; +} + +/** +** Name: ev_wait +** +** Description: Pause until something happens +*/ +static inline void +ev_wait( void ) OPSINLINED +{ + __asm__ __volatile__( "sti ; hlt" ); +} + + +/** +** Name: xchgl +** +** Description: Perform an atomic exchange with memory +** +** @param addr Memory location to be modified +** @param data Data to exchange +** +** @return The old contents of the memory location +*/ +static inline uint32_t +xchgl( volatile uint32_t *addr, uint32_t data ) OPSINLINED +{ + uint32_t old; + + // + indicates a read-modify-write operand + __asm__ __volatile__( "lock; xchgl %0, %1" + : "+m" (*addr), "=a" (old) + : "1" (data) + : "cc"); + return old; +} + +#endif /* !ASM_SRC */ + +#endif |