8148b6ee53
nesting cli/sti: release shouldn't always enable interrupts separate setup of lapic from starting of other cpus, so cpu() works earlier flag to disable locking in console output make locks work even when curproc==0 (still crashes in clock interrupt)
344 lines
8.2 KiB
C
344 lines
8.2 KiB
C
static __inline void breakpoint(void) __attribute__((always_inline));
|
|
static __inline uint8_t inb(int port) __attribute__((always_inline));
|
|
static __inline void insb(int port, void *addr, int cnt) __attribute__((always_inline));
|
|
static __inline uint16_t inw(int port) __attribute__((always_inline));
|
|
static __inline void insw(int port, void *addr, int cnt) __attribute__((always_inline));
|
|
static __inline uint32_t inl(int port) __attribute__((always_inline));
|
|
static __inline void insl(int port, void *addr, int cnt) __attribute__((always_inline));
|
|
static __inline void outb(int port, uint8_t data) __attribute__((always_inline));
|
|
static __inline void outsb(int port, const void *addr, int cnt) __attribute__((always_inline));
|
|
static __inline void outw(int port, uint16_t data) __attribute__((always_inline));
|
|
static __inline void outsw(int port, const void *addr, int cnt) __attribute__((always_inline));
|
|
static __inline void outsl(int port, const void *addr, int cnt) __attribute__((always_inline));
|
|
static __inline void outl(int port, uint32_t data) __attribute__((always_inline));
|
|
static __inline void invlpg(void *addr) __attribute__((always_inline));
|
|
static __inline void lidt(void *p) __attribute__((always_inline));
|
|
static __inline void lldt(uint16_t sel) __attribute__((always_inline));
|
|
static __inline void ltr(uint16_t sel) __attribute__((always_inline));
|
|
static __inline void lcr0(uint32_t val) __attribute__((always_inline));
|
|
static __inline uint32_t rcr0(void) __attribute__((always_inline));
|
|
static __inline uint32_t rcr2(void) __attribute__((always_inline));
|
|
static __inline void lcr3(uint32_t val) __attribute__((always_inline));
|
|
static __inline uint32_t rcr3(void) __attribute__((always_inline));
|
|
static __inline void lcr4(uint32_t val) __attribute__((always_inline));
|
|
static __inline uint32_t rcr4(void) __attribute__((always_inline));
|
|
static __inline void tlbflush(void) __attribute__((always_inline));
|
|
static __inline uint32_t read_eflags(void) __attribute__((always_inline));
|
|
static __inline void write_eflags(uint32_t eflags) __attribute__((always_inline));
|
|
static __inline uint32_t read_ebp(void) __attribute__((always_inline));
|
|
static __inline uint32_t read_esp(void) __attribute__((always_inline));
|
|
static __inline void cpuid(uint32_t info, uint32_t *eaxp, uint32_t *ebxp, uint32_t *ecxp, uint32_t *edxp);
|
|
static __inline uint64_t read_tsc(void) __attribute__((always_inline));
|
|
|
|
static __inline void
|
|
breakpoint(void)
|
|
{
|
|
__asm __volatile("int3");
|
|
}
|
|
|
|
static __inline uint8_t
|
|
inb(int port)
|
|
{
|
|
uint8_t data;
|
|
__asm __volatile("inb %w1,%0" : "=a" (data) : "d" (port));
|
|
return data;
|
|
}
|
|
|
|
static __inline void
|
|
insb(int port, void *addr, int cnt)
|
|
{
|
|
__asm __volatile("cld\n\trepne\n\tinsb" :
|
|
"=D" (addr), "=c" (cnt) :
|
|
"d" (port), "0" (addr), "1" (cnt) :
|
|
"memory", "cc");
|
|
}
|
|
|
|
static __inline uint16_t
|
|
inw(int port)
|
|
{
|
|
uint16_t data;
|
|
__asm __volatile("inw %w1,%0" : "=a" (data) : "d" (port));
|
|
return data;
|
|
}
|
|
|
|
static __inline void
|
|
insw(int port, void *addr, int cnt)
|
|
{
|
|
__asm __volatile("cld\n\trepne\n\tinsw" :
|
|
"=D" (addr), "=c" (cnt) :
|
|
"d" (port), "0" (addr), "1" (cnt) :
|
|
"memory", "cc");
|
|
}
|
|
|
|
static __inline uint32_t
|
|
inl(int port)
|
|
{
|
|
uint32_t data;
|
|
__asm __volatile("inl %w1,%0" : "=a" (data) : "d" (port));
|
|
return data;
|
|
}
|
|
|
|
static __inline void
|
|
insl(int port, void *addr, int cnt)
|
|
{
|
|
__asm __volatile("cld\n\trepne\n\tinsl" :
|
|
"=D" (addr), "=c" (cnt) :
|
|
"d" (port), "0" (addr), "1" (cnt) :
|
|
"memory", "cc");
|
|
}
|
|
|
|
static __inline void
|
|
outb(int port, uint8_t data)
|
|
{
|
|
__asm __volatile("outb %0,%w1" : : "a" (data), "d" (port));
|
|
}
|
|
|
|
static __inline void
|
|
outsb(int port, const void *addr, int cnt)
|
|
{
|
|
__asm __volatile("cld\n\trepne\n\toutsb" :
|
|
"=S" (addr), "=c" (cnt) :
|
|
"d" (port), "0" (addr), "1" (cnt) :
|
|
"cc");
|
|
}
|
|
|
|
static __inline void
|
|
outw(int port, uint16_t data)
|
|
{
|
|
__asm __volatile("outw %0,%w1" : : "a" (data), "d" (port));
|
|
}
|
|
|
|
static __inline void
|
|
outsw(int port, const void *addr, int cnt)
|
|
{
|
|
__asm __volatile("cld\n\trepne\n\toutsw" :
|
|
"=S" (addr), "=c" (cnt) :
|
|
"d" (port), "0" (addr), "1" (cnt) :
|
|
"cc");
|
|
}
|
|
|
|
static __inline void
|
|
outsl(int port, const void *addr, int cnt)
|
|
{
|
|
__asm __volatile("cld\n\trepne\n\toutsl" :
|
|
"=S" (addr), "=c" (cnt) :
|
|
"d" (port), "0" (addr), "1" (cnt) :
|
|
"cc");
|
|
}
|
|
|
|
static __inline void
|
|
outl(int port, uint32_t data)
|
|
{
|
|
__asm __volatile("outl %0,%w1" : : "a" (data), "d" (port));
|
|
}
|
|
|
|
static __inline void
|
|
invlpg(void *addr)
|
|
{
|
|
__asm __volatile("invlpg (%0)" : : "r" (addr) : "memory");
|
|
}
|
|
|
|
static __inline void
|
|
lidt(void *p)
|
|
{
|
|
__asm __volatile("lidt (%0)" : : "r" (p));
|
|
}
|
|
|
|
static __inline void
|
|
lldt(uint16_t sel)
|
|
{
|
|
__asm __volatile("lldt %0" : : "r" (sel));
|
|
}
|
|
|
|
static __inline void
|
|
ltr(uint16_t sel)
|
|
{
|
|
__asm __volatile("ltr %0" : : "r" (sel));
|
|
}
|
|
|
|
static __inline void
|
|
lcr0(uint32_t val)
|
|
{
|
|
__asm __volatile("movl %0,%%cr0" : : "r" (val));
|
|
}
|
|
|
|
static __inline uint32_t
|
|
rcr0(void)
|
|
{
|
|
uint32_t val;
|
|
__asm __volatile("movl %%cr0,%0" : "=r" (val));
|
|
return val;
|
|
}
|
|
|
|
static __inline uint32_t
|
|
rcr2(void)
|
|
{
|
|
uint32_t val;
|
|
__asm __volatile("movl %%cr2,%0" : "=r" (val));
|
|
return val;
|
|
}
|
|
|
|
static __inline void
|
|
lcr3(uint32_t val)
|
|
{
|
|
__asm __volatile("movl %0,%%cr3" : : "r" (val));
|
|
}
|
|
|
|
static __inline uint32_t
|
|
rcr3(void)
|
|
{
|
|
uint32_t val;
|
|
__asm __volatile("movl %%cr3,%0" : "=r" (val));
|
|
return val;
|
|
}
|
|
|
|
static __inline void
|
|
lcr4(uint32_t val)
|
|
{
|
|
__asm __volatile("movl %0,%%cr4" : : "r" (val));
|
|
}
|
|
|
|
static __inline uint32_t
|
|
rcr4(void)
|
|
{
|
|
uint32_t cr4;
|
|
__asm __volatile("movl %%cr4,%0" : "=r" (cr4));
|
|
return cr4;
|
|
}
|
|
|
|
static __inline void
|
|
tlbflush(void)
|
|
{
|
|
uint32_t cr3;
|
|
__asm __volatile("movl %%cr3,%0" : "=r" (cr3));
|
|
__asm __volatile("movl %0,%%cr3" : : "r" (cr3));
|
|
}
|
|
|
|
static __inline uint32_t
|
|
read_eflags(void)
|
|
{
|
|
uint32_t eflags;
|
|
__asm __volatile("pushfl; popl %0" : "=r" (eflags));
|
|
return eflags;
|
|
}
|
|
|
|
static __inline void
|
|
write_eflags(uint32_t eflags)
|
|
{
|
|
__asm __volatile("pushl %0; popfl" : : "r" (eflags));
|
|
}
|
|
|
|
static __inline uint32_t
|
|
read_ebp(void)
|
|
{
|
|
uint32_t ebp;
|
|
__asm __volatile("movl %%ebp,%0" : "=r" (ebp));
|
|
return ebp;
|
|
}
|
|
|
|
static __inline uint32_t
|
|
read_esp(void)
|
|
{
|
|
uint32_t esp;
|
|
__asm __volatile("movl %%esp,%0" : "=r" (esp));
|
|
return esp;
|
|
}
|
|
|
|
static __inline uint32_t
|
|
read_esi(void)
|
|
{
|
|
uint32_t esi;
|
|
__asm __volatile("movl %%esi,%0" : "=r" (esi));
|
|
return esi;
|
|
}
|
|
|
|
static __inline uint32_t
|
|
read_edi(void)
|
|
{
|
|
uint32_t edi;
|
|
__asm __volatile("movl %%edi,%0" : "=r" (edi));
|
|
return edi;
|
|
}
|
|
|
|
static __inline uint32_t
|
|
read_ebx(void)
|
|
{
|
|
uint32_t ebx;
|
|
__asm __volatile("movl %%ebx,%0" : "=r" (ebx));
|
|
return ebx;
|
|
}
|
|
|
|
static __inline void
|
|
cpuid(uint32_t info, uint32_t *eaxp, uint32_t *ebxp, uint32_t *ecxp, uint32_t *edxp)
|
|
{
|
|
uint32_t eax, ebx, ecx, edx;
|
|
asm volatile("cpuid"
|
|
: "=a" (eax), "=b" (ebx), "=c" (ecx), "=d" (edx)
|
|
: "a" (info));
|
|
if (eaxp)
|
|
*eaxp = eax;
|
|
if (ebxp)
|
|
*ebxp = ebx;
|
|
if (ecxp)
|
|
*ecxp = ecx;
|
|
if (edxp)
|
|
*edxp = edx;
|
|
}
|
|
|
|
static __inline uint32_t
|
|
cmpxchg(uint32_t oldval, uint32_t newval, volatile uint32_t* lock_addr)
|
|
{
|
|
uint32_t result;
|
|
__asm__ __volatile__(
|
|
"lock; cmpxchgl %2, %0"
|
|
:"+m" (*lock_addr), "=a" (result) : "r"(newval), "1"(oldval) : "cc"
|
|
);
|
|
return result;
|
|
}
|
|
|
|
static __inline uint64_t
|
|
read_tsc(void)
|
|
{
|
|
uint64_t tsc;
|
|
__asm __volatile("rdtsc" : "=A" (tsc));
|
|
return tsc;
|
|
}
|
|
|
|
struct PushRegs {
|
|
/* registers as pushed by pusha */
|
|
uint32_t reg_edi;
|
|
uint32_t reg_esi;
|
|
uint32_t reg_ebp;
|
|
uint32_t reg_oesp; /* Useless */
|
|
uint32_t reg_ebx;
|
|
uint32_t reg_edx;
|
|
uint32_t reg_ecx;
|
|
uint32_t reg_eax;
|
|
};
|
|
|
|
struct Trapframe {
|
|
struct PushRegs tf_regs;
|
|
uint16_t tf_es;
|
|
uint16_t tf_padding1;
|
|
uint16_t tf_ds;
|
|
uint16_t tf_padding2;
|
|
uint32_t tf_trapno;
|
|
/* below here defined by x86 hardware */
|
|
uint32_t tf_err;
|
|
uintptr_t tf_eip;
|
|
uint16_t tf_cs;
|
|
uint16_t tf_padding3;
|
|
uint32_t tf_eflags;
|
|
/* below here only when crossing rings, such as from user to kernel */
|
|
uintptr_t tf_esp;
|
|
uint16_t tf_ss;
|
|
uint16_t tf_padding4;
|
|
};
|
|
|
|
#define MAX_IRQS 16 // Number of IRQs
|
|
|
|
#define IRQ_OFFSET 32 // IRQ 0 corresponds to int IRQ_OFFSET
|
|
|
|
#define IRQ_IDE 14
|
|
#define IRQ_ERROR 19
|
|
#define IRQ_SPURIOUS 31
|