From: acevest Date: Mon, 5 Jun 2023 04:58:54 +0000 (+0800) Subject: 支持IDE Secondary通道上的硬盘 X-Git-Url: http://zhaoyanbai.com/repos/%22http:/www.isc.org/icons/migration?a=commitdiff_plain;h=5973d8b74ae3ec89f735bf4e3107c3c1b6ea441d;p=kernel.git 支持IDE Secondary通道上的硬盘 --- diff --git a/Makefile b/Makefile index 1712475..db2cf4e 100644 --- a/Makefile +++ b/Makefile @@ -24,6 +24,7 @@ endif CFLAGS = -g -c -fno-builtin -m32 -DBUILDER='"$(shell whoami)"' +CFLAGS += -DNR_TTYS=3 CFLAGS += -DFIX_SYSENTER_ESP_MODE=1 #CFLAGS += -DENABLE_BOOT_WAIT=1 SYSTEMMAP = System.map diff --git a/drivers/ata.c b/drivers/ata.c index f2db975..e7422e1 100644 --- a/drivers/ata.c +++ b/drivers/ata.c @@ -15,22 +15,14 @@ #include #include -extern ide_pci_controller_t ide_pci_controller; +extern ide_pci_controller_t ide_pci_controller[]; -typedef struct _ide_drive { - int present; - int dma; - uint64_t lba48; - uint64_t max_lba; -} ide_drive_t; - -#define MAX_IDE_DRIVE_CNT 4 ide_drive_t ide_drives[MAX_IDE_DRIVE_CNT]; #define ATA_TIMEOUT 10 // 10次时钟中断 -void ata_dma_read_ext(int dev, uint64_t pos, uint16_t count, void *dest); -int ata_pio_read_ext(int dev, uint64_t pos, uint16_t count, int timeout, void *dest); +void ata_dma_read_ext(int drv, uint64_t pos, uint16_t count, void *dest); +int ata_pio_read_ext(int drv, uint64_t pos, uint16_t count, int timeout, void *dest); void *mbr_buf; void ata_test(uint64_t nr) { @@ -53,19 +45,19 @@ void ata_test(uint64_t nr) { // 2. 等到status的BSY位清除 // 3. 等到status的DRQ位或ERR位设置 u16 identify[256]; -void ata_send_read_identify_cmd(int dev) {} +void ata_send_read_identify_cmd(int drv) {} -void ata_read_data(int dev, int sect_cnt, void *dst) { insl(REG_DATA(dev), dst, (512 * sect_cnt) / sizeof(uint32_t)); } +void ata_read_data(int drv, int sect_cnt, void *dst) { insl(REG_DATA(drv), dst, (512 * sect_cnt) / sizeof(uint32_t)); } -// 这里所用的dev是逻辑编号 ATA0、ATA1下的Master、Salve的dev分别为0,1,2,3 -void ata_read_identify(int dev, int disable_intr) { +// 这里所用的drv是逻辑编号 ATA0、ATA1下的Master、Salve的drv分别为0,1,2,3 +void ata_read_identify(int drv, int disable_intr) { uint8_t ctlv = 0x00; if (disable_intr != 0) { ctlv |= ATA_CTL_NIEN; } - outb(ctlv, REG_CTL(dev)); - outb(0x00 | ((dev & 0x01) << 4), REG_DEVICE(dev)); // 根据文档P113,这里不用指定bit5, bit7,直接指示DRIVE就行 - outb(ATA_CMD_IDENTIFY, REG_CMD(dev)); + outb(ctlv, REG_CTL(drv)); + outb(0x00 | ((drv & 0x01) << 4), REG_DEVICE(drv)); // 根据文档P113,这里不用指定bit5, bit7,直接指示DRIVE就行 + outb(ATA_CMD_IDENTIFY, REG_CMD(drv)); } void ata_read_identity_string(const uint16_t *identify, int bgn, int end, char *buf) { @@ -82,9 +74,17 @@ void ata_read_identity_string(const uint16_t *identify, int bgn, int end, char * // 《AT Attachment 8 - ATA/ATAPI Command Set》 void ide_ata_init() { for (int i = 0; i < MAX_IDE_DRIVE_CNT; i++) { - int dev = i; + int drv_no = i; memset(ide_drives + i, 0, sizeof(ide_drive_t)); + ide_drive_t *drv = ide_drives + drv_no; + + INIT_MUTEX(&drv->request_mutex); + + drv->request_queue.count = 0; + INIT_LIST_HEAD(&drv->request_queue.list); + semaphore_init(&drv->request_queue.sem, 0); + // https://wiki.osdev.org/ATA_PIO_Mode // To use the IDENTIFY command, select a target drive by sending 0xA0 for the master drive, or 0xB0 for the // slave, to the "drive select" IO port. On the Primary bus, this would be port 0x1F6. Then set the Sectorcount, @@ -117,9 +117,9 @@ void ide_ata_init() { // 2. 等到status的BSY位清除 // 3. 等到status的DRQ位或ERR位设置 - ata_read_identify(dev, 1); + ata_read_identify(drv_no, 1); - uint8_t status = inb(REG_STATUS(dev)); + uint8_t status = inb(REG_STATUS(drv_no)); if (status == 0 || (status & ATA_STATUS_ERR) || (status & ATA_STATUS_RDY == 0)) { ide_drives[i].present = 0; continue; @@ -128,7 +128,7 @@ void ide_ata_init() { } printk("ata[%d] status %x %s exists\n", i, status, ide_drives[i].present == 1 ? "" : "not"); - insl(REG_DATA(dev), identify, SECT_SIZE / sizeof(uint32_t)); + insl(REG_DATA(drv_no), identify, SECT_SIZE / sizeof(uint32_t)); // 第49个word的第8个bit位表示是否支持DMA // 第83个word的第10个bit位表示是否支持LBA48,为1表示支持。 @@ -196,11 +196,12 @@ void ide_ata_init() { } } +#if 0 void ata_init() { // 初始化hard_disk与中断函数之间的信号量 disk_request_t r; - r.dev = 0; + r.drv = 0; r.buf = (void *)identify; r.count = 1; r.pos = 0; @@ -238,9 +239,10 @@ void ata_init() { printd("%04x.", p[i]); } } +#endif // ATA_CMD_READ_DMA_EXT -void ata_dma_read_ext(int dev, uint64_t pos, uint16_t count, void *dest) { +void ata_dma_read_ext(int drv, uint64_t pos, uint16_t count, void *dest) { // Intel® // 82801CA (ICH3), 82801BA // (ICH2), 82801AA (ICH), and 82801AB @@ -259,8 +261,12 @@ void ata_dma_read_ext(int dev, uint64_t pos, uint16_t count, void *dest) { // by writing a 0 to this bit. This results in all state information being lost (i.e., master mode // operation cannot be stopped and then resumed). + int channel = (drv >> 1) & 0x01; + assert(channel == 0 || channel == 1); + ide_pci_controller_t *pci = ide_pci_controller + channel; + // 停止DMA - outb(PCI_IDE_CMD_STOP, ide_pci_controller.bus_cmd); + outb(PCI_IDE_CMD_STOP, pci->bus_cmd); // 配置描述符表 unsigned long dest_paddr = va2pa(dest); @@ -270,75 +276,78 @@ void ata_dma_read_ext(int dev, uint64_t pos, uint16_t count, void *dest) { const uint32_t _64K = 1 << 16; assert(((dest_paddr + size) & _64K) == (dest_paddr & _64K)); - ide_pci_controller.prdt[0].phys_addr = dest_paddr; - ide_pci_controller.prdt[0].byte_count = size; - ide_pci_controller.prdt[0].reserved = 0; - ide_pci_controller.prdt[0].eot = 1; - outl(va2pa(ide_pci_controller.prdt), ide_pci_controller.bus_prdt); + pci->prdt[0].phys_addr = dest_paddr; + pci->prdt[0].byte_count = size; + pci->prdt[0].reserved = 0; + pci->prdt[0].eot = 1; + outl(va2pa(pci->prdt), pci->bus_prdt); - // printk("paddr: %x prdt: %x %x prdte %x %x\n", dest_paddr, ide_pci_controller.prdt, - // va2pa(ide_pci_controller.prdt), - // ide_pci_controller.prdt[0].phys_addr, *(((unsigned int *)ide_pci_controller.prdt) + 1)); + // printk("paddr: %x prdt: %x %x prdte %x %x\n", dest_paddr, pci->prdt, + // va2pa(pci->prdt), + // pci->prdt[0].phys_addr, *(((unsigned int *)pci->prdt) + 1)); // 清除中断位和错误位 // 这里清除的方式是是设置1后清除 - outb(PCI_IDE_STATUS_INTR | PCI_IDE_STATUS_ERR, ide_pci_controller.bus_status); + outb(PCI_IDE_STATUS_INTR | PCI_IDE_STATUS_ERR, pci->bus_status); // 不再设置nIEN,DMA需要中断 - outb(0x00, REG_CTL(dev)); + outb(0x00, REG_CTL(drv)); // 等待硬盘不BUSY - while (inb(REG_STATUS(dev)) & ATA_STATUS_BSY) { + while (inb(REG_STATUS(drv)) & ATA_STATUS_BSY) { nop(); } // 选择DRIVE - outb(ATA_LBA48_DEVSEL(dev), REG_DEVICE(dev)); + outb(ATA_LBA48_DEVSEL(drv), REG_DEVICE(drv)); // 先写扇区数的高字节 - outb((count >> 8) & 0xFF, REG_NSECTOR(dev)); + outb((count >> 8) & 0xFF, REG_NSECTOR(drv)); // 接着写LBA48,高三个字节 - outb((pos >> 24) & 0xFF, REG_LBAL(dev)); - outb((pos >> 32) & 0xFF, REG_LBAM(dev)); - outb((pos >> 40) & 0xFF, REG_LBAH(dev)); + outb((pos >> 24) & 0xFF, REG_LBAL(drv)); + outb((pos >> 32) & 0xFF, REG_LBAM(drv)); + outb((pos >> 40) & 0xFF, REG_LBAH(drv)); // 再写扇区数的低字节 - outb((count >> 0) & 0xFF, REG_NSECTOR(dev)); + outb((count >> 0) & 0xFF, REG_NSECTOR(drv)); // 接着写LBA48,低三个字节 - outb((pos >> 0) & 0xFF, REG_LBAL(dev)); - outb((pos >> 8) & 0xFF, REG_LBAM(dev)); - outb((pos >> 16) & 0xFF, REG_LBAH(dev)); + outb((pos >> 0) & 0xFF, REG_LBAL(drv)); + outb((pos >> 8) & 0xFF, REG_LBAM(drv)); + outb((pos >> 16) & 0xFF, REG_LBAH(drv)); // 等待硬盘READY - while (inb(REG_STATUS(dev)) & ATA_STATUS_RDY == 0) { + while (inb(REG_STATUS(drv)) & ATA_STATUS_RDY == 0) { nop(); } - outb(ATA_CMD_READ_DMA_EXT, REG_CMD(dev)); + outb(ATA_CMD_READ_DMA_EXT, REG_CMD(drv)); // 这一句非常重要,如果不加这一句 // 在qemu中用DMA的方式读数据就会读不到数据,而只触是发中断,然后寄存器(Bus Master IDE Status // Register)的值会一直是5 也就是INTERRUPT和和ACTIVE位是1,正常应该是4,也就是只有INTERRUPT位为1 // 在bochs中则加不加这一句不会有影响,都能正常读到数据 - unsigned int v = pci_read_config_word(pci_cmd(ide_pci_controller.pci, PCI_COMMAND)); + unsigned int v = pci_read_config_word(pci_cmd(pci->pci, PCI_COMMAND)); // printk(" ide pci command %04x\n", v); - pci_write_config_word(v | PCI_COMMAND_MASTER, pci_cmd(ide_pci_controller.pci, PCI_COMMAND)); + pci_write_config_word(v | PCI_COMMAND_MASTER, pci_cmd(pci->pci, PCI_COMMAND)); + // pci_write_config_word(v, pci_cmd(pci->pci, PCI_COMMAND)); // 指定DMA操作为读取硬盘操作,内核用DMA读取,对硬盘而言是写出 // 并设置DMA的开始位,开始DMA - outb(PCI_IDE_CMD_WRITE | PCI_IDE_CMD_START, ide_pci_controller.bus_cmd); + outb(PCI_IDE_CMD_WRITE | PCI_IDE_CMD_START, pci->bus_cmd); } // TODO -int ata_dma_stop() { - uint8_t x = inb(ide_pci_controller.bus_cmd); +int ata_dma_stop(int channel) { + ide_pci_controller_t *pci = ide_pci_controller + channel; + + uint8_t x = inb(pci->bus_cmd); x &= ~PCI_IDE_CMD_START; - outb(x, ide_pci_controller.bus_cmd); + outb(x, pci->bus_cmd); - uint8_t status = inb(ide_pci_controller.bus_status); - outb(status | PCI_IDE_STATUS_INTR | PCI_IDE_STATUS_ERR, ide_pci_controller.bus_status); + uint8_t status = inb(pci->bus_status); + outb(status | PCI_IDE_STATUS_INTR | PCI_IDE_STATUS_ERR, pci->bus_status); // TODO if (status & PCI_IDE_STATUS_ERR) { @@ -349,44 +358,44 @@ int ata_dma_stop() { } // ATA_CMD_READ_PIO_EXT -int ata_pio_read_ext(int dev, uint64_t pos, uint16_t count, int timeout, void *dest) { +int ata_pio_read_ext(int drv, uint64_t pos, uint16_t count, int timeout, void *dest) { // PIO读,禁用中断 - outb(ATA_CTL_NIEN, REG_CTL(dev)); + outb(ATA_CTL_NIEN, REG_CTL(drv)); // 等待硬盘不BUSY - while (inb(REG_STATUS(dev)) & ATA_STATUS_BSY) { + while (inb(REG_STATUS(drv)) & ATA_STATUS_BSY) { nop(); } // 选择DRIVE - outb(ATA_LBA48_DEVSEL(dev), REG_DEVICE(dev)); + outb(ATA_LBA48_DEVSEL(drv), REG_DEVICE(drv)); // 先写扇区数的高字节 - outb((count >> 8) & 0xFF, REG_NSECTOR(dev)); + outb((count >> 8) & 0xFF, REG_NSECTOR(drv)); // 接着写LBA48,高三个字节q - outb((pos >> 24) & 0xFF, REG_LBAL(dev)); - outb((pos >> 32) & 0xFF, REG_LBAM(dev)); - outb((pos >> 40) & 0xFF, REG_LBAH(dev)); + outb((pos >> 24) & 0xFF, REG_LBAL(drv)); + outb((pos >> 32) & 0xFF, REG_LBAM(drv)); + outb((pos >> 40) & 0xFF, REG_LBAH(drv)); // 再写扇区数的低字节 - outb((count >> 0) & 0xFF, REG_NSECTOR(dev)); + outb((count >> 0) & 0xFF, REG_NSECTOR(drv)); // 接着写LBA48,低三个字节 - outb((pos >> 0) & 0xFF, REG_LBAL(dev)); - outb((pos >> 8) & 0xFF, REG_LBAM(dev)); - outb((pos >> 16) & 0xFF, REG_LBAH(dev)); + outb((pos >> 0) & 0xFF, REG_LBAL(drv)); + outb((pos >> 8) & 0xFF, REG_LBAM(drv)); + outb((pos >> 16) & 0xFF, REG_LBAH(drv)); - while (inb(REG_STATUS(dev)) & ATA_STATUS_RDY == 0) { + while (inb(REG_STATUS(drv)) & ATA_STATUS_RDY == 0) { nop(); } - outb(ATA_CMD_READ_PIO_EXT, REG_CMD(dev)); + outb(ATA_CMD_READ_PIO_EXT, REG_CMD(drv)); while (timeout > 0) { timeout--; - u8 status = inb(REG_STATUS(dev)); + u8 status = inb(REG_STATUS(drv)); if ((status & ATA_STATUS_BSY) == 0 && (status & ATA_STATUS_DRQ) != 0) { break; } @@ -399,22 +408,16 @@ int ata_pio_read_ext(int dev, uint64_t pos, uint16_t count, int timeout, void *d return -1; } - insl(REG_DATA(dev), dest, (SECT_SIZE * count) / sizeof(uint32_t)); + insl(REG_DATA(drv), dest, (SECT_SIZE * count) / sizeof(uint32_t)); return 0; } -uint8_t ata_pci_bus_status() { - uint8_t st = 0; - st = inb(ide_pci_controller.bus_status); - - outb(PCI_IDE_STATUS_INTR, ide_pci_controller.bus_status); - - return st; -} +// uint8_t ata_pci_bus_status() { +// uint8_t st = 0; +// st = inb(ide_pci_controller.bus_status); -unsigned int ATA_CHL0_CMD_BASE = 0x1F0; -unsigned int ATA_CHL1_CMD_BASE = 0x170; +// outb(PCI_IDE_STATUS_INTR, ide_pci_controller.bus_status); -unsigned int ATA_CHL0_CTL_BASE = 0x3F6; -unsigned int ATA_CHL1_CTL_BASE = 0x376; +// return st; +// } diff --git a/drivers/ata.h b/drivers/ata.h index e0f71d1..e62aee3 100644 --- a/drivers/ata.h +++ b/drivers/ata.h @@ -9,8 +9,8 @@ #pragma once -extern unsigned int ATA_CHL0_CMD_BASE; -extern unsigned int ATA_CHL1_CMD_BASE; +extern unsigned int IDE_CHL0_CMD_BASE; +extern unsigned int IDE_CHL1_CMD_BASE; // CTL其实不用BASE,只有一个寄存器 // 这么写纯粹是为了代码好看 @@ -20,8 +20,8 @@ extern unsigned int ATA_CHL1_CMD_BASE; // bit2: SRST Software Reset // bit1: IEN disable Interrupt // bit0: 0 -extern unsigned int ATA_CHL0_CTL_BASE; -extern unsigned int ATA_CHL1_CTL_BASE; +extern unsigned int IDE_CHL0_CTL_BASE; +extern unsigned int IDE_CHL1_CTL_BASE; #define ATA_DATA 0 @@ -47,7 +47,7 @@ extern unsigned int ATA_CHL1_CTL_BASE; // bit5: Obsolete // bit4: DRIVE // bit[0, 3] HS 如果L为0就是磁头号Head Number,如果L为1,则为LBA的24-27位 -#define ATA_LBA48_DEVSEL(dev) (0x40 | ((dev & 0x01) << 4)) +#define ATA_LBA48_DEVSEL(drv) (0x40 | ((drv & 0x01) << 4)) #define ATA_DEVICE 6 #define ATA_CMD 7 @@ -95,24 +95,24 @@ extern unsigned int ATA_CHL1_CTL_BASE; #define ATA_CTL_SRST 0x04 /* soft reset controller */ #define ATA_CTL_NIEN 0x02 /* disable interrupts */ -#define ATA_GET_CHL(dev) (((dev) >> 1) & 0x01) -#define ATA_GET_DEV(dev) (((dev) >> 1) & 0x01) +#define ATA_GET_CHL(drv) (((drv) >> 1) & 0x01) +#define ATA_GET_DEV(drv) (((drv) >> 1) & 0x01) -#define REG_CMD_BASE(dev, offset) (ATA_GET_CHL(dev) ? (ATA_CHL1_CMD_BASE + offset) : (ATA_CHL0_CMD_BASE + offset)) -#define REG_CTL_BASE(dev, offset) (ATA_GET_CHL(dev) ? (ATA_CHL1_CTL_BASE + offset) : (ATA_CHL0_CTL_BASE + offset)) +#define REG_CMD_BASE(drv, offset) (ATA_GET_CHL(drv) ? (IDE_CHL1_CMD_BASE + offset) : (IDE_CHL0_CMD_BASE + offset)) +#define REG_CTL_BASE(drv, offset) (ATA_GET_CHL(drv) ? (IDE_CHL1_CTL_BASE + offset) : (IDE_CHL0_CTL_BASE + offset)) -#define REG_DATA(dev) REG_CMD_BASE(dev, ATA_DATA) -#define REG_ERR(dev) REG_CMD_BASE(dev, ATA_ERR) -#define REG_NSECTOR(dev) REG_CMD_BASE(dev, ATA_NSECTOR) -#define REG_LBAL(dev) REG_CMD_BASE(dev, ATA_LBAL) -#define REG_LBAM(dev) REG_CMD_BASE(dev, ATA_LBAM) -#define REG_LBAH(dev) REG_CMD_BASE(dev, ATA_LBAH) -#define REG_DEVICE(dev) REG_CMD_BASE(dev, ATA_DEVICE) -#define REG_STATUS(dev) REG_CMD_BASE(dev, ATA_STATUS) -#define REG_FEATURES(dev) REG_CMD_BASE(dev, ATA_FEATURES) +#define REG_DATA(drv) REG_CMD_BASE(drv, ATA_DATA) +#define REG_ERR(drv) REG_CMD_BASE(drv, ATA_ERR) +#define REG_NSECTOR(drv) REG_CMD_BASE(drv, ATA_NSECTOR) +#define REG_LBAL(drv) REG_CMD_BASE(drv, ATA_LBAL) +#define REG_LBAM(drv) REG_CMD_BASE(drv, ATA_LBAM) +#define REG_LBAH(drv) REG_CMD_BASE(drv, ATA_LBAH) +#define REG_DEVICE(drv) REG_CMD_BASE(drv, ATA_DEVICE) +#define REG_STATUS(drv) REG_CMD_BASE(drv, ATA_STATUS) +#define REG_FEATURES(drv) REG_CMD_BASE(drv, ATA_FEATURES) -#define REG_CMD(dev) REG_CMD_BASE(dev, ATA_CMD) -#define REG_CTL(dev) REG_CTL_BASE(dev, ATA_CTL) +#define REG_CMD(drv) REG_CMD_BASE(drv, ATA_CMD) +#define REG_CTL(drv) REG_CTL_BASE(drv, ATA_CTL) #define ATA_IDENT_DEVTYPE 0 #define ATA_IDENT_CYLINDERS 2 diff --git a/drivers/ide.c b/drivers/ide.c index 6b97d0d..837eb00 100644 --- a/drivers/ide.c +++ b/drivers/ide.c @@ -13,14 +13,16 @@ #include #include -ide_pci_controller_t ide_pci_controller; +ide_pci_controller_t ide_pci_controller[NR_IDE_CONTROLLER]; -extern unsigned int ATA_CHL0_CMD_BASE; -extern unsigned int ATA_CHL1_CMD_BASE; +unsigned int IDE_CHL0_CMD_BASE = 0x1F0; +unsigned int IDE_CHL1_CMD_BASE = 0x170; -extern unsigned int ATA_CHL0_CTL_BASE; -extern unsigned int ATA_CHL1_CTL_BASE; +unsigned int IDE_CHL0_CTL_BASE = 0x3F6; +unsigned int IDE_CHL1_CTL_BASE = 0x376; +// 《PCI IDE Controller Specification》 +// 《Programming Interface for Bus Master IDE Controller》 void ide_pci_init(pci_device_t *pci) { unsigned int v; @@ -28,37 +30,38 @@ void ide_pci_init(pci_device_t *pci) { // printk(" ide pci command %04x\n", v); v = pci_read_config_byte(pci_cmd(pci, PCI_PROGIF)); - printk(" ide pci program interface %02x\n", v); + printd("ide pci program interface %02x\n", v); unsigned int iobase = pci_read_config_long(pci_cmd(pci, PCI_BAR4)); - printk(" ide pci Base IO Address Register %08x\n", iobase); - iobase &= 0xFFFC; // 最低为0是内存地址为1是端口地址 - ide_pci_controller.bus_iobase = iobase; - ide_pci_controller.bus_cmd = iobase + PCI_IDE_CMD; - ide_pci_controller.bus_status = iobase + PCI_IDE_STATUS; - ide_pci_controller.bus_prdt = iobase + PCI_IDE_PRDT; - ide_pci_controller.prdt = (prdte_t *)alloc_one_page(0); - - int i; - printk(" BARS: "); - for (i = 0; i < BARS_CNT; ++i) { - printk("%08x ", pci->bars[i]); - pci->bars[i] &= (~1UL); - } - printk("\n"); - ATA_CHL0_CMD_BASE = pci->bars[0] ? pci->bars[0] : ATA_CHL0_CMD_BASE; - ATA_CHL0_CTL_BASE = pci->bars[1] ? pci->bars[1] : ATA_CHL0_CTL_BASE; + for (int i = 0; i < NR_IDE_CONTROLLER; i++) { + iobase += i * 8; // secondary channel 需要加8 + printd("ide pci Base IO Address Register %08x\n", iobase); + iobase &= 0xFFFC; // 最低为0是内存地址为1是端口地址 + ide_pci_controller[i].bus_iobase = iobase; + ide_pci_controller[i].bus_cmd = iobase + PCI_IDE_CMD; + ide_pci_controller[i].bus_status = iobase + PCI_IDE_STATUS; + ide_pci_controller[i].bus_prdt = iobase + PCI_IDE_PRDT; + ide_pci_controller[i].prdt = (prdte_t *)alloc_one_page(0); + + printd("BARS: "); + for (int j = 0; j < BARS_CNT; ++j) { + printd("%08x ", pci->bars[j]); + pci->bars[j] &= (~1UL); + } + printd("\n"); + + ide_pci_controller[i].pci = pci; + } - ATA_CHL1_CMD_BASE = pci->bars[2] ? pci->bars[2] : ATA_CHL1_CMD_BASE; - ATA_CHL1_CTL_BASE = pci->bars[3] ? pci->bars[3] : ATA_CHL1_CTL_BASE; + IDE_CHL0_CMD_BASE = pci->bars[0] ? pci->bars[0] : IDE_CHL0_CMD_BASE; + IDE_CHL0_CTL_BASE = pci->bars[1] ? pci->bars[1] : IDE_CHL0_CTL_BASE; - ide_pci_controller.pci = pci; + IDE_CHL1_CMD_BASE = pci->bars[2] ? pci->bars[2] : IDE_CHL1_CMD_BASE; + IDE_CHL1_CTL_BASE = pci->bars[3] ? pci->bars[3] : IDE_CHL1_CTL_BASE; - printd("channel0: cmd %04x ctl %04x channel1: cmd %04x ctl %04x\n", ATA_CHL0_CMD_BASE, ATA_CHL0_CTL_BASE, - ATA_CHL1_CMD_BASE, ATA_CHL1_CTL_BASE); - // printl(18, "channel0: cmd %04x ctl %04x channel1: cmd %04x ctl %04x", HD_CHL0_CMD_BASE, HD_CHL0_CTL_BASE, - // HD_CHL1_CMD_BASE, HD_CHL1_CTL_BASE); + printd("ide channel 0: cmd %04x ctl %04x\n", IDE_CHL0_CMD_BASE, IDE_CHL0_CTL_BASE); + printd("ide channel 1: cmd %04x ctl %04x\n", IDE_CHL1_CMD_BASE, IDE_CHL1_CTL_BASE); } // void ide_status() { @@ -82,6 +85,11 @@ void ide_pci_init(pci_device_t *pci) { const char *pci_get_info(unsigned int classcode, unsigned int progif); void init_pci_controller(unsigned int classcode) { pci_device_t *pci = pci_find_device_by_classcode(classcode); + if (pci == NULL) { + printk("can not find pci classcode: %08x", classcode); + panic("can not find ide controller"); + } + assert(pci->intr_line < 16); if (pci != 0 && pci->intr_line < 16) { printk("found pci %03d:%02d.%d #%02d %04X:%04X ProgIF %02x %s\n", pci->bus, pci->dev, pci->devfn, pci->intr_line, pci->vendor, pci->device, pci->progif, pci_get_info(pci->classcode, pci->progif)); @@ -98,7 +106,6 @@ void init_pci_controller(unsigned int classcode) { extern semaphore_t disk_intr_sem; extern void *mbr_buf; -extern ide_pci_controller_t ide_pci_controller; extern uint32_t disk_request_cnt; extern uint32_t disk_handled_cnt; @@ -106,12 +113,15 @@ uint8_t ata_pci_bus_status(); volatile uint32_t disk_inter_cnt = 0; -void ide_irq_bh_handler() { +void ata_dma_stop(int channel); +void ide_irq_bh_handler(void *arg) { disk_inter_cnt++; + int channel = (int)arg; + // printl(MPL_IDE, "disk req %u consumed %u irq %u", disk_request_cnt, disk_handled_cnt, disk_inter_cnt); printlxy(MPL_IDE, MPO_IDE, "disk irq %u req %u consumed %u ", disk_inter_cnt, disk_request_cnt, disk_handled_cnt); - ata_dma_stop(); + // up里不会立即重新调度进程 up(&disk_intr_sem); } @@ -119,18 +129,27 @@ void ide_irq_bh_handler() { void ide_irq_handler(unsigned int irq, pt_regs_t *regs, void *devid) { // printk("ide irq %d handler pci status: 0x%02x\n", irq, ata_pci_bus_status()); - add_irq_bh_handler(ide_irq_bh_handler); + int channel = irq == 14 ? 0 : 1; + ata_dma_stop(channel); + + add_irq_bh_handler(ide_irq_bh_handler, &channel); } +void ide1_irq_handler(unsigned int irq, pt_regs_t *regs, void *devid) { panic("ide 0"); } + +void ide_ata_init(); void ide_init() { - // memset((void *)&drv, 0, sizeof(drv)); - memset(&ide_pci_controller, 0, sizeof(ide_pci_controller)); + memset(ide_pci_controller, 0, sizeof(ide_pci_controller[0]) * NR_IDE_CONTROLLER); + + // 读PCI里 IDE相关寄存器的配置 + // init_pci_controller(0x0106); + init_pci_controller(0x0101); + // init_pci_controller(0x7010); - void ide_ata_init(); + // 读IDE 硬盘的identity ide_ata_init(); request_irq(0x0E, ide_irq_handler, "hard", "IDE"); - // init_pci_controller(0x0106); - init_pci_controller(0x0101); + request_irq(0x0F, ide_irq_handler, "hard", "IDE"); } diff --git a/drivers/ide.h b/drivers/ide.h index 46df6c0..1a63a92 100644 --- a/drivers/ide.h +++ b/drivers/ide.h @@ -9,7 +9,9 @@ #pragma once +#include #include +#include #include #include @@ -181,5 +183,21 @@ typedef struct _ide_pci_controller { int done; } ide_pci_controller_t; +#define NR_IDE_CONTROLLER 2 + +typedef struct _ide_drive { + int present; + int dma; + uint64_t lba48; + uint64_t max_lba; + + semaphore_t request_mutex; + + disk_request_queue_t request_queue; +} ide_drive_t; + +#define MAX_IDE_DRIVE_CNT 4 +extern ide_drive_t ide_drives[MAX_IDE_DRIVE_CNT]; + void sleep_on_ide(); -void wait_on_ide(); \ No newline at end of file +void wait_on_ide(); diff --git a/drivers/keyboard.c b/drivers/keyboard.c index e1f729a..e26b6f5 100644 --- a/drivers/keyboard.c +++ b/drivers/keyboard.c @@ -54,7 +54,7 @@ char kbd_char_tbl[] = { // TODO 改造成环形缓冲区 uint8_t scan_code; -void kbd_bh_handler() { +void kbd_bh_handler(void *arg) { kbd_debug(scan_code); if (0x80 & scan_code) { // break code return; @@ -66,7 +66,7 @@ void kbd_bh_handler() { void kbd_handler(unsigned int irq, pt_regs_t *regs, void *dev_id) { scan_code = inb(0x60); - add_irq_bh_handler(kbd_bh_handler); + add_irq_bh_handler(kbd_bh_handler, NULL); } extern tty_t *const default_tty; diff --git a/drivers/pci.c b/drivers/pci.c index 4c35d0a..21718d1 100644 --- a/drivers/pci.c +++ b/drivers/pci.c @@ -153,7 +153,7 @@ void dump_pci_dev() { // pci->progif, pci->bus, pci->intr_line); // printk("%s\n", pci_get_info(pci->classcode, pci->progif)); printk("PCI %03d:%02d.%d #%02d %04X:%04X %s\n", pci->bus, pci->dev, pci->devfn, pci->intr_line, pci->vendor, - pci->device, pci_get_info(pci->classcode, pci->progif)); + pci->classcode, pci_get_info(pci->classcode, pci->progif)); #if 0 switch (pci->hdr_type) { case PCI_HDRTYPE_NORMAL: @@ -228,6 +228,9 @@ void setup_pci() { } dump_pci_dev(); + + // while (1) + // ; } typedef struct pci_info { diff --git a/include/disk.h b/include/disk.h index 6e56080..d542349 100644 --- a/include/disk.h +++ b/include/disk.h @@ -20,7 +20,7 @@ typedef enum { } disk_request_cmd_t; typedef struct disk_request { - int dev; + dev_t dev; uint64_t pos; // 扇区号 uint16_t count; // 扇区数 void *buf; // 到的缓冲区 @@ -43,4 +43,4 @@ typedef struct { list_head_t list; } disk_request_queue_t; -void send_disk_request(disk_request_t *r); \ No newline at end of file +void send_disk_request(disk_request_t *r); diff --git a/include/irq.h b/include/irq.h index c96eae4..bec6002 100644 --- a/include/irq.h +++ b/include/irq.h @@ -46,6 +46,7 @@ typedef struct irq_desc { typedef struct irq_bh_action { void (*handler)(); + void *arg; struct irq_bh_action *next; } irq_bh_action_t; @@ -56,7 +57,7 @@ int request_irq(unsigned int irq, // void (*handler)(pt_regs_t *, unsigned int), void (*handler)(unsigned int, pt_regs_t *, void *), const char *devname, void *dev_id); -void add_irq_bh_handler(void (*handler)()); +void add_irq_bh_handler(void (*handler)(), void *arg); int open_irq(unsigned int irq); int close_irq(unsigned int irq); diff --git a/include/semaphore.h b/include/semaphore.h index 72f6a52..70d86ec 100644 --- a/include/semaphore.h +++ b/include/semaphore.h @@ -33,5 +33,11 @@ void down(semaphore_t *s); void up(semaphore_t *s); #define DECLARE_MUTEX(name) semaphore_t name = SEMAPHORE_INITIALIZER(name, 1) + +#define INIT_MUTEX(ptr) \ + do { \ + (ptr)->cnt = 1; \ + INIT_LIST_HEAD(&((ptr)->wait_list)); \ + } while (0) void mutex_lock(semaphore_t *); void mutex_unlock(semaphore_t *); diff --git a/include/system.h b/include/system.h index d353804..9189c40 100644 --- a/include/system.h +++ b/include/system.h @@ -139,7 +139,7 @@ typedef struct pt_regs { u16 ss, _ss; } __attribute__((packed)) pt_regs_t; -typedef unsigned long dev_t; +typedef uint32_t dev_t; typedef struct system { u32 mmap_addr; diff --git a/kernel/clock.c b/kernel/clock.c index 3921de5..438386a 100644 --- a/kernel/clock.c +++ b/kernel/clock.c @@ -23,7 +23,8 @@ unsigned int sys_clock() { return jiffies; } void debug_print_all_tasks(); void dump_irq_nr_stack(); -void clk_bh_handler(); +void clk_bh_handler(void *arg); + void clk_handler(unsigned int irq, pt_regs_t *regs, void *dev_id) { // if (jiffies % 100 == 0) { // printl(MPL_CLOCK, "clock irq: %d", jiffies); @@ -45,13 +46,13 @@ void clk_handler(unsigned int irq, pt_regs_t *regs, void *dev_id) { assert(current->ticks <= TASK_MAX_PRIORITY); // 防止ticks被减到0后再减溢出 - add_irq_bh_handler(clk_bh_handler); + add_irq_bh_handler(clk_bh_handler, NULL); } // 开中断执行这个函数 // 后续放到一个内核任务中去做,需要先把禁止内核抢占做了 const char *task_state(unsigned int state); -void clk_bh_handler() { +void clk_bh_handler(void *arg) { task_union *p = 0; list_head_t *t = 0; list_head_t *pos = 0; @@ -60,7 +61,7 @@ void clk_bh_handler() { // printk("%s state: %s\n", p->name, task_state(p->state)); assert(p->state == TASK_WAIT); assert(p->delay_jiffies != 0); - if (jiffies > p->delay_jiffies) { + if (p->delay_jiffies > 0 && jiffies > p->delay_jiffies) { list_del(&p->pend); p->delay_jiffies = 0; p->state = TASK_READY; diff --git a/kernel/irq.c b/kernel/irq.c index 4517a85..b828694 100644 --- a/kernel/irq.c +++ b/kernel/irq.c @@ -162,7 +162,7 @@ void irq_bh_handler() { } while (action != NULL) { - action->handler(); + action->handler(action->arg); irq_bh_action_t *p = action; action = action->next; kfree(p); @@ -218,7 +218,7 @@ int request_irq(unsigned int irq, void (*handler)(unsigned int, pt_regs_t *, voi return 0; } -void add_irq_bh_handler(void (*handler)()) { +void add_irq_bh_handler(void (*handler)(), void *arg) { // 只能在中断处理函数中调用 assert(irq_disabled()); @@ -227,12 +227,12 @@ void add_irq_bh_handler(void (*handler)()) { assert(p != NULL); p->handler = handler; + p->arg = arg; if (irq_bh_actions_end == NULL) { assert(irq_bh_actions == NULL); irq_bh_actions = p; irq_bh_actions_end = p; - } else { assert(irq_bh_actions != NULL); irq_bh_actions_end->next = p; diff --git a/kernel/sched.c b/kernel/sched.c index 54fab03..b710ee3 100644 --- a/kernel/sched.c +++ b/kernel/sched.c @@ -166,10 +166,10 @@ const char *task_state(unsigned int state) { void debug_print_all_tasks() { task_union *p = 0; list_head_t *pos = 0, *t = 0; - printl(MPL_TASK_TITLE, " NAME STATE TK/PI TURN SCHED KEEP"); + printl(MPL_TASK_TITLE, " NAME STATE TK/PI TURN SCHED KEEP"); list_for_each_safe(pos, t, &all_tasks) { p = list_entry(pos, task_union, list); - printl(MPL_TASK_0 + p->pid, "%08x%s%4s:%u %s %02u/%02u %-10u %-10u %-10u", p, + printl(MPL_TASK_0 + p->pid, "%08x%s%-6s:%u %s %02u/%02u %-10u %-10u %-10u", p, p->state == TASK_RUNNING ? ">" : " ", p->name, p->pid, task_state(p->state), p->ticks, p->priority, p->turn, p->sched_cnt, p->sched_keep_cnt); } @@ -245,6 +245,7 @@ void schedule() { } assert(current->state == TASK_RUNNING); + irq_restore(iflags); } diff --git a/kernel/setup.c b/kernel/setup.c index a410fe3..8b2aa57 100644 --- a/kernel/setup.c +++ b/kernel/setup.c @@ -80,7 +80,7 @@ void setup_kernel() { boot_delay(DEFAULT_BOOT_DELAY_TICKS); extern tty_t *const monitor_tty; - // tty_switch(monitor_tty); + tty_switch(monitor_tty); boot_delay(DEFAULT_BOOT_DELAY_TICKS); @@ -90,11 +90,3 @@ void setup_kernel() { void ide_init(); ide_init(); } - -// 在开中断的情况下继续初始化的内容 -void setup_under_irq() { - void ata_init(); - ata_init(); - return; - setup_fs(); -} diff --git a/kernel/syscall.S b/kernel/syscall.S index 6f204cf..15906f0 100644 --- a/kernel/syscall.S +++ b/kernel/syscall.S @@ -95,10 +95,13 @@ ret_from_fork_krnl: popfl // EFLAGS addl $8, %esp // ESP SS + pushl %ecx call *%edx addl $4, %esp // CALL PUSH EIP + addl $4, %esp // ecx: arg + // TODO // add exit here diff --git a/kernel/system.c b/kernel/system.c index 124d6f2..1717762 100644 --- a/kernel/system.c +++ b/kernel/system.c @@ -134,7 +134,7 @@ void setup_irqs() { request_irq(0x01, kbd_handler, "Intel 8042", "PS/2 Keyboard"); // request_irq(0x0E, default_ide_irq_handler, "hard", "IDE"); for (int i = 0; i < 16; i++) { - if (i != 0 && i != 1 && i != 10 && i != 14) { + if (i != 0 && i != 1 && i != 10 && i != 14 && i != 15) { request_irq(i, default_irq_handler, "default", "default"); } } @@ -152,6 +152,7 @@ void setup_irqs() { open_irq(IRQ_CLOCK); open_irq(IRQ_KEYBOARD); open_irq(IRQ_DISK); + open_irq(15); } void boot_irq_handler(); diff --git a/kernel/task_disk.c b/kernel/task_disk.c index 8bc22f5..741a933 100644 --- a/kernel/task_disk.c +++ b/kernel/task_disk.c @@ -9,32 +9,36 @@ #include #include +#include #include -disk_request_queue_t disk_request_queue; - // task disk与中断函数之间的信号量 semaphore_t disk_intr_sem; -DECLARE_MUTEX(disk_request_mutex); - -void disk_init() { - disk_request_queue.count = 0; - INIT_LIST_HEAD(&disk_request_queue.list); - // disk_request_queue.sem.cnt = 0; - // INIT_LIST_HEAD(&disk_request_queue.sem.wait_list); - semaphore_init(&disk_request_queue.sem, 0); +// task disk 之间发送命令的互斥量 +DECLARE_MUTEX(disk_cmd_mutex); - semaphore_init(&disk_intr_sem, 0); -} +void disk_init() { semaphore_init(&disk_intr_sem, 0); } volatile uint32_t disk_request_cnt = 0; volatile uint32_t disk_handled_cnt = 0; + void send_disk_request(disk_request_t *r) { if (NULL == r) { panic("null disk request"); } + // TODO: 转换 + int drv_no = r->dev; + // assert(drv_no == 0); + + assert(drv_no >= 0); + assert(drv_no <= MAX_IDE_DRIVE_CNT); + + ide_drive_t *drv = ide_drives + drv_no; + + assert(drv->present == 1); + // 这个用来让task_disk唤醒自己 semaphore_init(&r->sem, 0); @@ -47,47 +51,66 @@ void send_disk_request(disk_request_t *r) { panic("disk DMA read cross 64K"); } - mutex_lock(&disk_request_mutex); + mutex_lock(&drv->request_mutex); disk_request_cnt++; - list_add_tail(&r->list, &disk_request_queue.list); - mutex_unlock(&disk_request_mutex); + list_add_tail(&r->list, &drv->request_queue.list); + mutex_unlock(&drv->request_mutex); // 唤醒task_disk - up(&disk_request_queue.sem); + up(&drv->request_queue.sem); // 等待被task_disk唤醒 down(&r->sem); } -void disk_task_entry() { +void disk_task_entry(int arg) { int r_cnt = 0; while (1) { - // printk("wait for new hard disk request\n"); - down(&disk_request_queue.sem); - // printk("hard disk request: %d\n", disk_request_queue.count++); + // 如果要改造成每个drive对应一个内核任务的话 + // 就要注意共享disk_intr_sem的问题 + // 目前只支持drv_no == 0 + int drv_no = arg; + ide_drive_t *drv = ide_drives + drv_no; + if (drv->present == 0) { + panic("disk not present"); + } + + // 为了在DEBUG时看到RUNNING + for (int i = 0; i < 3; i++) { + asm("hlt;"); + } + + // printk("wait request for hard disk %d\n", drv_no); + down(&drv->request_queue.sem); + // printk("hard disk %d\n", drv_no); - mutex_lock(&disk_request_mutex); + mutex_lock(&drv->request_mutex); disk_request_t *r; - r = list_first_entry(&disk_request_queue.list, disk_request_t, list); + r = list_first_entry(&drv->request_queue.list, disk_request_t, list); if (NULL == r) { panic("no disk request"); } list_del(&r->list); disk_handled_cnt++; - mutex_unlock(&disk_request_mutex); + mutex_unlock(&drv->request_mutex); + // 目前这个disk_cmd_mutex是用于两个通道四个DRIVE之间互斥 + // 目前还不确定两个通道之间能否同时执行 + // 后续要把disk分成两个进程,分别负责channel 0 1 + // 这里再视情况改写 + mutex_lock(&disk_cmd_mutex); switch (r->command) { case DISK_REQ_IDENTIFY: assert(r->count == 1); - void ata_read_identify(int dev, int disable_intr); - ata_read_identify(r->dev, 0); + void ata_read_identify(int drv, int disable_intr); + ata_read_identify(drv_no, 0); break; case DISK_REQ_READ: assert(r->count > 0); assert(r->buf != NULL); - void ata_dma_read_ext(int dev, uint64_t pos, uint16_t count, void *dest); - ata_dma_read_ext(r->dev, r->pos, r->count, r->buf); + void ata_dma_read_ext(int drv, uint64_t pos, uint16_t count, void *dest); + ata_dma_read_ext(drv_no, r->pos, r->count, r->buf); break; default: break; @@ -95,11 +118,11 @@ void disk_task_entry() { // 等待硬盘中断 down(&disk_intr_sem); - + mutex_unlock(&disk_cmd_mutex); // 读数据 if (DISK_REQ_IDENTIFY == r->command) { - void ata_read_data(int dev, int sect_cnt, void *dst); - ata_read_data(r->dev, 1, r->buf); + void ata_read_data(int drv_no, int sect_cnt, void *dst); + ata_read_data(drv_no, 1, r->buf); } // 唤醒等待该请求的进程 diff --git a/kernel/task_init.c b/kernel/task_init.c index 7c7383d..2e541ad 100644 --- a/kernel/task_init.c +++ b/kernel/task_init.c @@ -13,11 +13,6 @@ int sysc_wait(uint32_t ticks); void init_task_entry() { current->priority = 10; - // 继续内核未完成的初始化 - // 这些初始化在开中断的情况下完成 - void setup_under_irq(); - setup_under_irq(); - while (1) { asm("sti;hlt;"); sysc_wait(2); diff --git a/kernel/task_root.c b/kernel/task_root.c index 5c0c700..cece740 100644 --- a/kernel/task_root.c +++ b/kernel/task_root.c @@ -25,7 +25,7 @@ int sysc_wait(uint32_t ticks); #define get_eflags(x) __asm__ __volatile__("pushfl; popl %0;" : "=g"(x)::"memory") -void kernel_task(char *name, void *entry) { +void kernel_task(char *name, void *entry, void *arg) { pt_regs_t regs; memset((void *)®s, 0, sizeof(regs)); @@ -33,6 +33,9 @@ void kernel_task(char *name, void *entry) { // 内核任务入口 regs.edx = (unsigned long)entry; + // 参数 + regs.ecx = (unsigned long)arg; + regs.eax = (u32)name; // 创建内核任务的时候就直接指定其在fork后走的路径 @@ -103,6 +106,7 @@ void taskA_entry() { memset(disk_buf1, 0, 512); disk_request_t r; + r.dev = 0; r.command = DISK_REQ_READ; r.pos = sect_nr; r.count = 1; @@ -126,12 +130,13 @@ void taskB_entry() { uint64_t sect_nr = get_next_deubug_sect_nr(); memset(disk_buf2, 0, 512); disk_request_t r; + r.dev = 2; r.command = DISK_REQ_READ; r.pos = sect_nr; r.count = 1; r.buf = disk_buf2; send_disk_request(&r); - verify_hd_data(sect_nr, disk_buf2, current->name); + // verify_hd_data(sect_nr, disk_buf2, current->name); for (int i = 0; i < 1; i++) { asm("hlt;"); @@ -165,17 +170,18 @@ void root_task_entry() { void disk_init(); disk_init(); - kernel_task("init", init_task_entry); - kernel_task("disk", disk_task_entry); - kernel_task("user", user_task_entry); + kernel_task("init", init_task_entry, NULL); + kernel_task("disk/0", disk_task_entry, (void *)0); + kernel_task("disk/2", disk_task_entry, (void *)2); + kernel_task("user", user_task_entry, NULL); // for (int i = 0; i < 100; i++) { // asm("hlt;"); // } - kernel_task("tskA", taskA_entry); - kernel_task("tskB", taskB_entry); - kernel_task("tskC", taskC_entry); + kernel_task("tskA", taskA_entry, NULL); + kernel_task("tskB", taskB_entry, NULL); + kernel_task("tskC", taskC_entry, NULL); current->priority = 1; while (1) { diff --git a/kernel/tty.c b/kernel/tty.c index 3d78ab7..f574aeb 100644 --- a/kernel/tty.c +++ b/kernel/tty.c @@ -22,7 +22,7 @@ const uint32_t PHY_VADDR = 0xB8000; const uint32_t VADDR = (uint32_t)pa2va(PHY_VADDR); #define TTY_VRAM_SIZE (0x1000) -#define NR_TTYS 8 +#define MAX_NR_TTYS 8 tty_t ttys[NR_TTYS]; #define MAX_X 80 @@ -67,6 +67,8 @@ void __tty_set_next_pos_color(tty_t *tty, char color) { void init_tty(tty_t *tty, const char *name, unsigned long base) { assert(0 != tty); + assert(NR_TTYS >= 1); + assert(NR_TTYS <= MAX_NR_TTYS); strlcpy(tty->name, name, sizeof(tty->name)); diff --git a/qemu.sh b/qemu.sh index c38b3f5..fa9ce47 100755 --- a/qemu.sh +++ b/qemu.sh @@ -1,8 +1,9 @@ qemu-system-i386 \ -device ich9-ahci,id=ahci \ -boot d \ - -drive file=HD.IMG,format=raw,index=0,media=disk \ + -drive file=HDa.IMG,format=raw,index=0,media=disk \ -drive file=kernel.iso,index=1,media=cdrom \ + -drive file=HDb.IMG,format=raw,index=2,media=disk \ -name kernel \ -s -S \ &