5ce9751cab
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.
359 lines
8.3 KiB
C
359 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
|