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);
int memcmp(const void *v1, const void *v2, unsigned n);
void *memmove(void *dst, const void *src, unsigned n);
int strncmp(const char *p, const char *q, unsigned n);
// syscall.c
void syscall(void);
// picirq.c
extern uint16_t irq_mask_8259A;
void irq_setmask_8259A(uint16_t mask);
void pic_init(void);
@ -66,3 +68,7 @@ struct fd * fd_alloc();
void fd_close(struct fd *);
int fd_read(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);

119
ide.c
View file

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

6
main.c
View file

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

61
mp.c
View file

@ -92,6 +92,28 @@ enum { /* LAPIC_TDCR */
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
static struct MP* mp; // The MP floating point structure
@ -126,7 +148,7 @@ lapic_timerinit()
void
lapic_timerintr()
{
// cprintf("%d: timer interrupt!\n", cpu());
cprintf("%d: timer interrupt!\n", cpu());
lapic_write (LAPIC_EOI, 0);
}
@ -137,23 +159,17 @@ lapic_init(int 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);
r = (lapic_read(LAPIC_ID)>>24) & 0xFF;
lapic_write(LAPIC_LDR, (1<<r)<<24);
lapic_write(LAPIC_TPR, 0xFF);
lapic_write(LAPIC_SVR, LAPIC_ENABLE|(IRQ_OFFSET+IRQ_SPURIOUS));
// in virtual wire mode, set up the LINT0 and LINT1 as follows:
lapic_write(LAPIC_LINT0, APIC_IMASK | APIC_EXTINT);
lapic_write(LAPIC_LINT1, APIC_IMASK | APIC_NMI);
/*
* 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);
lapic_write(LAPIC_EOI, 0); // acknowledge any outstanding interrupts.
lvt = (lapic_read(LAPIC_VER)>>16) & 0xFF;
if(lvt >= 4)
@ -290,7 +306,7 @@ mp_detect(void)
if(sum || (pcmp->version != 1 && pcmp->version != 4))
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;
}
@ -308,8 +324,10 @@ mp_init()
uint8_t *p, *e;
struct MPCTB *mpctb;
struct MPPE *proc;
struct MPBE *bus;
int c;
extern int main();
int i;
ncpu = 0;
if ((r = mp_detect()) != 0) return;
@ -332,8 +350,6 @@ mp_init()
case MPPROCESSOR:
proc = (struct MPPE *) p;
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);
if (proc->flags & MPBP) {
bcpu = &cpus[ncpu];
@ -342,6 +358,12 @@ mp_init()
p += sizeof(struct MPPE);
continue;
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);
continue;
case MPIOAPIC:
@ -349,6 +371,7 @@ mp_init()
p += sizeof(struct MPIOAPIC);
continue;
case MPIOINTR:
cprintf("an I/O intr\n");
p += sizeof(struct MPIE);
continue;
default:

111
picirq.c
View file

@ -4,80 +4,85 @@
#include "x86.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.
// Initial IRQ mask has interrupt 2 enabled (for slave 8259A).
uint16_t irq_mask_8259A = 0xFFFF & ~(1<<IRQ_SLAVE);
static int didinit;
/* Initialize the 8259A interrupt controllers. */
void
pic_init(void)
{
didinit = 1;
// mask all interrupts
outb(IO_PIC1+1, 0xFF);
outb(IO_PIC2+1, 0xFF);
// mask all interrupts
outb(IO_PIC1+1, 0xFF);
outb(IO_PIC2+1, 0xFF);
// Set up master (8259A-1)
// 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
// 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);
// ICW2: Vector offset
outb(IO_PIC1+1, IRQ_OFFSET);
// ICW2: Vector offset
outb(IO_PIC1+1, IRQ_OFFSET);
// ICW3: bit mask of IR lines connected to slave PICs (master PIC),
// 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),
// 3-bit No of IR line at which slave connects to master(slave PIC).
outb(IO_PIC1+1, 1<<IRQ_SLAVE);
// ICW4: 000nbmap
// n: 1 = special fully nested mode
// 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
// n: 1 = special fully nested mode
// 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);
// Set up slave (8259A-2)
outb(IO_PIC2, 0x11); // ICW1
outb(IO_PIC2+1, IRQ_OFFSET + 8); // ICW2
outb(IO_PIC2+1, IRQ_SLAVE); // ICW3
// NB Automatic EOI mode doesn't tend to work on the slave.
// Linux source code says it's "to be investigated".
outb(IO_PIC2+1, 0x3); // ICW4
// Set up slave (8259A-2)
outb(IO_PIC2, 0x11); // ICW1
outb(IO_PIC2+1, IRQ_OFFSET + 8); // ICW2
outb(IO_PIC2+1, IRQ_SLAVE); // ICW3
// NB Automatic EOI mode doesn't tend to work on the slave.
// Linux source code says it's "to be investigated".
outb(IO_PIC2+1, 0x01); // ICW4
// OCW3: 0ef01prs
// ef: 0x = NOP, 10 = clear specific mask, 11 = set specific mask
// 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 */
// OCW3: 0ef01prs
// ef: 0x = NOP, 10 = clear specific mask, 11 = set specific mask
// 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 */
outb(IO_PIC2, 0x0a); /* OCW3 */
outb(IO_PIC2, 0x68); /* OCW3 */
outb(IO_PIC2, 0x0a); /* OCW3 */
if (irq_mask_8259A != 0xFFFF)
irq_setmask_8259A(irq_mask_8259A);
if (irq_mask_8259A != 0xFFFF)
irq_setmask_8259A(irq_mask_8259A);
}
void
irq_setmask_8259A(uint16_t mask)
{
int i;
irq_mask_8259A = mask;
if (!didinit)
return;
outb(IO_PIC1+1, (char)mask);
outb(IO_PIC2+1, (char)(mask >> 8));
cprintf("enabled interrupts:");
for (i = 0; i < 16; i++)
if (~mask & (1<<i))
cprintf(" %d", i);
cprintf("\n");
int i;
irq_mask_8259A = mask;
outb(IO_PIC1+1, (char)mask);
outb(IO_PIC2+1, (char)(mask >> 8));
cprintf("%d: enabled interrupts:", cpu());
for (i = 0; i < 16; i++)
if (~mask & (1<<i))
cprintf(" %d", i);
cprintf("\n");
}

1
proc.h
View file

@ -42,7 +42,6 @@ extern struct proc *curproc[NCPU];
struct cpu {
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()
};

View file

@ -58,3 +58,14 @@ memmove(void *dst, const void *src, unsigned n)
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;
}
cprintf("trap %d eip %x:%x\n", tf->tf_trapno, tf->tf_cs, tf->tf_eip);
// 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
// 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_ERROR 19