xv6/x86.h
rsc 5ce9751cab Changes to allow use of native x86 ELF compilers, which on my
Linux 2.4 box using gcc 3.4.6 don't seem to follow the same
conventions as the i386-jos-elf-gcc compilers.
Can run make 'TOOLPREFIX=' or edit the Makefile.

curproc[cpu()] can now be NULL, indicating that no proc is running.
This seemed safer to me than having curproc[0] and curproc[1]
both pointing at proc[0] potentially.

The old implementation of swtch depended on the stack frame layout
used inside swtch being okay to return from on the other stack
(exactly the V6 you are not expected to understand this).
It also could be called in two contexts: at boot time, to schedule
the very first process, and later, on behalf of a process, to sleep
or schedule some other process.

I split this into two functions: scheduler and swtch.

The scheduler is now a separate never-returning function, invoked
by each cpu once set up.  The scheduler looks like:

	scheduler() {
		setjmp(cpu.context);

		pick proc to schedule
		blah blah blah

		longjmp(proc.context)
	}

The new swtch is intended to be called only when curproc[cpu()] is not NULL,
that is, only on behalf of a user proc.  It does:

	swtch() {
		if(setjmp(proc.context) == 0)
			longjmp(cpu.context)
	}

to save the current proc context and then jump over to the scheduler,
running on the cpu stack.

Similarly the system call stubs are now in assembly in usys.S to avoid
needing to know the details of stack frame layout used by the compiler.

Also various changes in the debugging prints.
2006-07-11 01:07:40 +00:00

358 lines
8.3 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;
}
// disable interrupts
static __inline void
cli(void)
{
__asm __volatile("cli");
}
// enable interrupts
static __inline void
sti(void)
{
__asm __volatile("sti");
}
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