diff options
| -rw-r--r-- | Makefile | 2 | ||||
| -rw-r--r-- | defs.h | 4 | ||||
| -rw-r--r-- | ide.c | 117 | ||||
| -rw-r--r-- | main.c | 20 | ||||
| -rw-r--r-- | picirq.c | 92 | 
5 files changed, 228 insertions, 7 deletions
@@ -1,5 +1,5 @@  OBJS = main.o console.o string.o kalloc.o proc.o trapasm.o trap.o vectors.o \ -       syscall.o +       syscall.o ide.o picirq.o  CC = i386-jos-elf-gcc  LD = i386-jos-elf-ld @@ -24,3 +24,7 @@ void * memset(void *dst, int c, unsigned n);  // syscall.c  void syscall(void); + +// picirq.c +void irq_setmask_8259A(uint16_t mask); +void pic_init(void); @@ -0,0 +1,117 @@ +/* + * Minimal PIO-based (non-interrupt-driven) IDE driver code. + * For information about what all this IDE/ATA magic means, + * see the materials available on the class references page. + */ + +#include "types.h" +#include "param.h" +#include "mmu.h" +#include "proc.h" +#include "defs.h" +#include "x86.h" + +#define IDE_BSY		0x80 +#define IDE_DRDY	0x40 +#define IDE_DF		0x20 +#define IDE_ERR		0x01 + +static int diskno = 0; + +static int +ide_wait_ready(int check_error) +{ +	int r; + +	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; +} + +int +ide_probe_disk1(void) +{ +	int r, x; + +	// wait for Device 0 to be ready +	ide_wait_ready(0); + +	// 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 */; + +	// switch back to Device 0 +	outb(0x1F6, 0xE0 | (0<<4)); + +	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; +} + +int +ide_read(uint32_t secno, void *dst, unsigned nsecs) +{ +	int r; + +        if(nsecs > 256) +          panic("ide_read"); + +	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 +         +        sleep(0); + +	for (; nsecs > 0; nsecs--, dst += 512) { +		if ((r = ide_wait_ready(1)) < 0) +			return r; +		insl(0x1F0, dst, 512/4); +	} +	 +	return 0; +} + +int +ide_write(uint32_t secno, const void *src, unsigned nsecs) +{ +	int r; +	 +        if(nsecs > 256) +          panic("ide_write"); + +	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 + +	for (; nsecs > 0; nsecs--, src += 512) { +		if ((r = ide_wait_ready(1)) < 0) +			return r; +		outsl(0x1F0, src, 512/4); +	} + +	return 0; +} @@ -9,6 +9,8 @@  extern char edata[], end[]; +char buf[512]; +  int  main()  { @@ -18,16 +20,11 @@ main()    // clear BSS    memset(edata, 0, end - edata); -  // partially initizialize PIC -  outb(0x20+1, 0xFF); // IO_PIC1 -  outb(0xA0+1, 0xFF); // IO_PIC2 -  outb(0x20, 0x11); -  outb(0x20+1, 32); -    cprintf("\nxV6\n\n");    kinit(); // physical memory allocator    tinit(); // traps and interrupts +  pic_init();    // create fake process zero    p = &proc[0]; @@ -46,6 +43,16 @@ main()    p->ppid = 0;    setupsegs(p); +  // turn on interrupts +  write_eflags(read_eflags() | FL_IF); +  irq_setmask_8259A(0); + +#if 1 +  ide_read(0, buf, 1); +  cprintf("sec0.0 %x\n", buf[0] & 0xff); +#endif + +#if 0    p = newproc();    i = 0; @@ -73,6 +80,7 @@ main()    p->mem[i++] = T_SYSCALL;    p->tf->tf_eip = 0;    p->tf->tf_esp = p->sz; +#endif    swtch(); diff --git a/picirq.c b/picirq.c new file mode 100644 index 0000000..5fc90c5 --- /dev/null +++ b/picirq.c @@ -0,0 +1,92 @@ +/* See COPYRIGHT for copyright information. */ + +#include "types.h" +#include "x86.h" +#include "defs.h" + +#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 + +// 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); + +	// 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); + +	// 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); + +	// 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, 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 */ + +	outb(IO_PIC2, 0x68);               /* OCW3 */ +	outb(IO_PIC2, 0x0a);               /* OCW3 */ + +	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"); +}  | 
