timer interrupts

disk interrupts (assuming bochs has a bug)
This commit is contained in:
kaashoek 2006-07-05 20:00:14 +00:00
parent 8b4e2a08fe
commit b22d898297
9 changed files with 185 additions and 138 deletions

6
defs.h
View file

@ -25,11 +25,13 @@ void * memcpy(void *dst, void *src, unsigned n);
void * memset(void *dst, int c, unsigned n); void * memset(void *dst, int c, unsigned n);
int memcmp(const void *v1, const void *v2, unsigned n); int memcmp(const void *v1, const void *v2, unsigned n);
void *memmove(void *dst, const void *src, unsigned n); void *memmove(void *dst, const void *src, unsigned n);
int strncmp(const char *p, const char *q, unsigned n);
// syscall.c // syscall.c
void syscall(void); void syscall(void);
// picirq.c // picirq.c
extern uint16_t irq_mask_8259A;
void irq_setmask_8259A(uint16_t mask); void irq_setmask_8259A(uint16_t mask);
void pic_init(void); void pic_init(void);
@ -66,3 +68,7 @@ struct fd * fd_alloc();
void fd_close(struct fd *); void fd_close(struct fd *);
int fd_read(struct fd *fd, char *addr, int n); int fd_read(struct fd *fd, char *addr, int n);
int fd_write(struct fd *fd, char *addr, int n); int fd_write(struct fd *fd, char *addr, int n);
// ide.c
void ide_init(void);
int ide_read(uint32_t secno, void *dst, unsigned nsecs);

121
ide.c
View file

@ -21,97 +21,104 @@ static int diskno = 0;
static int static int
ide_wait_ready(int check_error) ide_wait_ready(int check_error)
{ {
int r; int r;
while (((r = inb(0x1F7)) & (IDE_BSY|IDE_DRDY)) != IDE_DRDY) while (((r = inb(0x1F7)) & (IDE_BSY|IDE_DRDY)) != IDE_DRDY)
/* do nothing */; /* do nothing */;
if (check_error && (r & (IDE_DF|IDE_ERR)) != 0) if (check_error && (r & (IDE_DF|IDE_ERR)) != 0)
return -1; return -1;
return 0; return 0;
} }
void
ide_init(void)
{
cprintf("ide_init: enable IRQ 14\n");
irq_setmask_8259A(irq_mask_8259A & ~(1<<14));
ide_wait_ready(0);
}
int int
ide_probe_disk1(void) ide_probe_disk1(void)
{ {
int r, x; int r, x;
// wait for Device 0 to be ready // wait for Device 0 to be ready
ide_wait_ready(0); ide_wait_ready(0);
// switch to Device 1 // switch to Device 1
outb(0x1F6, 0xE0 | (1<<4)); outb(0x1F6, 0xE0 | (1<<4));
// check for Device 1 to be ready for a while // check for Device 1 to be ready for a while
for (x = 0; x < 1000 && (r = inb(0x1F7)) == 0; x++) for (x = 0; x < 1000 && (r = inb(0x1F7)) == 0; x++)
/* do nothing */; /* do nothing */;
// switch back to Device 0 // switch back to Device 0
outb(0x1F6, 0xE0 | (0<<4)); outb(0x1F6, 0xE0 | (0<<4));
cprintf("Device 1 presence: %d\n", (x < 1000)); cprintf("Device 1 presence: %d\n", (x < 1000));
return (x < 1000); return (x < 1000);
} }
void void
ide_set_disk(int d) ide_set_disk(int d)
{ {
if (d != 0 && d != 1) if (d != 0 && d != 1)
panic("bad disk number"); panic("bad disk number");
diskno = d; diskno = d;
} }
int int
ide_read(uint32_t secno, void *dst, unsigned nsecs) ide_read(uint32_t secno, void *dst, unsigned nsecs)
{ {
int r; int r;
if(nsecs > 256) if(nsecs > 256)
panic("ide_read"); panic("ide_read");
ide_wait_ready(0); ide_wait_ready(0);
outb(0x3f6, 0); outb(0x3f6, 0);
outb(0x1F2, nsecs); outb(0x1F2, nsecs);
outb(0x1F3, secno & 0xFF); outb(0x1F3, secno & 0xFF);
outb(0x1F4, (secno >> 8) & 0xFF); outb(0x1F4, (secno >> 8) & 0xFF);
outb(0x1F5, (secno >> 16) & 0xFF); outb(0x1F5, (secno >> 16) & 0xFF);
outb(0x1F6, 0xE0 | ((diskno&1)<<4) | ((secno>>24)&0x0F)); outb(0x1F6, 0xE0 | ((diskno&1)<<4) | ((secno>>24)&0x0F));
outb(0x1F7, 0x20); // CMD 0x20 means read sector outb(0x1F7, 0x20); // CMD 0x20 means read sector
sleep(0); for (; nsecs > 0; nsecs--, dst += 512) {
if ((r = ide_wait_ready(1)) < 0)
for (; nsecs > 0; nsecs--, dst += 512) { return r;
if ((r = ide_wait_ready(1)) < 0) insl(0x1F0, dst, 512/4);
return r; }
insl(0x1F0, dst, 512/4);
}
return 0; return 0;
} }
int int
ide_write(uint32_t secno, const void *src, unsigned nsecs) ide_write(uint32_t secno, const void *src, unsigned nsecs)
{ {
int r; int r;
if(nsecs > 256) if(nsecs > 256)
panic("ide_write"); panic("ide_write");
ide_wait_ready(0); ide_wait_ready(0);
outb(0x1F2, nsecs); outb(0x1F2, nsecs);
outb(0x1F3, secno & 0xFF); outb(0x1F3, secno & 0xFF);
outb(0x1F4, (secno >> 8) & 0xFF); outb(0x1F4, (secno >> 8) & 0xFF);
outb(0x1F5, (secno >> 16) & 0xFF); outb(0x1F5, (secno >> 16) & 0xFF);
outb(0x1F6, 0xE0 | ((diskno&1)<<4) | ((secno>>24)&0x0F)); outb(0x1F6, 0xE0 | ((diskno&1)<<4) | ((secno>>24)&0x0F));
outb(0x1F7, 0x30); // CMD 0x30 means write sector outb(0x1F7, 0x30); // CMD 0x30 means write sector
for (; nsecs > 0; nsecs--, src += 512) { for (; nsecs > 0; nsecs--, src += 512) {
if ((r = ide_wait_ready(1)) < 0) if ((r = ide_wait_ready(1)) < 0)
return r; return r;
outsl(0x1F0, src, 512/4); outsl(0x1F0, src, 512/4);
} }
return 0; return 0;
} }

6
main.c
View file

@ -36,7 +36,7 @@ main()
cprintf("\nxV6\n\n"); cprintf("\nxV6\n\n");
pic_init(); // initialize PIC---not clear why pic_init(); // initialize PIC
mp_init(); // multiprocessor mp_init(); // multiprocessor
kinit(); // physical memory allocator kinit(); // physical memory allocator
tvinit(); // trap vectors tvinit(); // trap vectors
@ -59,12 +59,14 @@ main()
p->ppid = 0; p->ppid = 0;
setupsegs(p); setupsegs(p);
write_eflags(read_eflags() | FL_IF);
// turn on interrupts on boot processor // turn on interrupts on boot processor
lapic_timerinit(); lapic_timerinit();
lapic_enableintr(); lapic_enableintr();
write_eflags(read_eflags() | FL_IF);
#if 0 #if 0
ide_init();
ide_read(0, buf, 1); ide_read(0, buf, 1);
cprintf("sec0.0 %x\n", buf[0] & 0xff); cprintf("sec0.0 %x\n", buf[0] & 0xff);
#endif #endif

61
mp.c
View file

@ -92,6 +92,28 @@ enum { /* LAPIC_TDCR */
LAPIC_X1 = 0x0000000B, /* divide by 1 */ LAPIC_X1 = 0x0000000B, /* divide by 1 */
}; };
static char* buses[] = {
"CBUSI ",
"CBUSII",
"EISA ",
"FUTURE",
"INTERN",
"ISA ",
"MBI ",
"MBII ",
"MCA ",
"MPI ",
"MPSA ",
"NUBUS ",
"PCI ",
"PCMCIA",
"TC ",
"VL ",
"VME ",
"XPRESS",
0,
};
#define APBOOTCODE 0x7000 // XXX hack #define APBOOTCODE 0x7000 // XXX hack
static struct MP* mp; // The MP floating point structure static struct MP* mp; // The MP floating point structure
@ -126,7 +148,7 @@ lapic_timerinit()
void void
lapic_timerintr() lapic_timerintr()
{ {
// cprintf("%d: timer interrupt!\n", cpu()); cprintf("%d: timer interrupt!\n", cpu());
lapic_write (LAPIC_EOI, 0); lapic_write (LAPIC_EOI, 0);
} }
@ -137,23 +159,17 @@ lapic_init(int c)
cprintf("lapic_init %d\n", c); cprintf("lapic_init %d\n", c);
irq_setmask_8259A(0xFFFF); lapic_write(LAPIC_DFR, 0xFFFFFFFF); // set destination format register
r = (lapic_read(LAPIC_ID)>>24) & 0xFF; // read APIC ID
lapic_write(LAPIC_LDR, (1<<r)<<24); // set logical destination register to r
lapic_write(LAPIC_TPR, 0xFF); // no interrupts for now
lapic_write(LAPIC_SVR, LAPIC_ENABLE|(IRQ_OFFSET+IRQ_SPURIOUS)); // enable APIC
lapic_write(LAPIC_DFR, 0xFFFFFFFF); // in virtual wire mode, set up the LINT0 and LINT1 as follows:
r = (lapic_read(LAPIC_ID)>>24) & 0xFF; lapic_write(LAPIC_LINT0, APIC_IMASK | APIC_EXTINT);
lapic_write(LAPIC_LDR, (1<<r)<<24); lapic_write(LAPIC_LINT1, APIC_IMASK | APIC_NMI);
lapic_write(LAPIC_TPR, 0xFF);
lapic_write(LAPIC_SVR, LAPIC_ENABLE|(IRQ_OFFSET+IRQ_SPURIOUS));
/* lapic_write(LAPIC_EOI, 0); // acknowledge any outstanding interrupts.
* Set the local interrupts. It's likely these should just be
* masked off for SMP mode as some Pentium Pros have problems if
* LINT[01] are set to ExtINT.
* Acknowledge any outstanding interrupts.
*/
lapic_write(LAPIC_LINT0, cpus[c].lintr[0]);
lapic_write(LAPIC_LINT1, cpus[c].lintr[1]);
lapic_write(LAPIC_EOI, 0);
lvt = (lapic_read(LAPIC_VER)>>16) & 0xFF; lvt = (lapic_read(LAPIC_VER)>>16) & 0xFF;
if(lvt >= 4) if(lvt >= 4)
@ -290,7 +306,7 @@ mp_detect(void)
if(sum || (pcmp->version != 1 && pcmp->version != 4)) if(sum || (pcmp->version != 1 && pcmp->version != 4))
return 3; return 3;
cprintf("Mp spec rev #: %x\n", mp->specrev); cprintf("Mp spec rev #: %x imcrp 0x%x\n", mp->specrev, mp->imcrp);
return 0; return 0;
} }
@ -308,8 +324,10 @@ mp_init()
uint8_t *p, *e; uint8_t *p, *e;
struct MPCTB *mpctb; struct MPCTB *mpctb;
struct MPPE *proc; struct MPPE *proc;
struct MPBE *bus;
int c; int c;
extern int main(); extern int main();
int i;
ncpu = 0; ncpu = 0;
if ((r = mp_detect()) != 0) return; if ((r = mp_detect()) != 0) return;
@ -332,8 +350,6 @@ mp_init()
case MPPROCESSOR: case MPPROCESSOR:
proc = (struct MPPE *) p; proc = (struct MPPE *) p;
cpus[ncpu].apicid = proc->apicid; cpus[ncpu].apicid = proc->apicid;
cpus[ncpu].lintr[0] = APIC_IMASK;
cpus[ncpu].lintr[1] = APIC_IMASK;
cprintf("a processor %x\n", cpus[ncpu].apicid); cprintf("a processor %x\n", cpus[ncpu].apicid);
if (proc->flags & MPBP) { if (proc->flags & MPBP) {
bcpu = &cpus[ncpu]; bcpu = &cpus[ncpu];
@ -342,6 +358,12 @@ mp_init()
p += sizeof(struct MPPE); p += sizeof(struct MPPE);
continue; continue;
case MPBUS: case MPBUS:
bus = (struct MPBE *) p;
for(i = 0; buses[i]; i++){
if(strncmp(buses[i], bus->string, sizeof(bus->string)) == 0)
break;
}
cprintf("a bus %d\n", i);
p += sizeof(struct MPBE); p += sizeof(struct MPBE);
continue; continue;
case MPIOAPIC: case MPIOAPIC:
@ -349,6 +371,7 @@ mp_init()
p += sizeof(struct MPIOAPIC); p += sizeof(struct MPIOAPIC);
continue; continue;
case MPIOINTR: case MPIOINTR:
cprintf("an I/O intr\n");
p += sizeof(struct MPIE); p += sizeof(struct MPIE);
continue; continue;
default: default:

111
picirq.c
View file

@ -4,80 +4,85 @@
#include "x86.h" #include "x86.h"
#include "defs.h" #include "defs.h"
// I/O Addresses of the two 8259A programmable interrupt controllers
#define IO_PIC1 0x20 // Master (IRQs 0-7)
#define IO_PIC2 0xA0 // Slave (IRQs 8-15)
#define IRQ_SLAVE 2 // IRQ at which slave connects to master
// Current IRQ mask. // Current IRQ mask.
// Initial IRQ mask has interrupt 2 enabled (for slave 8259A). // Initial IRQ mask has interrupt 2 enabled (for slave 8259A).
uint16_t irq_mask_8259A = 0xFFFF & ~(1<<IRQ_SLAVE); uint16_t irq_mask_8259A = 0xFFFF & ~(1<<IRQ_SLAVE);
static int didinit;
/* Initialize the 8259A interrupt controllers. */ /* Initialize the 8259A interrupt controllers. */
void void
pic_init(void) pic_init(void)
{ {
didinit = 1; // mask all interrupts
outb(IO_PIC1+1, 0xFF);
outb(IO_PIC2+1, 0xFF);
// mask all interrupts // Set up master (8259A-1)
outb(IO_PIC1+1, 0xFF);
outb(IO_PIC2+1, 0xFF);
// Set up master (8259A-1) // ICW1: 0001g0hi
// g: 0 = edge triggering, 1 = level triggering
// h: 0 = cascaded PICs, 1 = master only
// i: 0 = no ICW4, 1 = ICW4 required
outb(IO_PIC1, 0x11);
// ICW1: 0001g0hi // ICW2: Vector offset
// g: 0 = edge triggering, 1 = level triggering outb(IO_PIC1+1, IRQ_OFFSET);
// h: 0 = cascaded PICs, 1 = master only
// i: 0 = no ICW4, 1 = ICW4 required
outb(IO_PIC1, 0x11);
// ICW2: Vector offset // ICW3: bit mask of IR lines connected to slave PICs (master PIC),
outb(IO_PIC1+1, IRQ_OFFSET); // 3-bit No of IR line at which slave connects to master(slave PIC).
outb(IO_PIC1+1, 1<<IRQ_SLAVE);
// ICW3: bit mask of IR lines connected to slave PICs (master PIC), // ICW4: 000nbmap
// 3-bit No of IR line at which slave connects to master(slave PIC). // n: 1 = special fully nested mode
outb(IO_PIC1+1, 1<<IRQ_SLAVE); // b: 1 = buffered mode
// m: 0 = slave PIC, 1 = master PIC
// (ignored when b is 0, as the master/slave role
// can be hardwired).
// a: 1 = Automatic EOI mode
// p: 0 = MCS-80/85 mode, 1 = intel x86 mode
outb(IO_PIC1+1, 0x3);
// ICW4: 000nbmap // Set up slave (8259A-2)
// n: 1 = special fully nested mode outb(IO_PIC2, 0x11); // ICW1
// b: 1 = buffered mode outb(IO_PIC2+1, IRQ_OFFSET + 8); // ICW2
// m: 0 = slave PIC, 1 = master PIC outb(IO_PIC2+1, IRQ_SLAVE); // ICW3
// (ignored when b is 0, as the master/slave role // NB Automatic EOI mode doesn't tend to work on the slave.
// can be hardwired). // Linux source code says it's "to be investigated".
// a: 1 = Automatic EOI mode outb(IO_PIC2+1, 0x3); // ICW4
// p: 0 = MCS-80/85 mode, 1 = intel x86 mode
outb(IO_PIC1+1, 0x3);
// Set up slave (8259A-2) // OCW3: 0ef01prs
outb(IO_PIC2, 0x11); // ICW1 // ef: 0x = NOP, 10 = clear specific mask, 11 = set specific mask
outb(IO_PIC2+1, IRQ_OFFSET + 8); // ICW2 // p: 0 = no polling, 1 = polling mode
outb(IO_PIC2+1, IRQ_SLAVE); // ICW3 // rs: 0x = NOP, 10 = read IRR, 11 = read ISR
// NB Automatic EOI mode doesn't tend to work on the slave. outb(IO_PIC1, 0x68); /* clear specific mask */
// Linux source code says it's "to be investigated". outb(IO_PIC1, 0x0a); /* read IRR by default */
outb(IO_PIC2+1, 0x01); // ICW4
// OCW3: 0ef01prs outb(IO_PIC2, 0x68); /* OCW3 */
// ef: 0x = NOP, 10 = clear specific mask, 11 = set specific mask outb(IO_PIC2, 0x0a); /* OCW3 */
// p: 0 = no polling, 1 = polling mode
// rs: 0x = NOP, 10 = read IRR, 11 = read ISR
outb(IO_PIC1, 0x68); /* clear specific mask */
outb(IO_PIC1, 0x0a); /* read IRR by default */
outb(IO_PIC2, 0x68); /* OCW3 */ if (irq_mask_8259A != 0xFFFF)
outb(IO_PIC2, 0x0a); /* OCW3 */ irq_setmask_8259A(irq_mask_8259A);
if (irq_mask_8259A != 0xFFFF)
irq_setmask_8259A(irq_mask_8259A);
} }
void void
irq_setmask_8259A(uint16_t mask) irq_setmask_8259A(uint16_t mask)
{ {
int i; int i;
irq_mask_8259A = mask; irq_mask_8259A = mask;
if (!didinit)
return; outb(IO_PIC1+1, (char)mask);
outb(IO_PIC1+1, (char)mask); outb(IO_PIC2+1, (char)(mask >> 8));
outb(IO_PIC2+1, (char)(mask >> 8));
cprintf("enabled interrupts:"); cprintf("%d: enabled interrupts:", cpu());
for (i = 0; i < 16; i++)
if (~mask & (1<<i)) for (i = 0; i < 16; i++)
cprintf(" %d", i); if (~mask & (1<<i))
cprintf("\n"); cprintf(" %d", i);
cprintf("\n");
} }

1
proc.h
View file

@ -42,7 +42,6 @@ extern struct proc *curproc[NCPU];
struct cpu { struct cpu {
uint8_t apicid; // Local APIC ID uint8_t apicid; // Local APIC ID
int lintr[2]; // Local APIC
char mpstack[MPSTACK]; // per-cpu start-up stack, only used to get into main() char mpstack[MPSTACK]; // per-cpu start-up stack, only used to get into main()
}; };

View file

@ -58,3 +58,14 @@ memmove(void *dst, const void *src, unsigned n)
return dst; return dst;
} }
int
strncmp(const char *p, const char *q, unsigned n)
{
while (n > 0 && *p && *p == *q)
n--, p++, q++;
if (n == 0)
return 0;
else
return (int) ((unsigned char) *p - (unsigned char) *q);
}

1
trap.c
View file

@ -61,7 +61,6 @@ trap(struct Trapframe *tf)
return; return;
} }
cprintf("trap %d eip %x:%x\n", tf->tf_trapno, tf->tf_cs, tf->tf_eip);
// XXX probably ought to lgdt on trap return // XXX probably ought to lgdt on trap return

5
x86.h
View file

@ -352,11 +352,6 @@ struct Trapframe {
#define MAX_IRQS 16 // Number of IRQs #define MAX_IRQS 16 // Number of IRQs
// I/O Addresses of the two 8259A programmable interrupt controllers
#define IO_PIC1 0x20 // Master (IRQs 0-7)
#define IO_PIC2 0xA0 // Slave (IRQs 8-15)
#define IRQ_SLAVE 2 // IRQ at which slave connects to master
#define IRQ_OFFSET 32 // IRQ 0 corresponds to int IRQ_OFFSET #define IRQ_OFFSET 32 // IRQ 0 corresponds to int IRQ_OFFSET
#define IRQ_ERROR 19 #define IRQ_ERROR 19