📄 ide.c
字号:
return rc;}static int ide_drive_probe(struct ide_drive *drive){ int rc, count; /* * Now, select which drive we want to talk to. At * this point, we should be able to read back the * device/head (SELECT) register. This test will * trap out the truely non-present drives. */ if (!ide_select_drive(drive)) { rc = 3; goto out; } /* * Now, have another go at guessing which status * register we should use. This may be different * from before. */ drive->statusreg = ide_detect_status_reg(drive->hw); /* * Try to identify the device. */ count = 0; do { rc = ide_identify_device(drive, WIN_IDENTIFY, &drive->id); if (!rc) { if (ID_INCOMPLETE(&drive->id)) printf("(i) "); ide_parse_identify(drive, &drive->id); break; } } while (++count < 2);out: return rc;}/* * Read the status/altstatus register */static inline int ide_hw_read_status_reg(struct ide_hw *hw){ return ide_inb(hw, hw->statusreg) & 0xf9;}/* * Try to detect a drive. Note that this routine should NOT be * called within 2ms of the negation of RESET to the drive. Note * also that "centisecs" is the time past since we started running * the bios, so we can do an absolute timeout here. */static int ide_hw_wait_ready(struct ide_hw *hw){ int target = MAX_BUSY_WAIT, rc; /* * First, select which status register to use */ hw->statusreg = ide_detect_status_reg(hw); /* * Check the busy bit. If it is set, we can't access any registers. * We wait a maximum of 32 seconds for the status register to become * not busy. Note that the T13 ATAPI standard defines there to be * a 10K pull-down resistor on this line. */ while (ide_hw_read_status_reg(hw) & BUSY_STAT) { if (centisecs > target) { rc = 2; goto out; } /* * Wait a full second before trying again - we don't * want to hammer the drive with status reads */ wait_cs(100); } /* * Detect any error that the drive may be reporting. Our parent will * report the error code to the user. Maybe we ought to tell the * user in plain english which drive has failed? */ if (ide_hw_read_status_reg(hw) & ERR_STAT) { rc = 1; goto out; } rc = 0;out: return rc;}/* * Initialise one interface */static void ide_init_one_if(struct ide_hw *hw){ int drvnr, rc, drvok = 3; printf(" ide%d: %s at 0x%04x,0x%04x", hw->ifnr, hw->dma->name, hw->regs[0], hw->regs[8]); if (hw->dma_base) printf(", BM-DMA at 0x%04x", hw->dma_base); if (hw->dma && hw->dma->init) hw->dma->init(hw); printf("\n"); /* * Wait for the interface to become not busy. This can take * up to 32 seconds after power on for the drive to finish * its diagnostics, during which time the interface must * otherwise remain idle. */ rc = ide_hw_wait_ready(hw); if (rc) { int error; switch (rc) { case 2: printf(" ide%d: timeout waiting for busy to " "deassert\n", hw->ifnr); drvok = 0; break; case 1: /* * There are some drives that indicate an error * because they have not detected a slave. If * this is the case, then we continue anyway. * [ note that these drives typically don't * perform diagnostics on reset either ] */ error = ide_inb(hw, IDE_ERROR); if ((error & 0x7f) != 0x01) { printf(" ide%d: master drive diagnostic " "failure, code 0x%02x\n", hw->ifnr, error & 0x7f); drvok &= ~1; } if (error & 0x80) { /* * Slave error - we must read its error * register to get the full picture. */ ide_outb(hw, 0xb0, IDE_SELECT); error = ide_inb(hw, IDE_ERROR); ide_outb(hw, 0xa0, IDE_SELECT); printf(" ide%d: slave drive diagnostic " "failure, code 0x%02x\n", hw->ifnr, error); drvok &= ~2; } } } /* * setup each drive on this interface, and * then try to detect it. */ for (drvnr = 0; drvnr < 2; drvnr++) { struct ide_drive *drv; if (drvok & (1 << drvnr)) { drv = malloc(sizeof(struct ide_drive)); memset(drv, 0, sizeof(struct ide_drive)); hw->drive[drvnr] = drv; drv->hw = hw; drv->slave = drvnr; drv->name = 'a' + hw->ifnr * 2 + drvnr; drv->select = 0xa0 | (drvnr << 4); ide_dma_disable(drv); printf(" hd%c: ", drv->name); rc = ide_drive_probe(drv); if (rc) { printf("not present (%d)\n", rc); hw->drive[drvnr] = NULL; free(drv); } } }}static void ide_init_hw(unsigned int reg_base, unsigned int ctrl_base, unsigned int dma_base, struct pci_dev *dev, const struct dma_hw *dma){ static int ifnr; struct ide_hw *hw; int i; if (ifnr >= NR_HW || reg_base == 0) return; ide_hw_list[ifnr] = hw = malloc(sizeof(struct ide_hw)); memset(hw, 0, sizeof(struct ide_hw)); for (i = 0; i < 8; i++) hw->regs[i] = reg_base + i; hw->regs[8] = ctrl_base; hw->dma_base = dma_base; hw->dev = dev; hw->dma = dma; hw->ifnr = ifnr; ide_init_one_if(hw); ifnr += 1;}static void ide_init_one_hw(struct pci_dev *dev, const struct dma_hw *dma){ int i; if (pci_enable(dev)) return; for (i = 0; i < 2; i++) { unsigned int reg_base, ctrl_base, dma_base; if (i == 0) { reg_base = dev->bar[0] & ~3; ctrl_base = dev->bar[1] & ~3; dma_base = dev->bar[4] & ~3; } else if (!dma->split_cfg) { reg_base = dev->bar[2] & ~3; ctrl_base = dev->bar[3] & ~3; dma_base = (dev->bar[4] & ~3) + 8; } else { reg_base = dev->next->bar[0] & ~3; ctrl_base = dev->next->bar[1] & ~3; dma_base = (dev->bar[4] & ~3) + 8; } ide_init_hw(reg_base, ctrl_base + 2, dma_base, dev, dma); }}/* * Probe for all IDE devices on this bus. */static int ide_probe(void){ struct pci_dev *dev = NULL; /* * Search for known interfaces */ while ((dev = pci_dev_next(dev)) != NULL) { const struct dma_hw *dma; int i, ok = 0; /* * If this is an IDE or RAID storage adapter, * then we have found the correct entry. */ if (dev->class == PCI_CLASS_STORAGE_IDE || dev->class == PCI_CLASS_STORAGE_RAID) ok = 1; /* * Now look it up in the table of known adapters - we * may have to ignore this entry for some reason. */ for (i = 0, dma = dma_hw; dma->vendev; i++, dma++) { if ((dev->vendor << 16 | dev->device) == dma->vendev) { ok = dma->check ? dma->check(dev) : 1; break; } } if (ok) ide_init_one_hw(dev, dma); } return 0;}static int ide_start(void){ int ifnr, drvnr, present = 0; for (ifnr = 0; ifnr < NR_HW; ifnr++) { struct ide_hw *hw = ide_hw_list[ifnr]; /* * Interface present? */ if (!hw) continue; /* * Try each drive */ for (drvnr = 0; drvnr < 2; drvnr++) { if (hw->drive[drvnr]) present = 1; } } return present ? 0 : -1;}#if 0static void dump_sector(u8 *buffer){ int i, j; for (i = 0; i < 512; i += 16) { debug_printf("%03X ", i); for (j = i; j < i + 16; j++) debug_printf("%02X ", buffer[j]); debug_printf(" "); for (j = i; j < i + 16; j++) debug_printf("%c", (buffer[j] < 32 || buffer[j] > 127) ? '.' : buffer[j]); debug_printf("\n"); }}#endifstatic int __ide_read_sectors(struct ide_drive *drive, u32 sector, u8 *buf, int nsect){ u8 sect, lcyl, hcyl, sel; unsigned int target; int status, rc = -1; if (sector > drive->capacity - nsect) { printf("__ide_read_sectors: bad sector 0x%x len 0x%x > capacity 0x%x\n", sector, nsect, drive->capacity); return -1; } if (!ide_status_ok(drive, 0, BUSY_STAT)) { printf("__ide_read_sectors: drive hd%c busy\n", drive->name); return -1; } if (!ide_select_drive(drive)) return -1; wait_cs(1); if (!ide_status_ok(drive, READY_STAT, BUSY_STAT|DRQ_STAT)) { printf("hd%c: drive not ready for command\n", drive->name); return -1; } ide_outb(drive->hw, 8, IDE_CONTROL); ide_outb(drive->hw, nsect, IDE_NSECTOR); if (drive->lba) { sect = sector; lcyl = sector >> 8; hcyl = sector >> 16; sel = (sector >> 24) & 15; } else { unsigned int cyl, track; sect = sector % drive->sect + 1; track = sector / drive->sect; sel = track % drive->head; cyl = track / drive->head; lcyl = cyl; hcyl = cyl >> 8; } ide_outb(drive->hw, sect, IDE_SECTOR); ide_outb(drive->hw, lcyl, IDE_LCYL); ide_outb(drive->hw, hcyl, IDE_HCYL); ide_outb(drive->hw, sel | drive->select, IDE_SELECT); ide_outb(drive->hw, WIN_READ, IDE_COMMAND); wait_cs(1); rc = -2; target = centisecs + 2000; do { status = ide_inb(drive->hw, IDE_STATUS); if (status & BUSY_STAT) continue; if (status & DRQ_STAT) { target = centisecs + 100; ide_input_data(drive, buf, 512); buf += 512; nsect -= 1; } if (status & ERR_STAT) break; } while (target > centisecs && nsect); if (status & ERR_STAT) { printf("hd%c: error reading sectors: 0x%02x\n", drive->name, ide_inb(drive->hw, IDE_ERROR)); } else if (!nsect) rc = 0; return rc;}static int ide_read_sectors(struct ide_drive *drive, u32 sector, void *buffer, int len){ u8 *buf = (u8 *)buffer; int rc = -1; if (len & 511) return -1; len = len >> 9; while (len) { int nsect; nsect = len; if (nsect > 244) nsect = 244; rc = __ide_read_sectors(drive, sector, buf, nsect); if (rc) break; len -= nsect; sector += nsect; buf += (nsect << 9); } return rc;}static u32 part_getbootstart(struct ide_drive *drive){ u8 sector[512], *p; int nr; if (ide_read_sectors(drive, 0, sector, 512)) return 0; if ((sector[510] != 0x55 || sector[511] != 0xaa) && (sector[510] != 'R' || sector[511] != 'K')) return 0; for (p = sector + 0x1be, nr = 0; nr < 4; p += 16, nr++) if (p[0] == 0x80) return p[8] | p[9] << 8 | p[10] << 16 | p[11] << 24; return 0;}struct map { u32 magic; u32 block_sz; struct { u32 off; u32 len; } map[63];};static int read_mapped_file(struct ide_drive *drive, u32 part_start, struct map *map, u8 *ptr){ int i; if (map->magic != 0xc53a4b2d) return -1; for (i = 0; i < 63 && map->map[i].off; i++) { u32 start; start = part_start + map->map[i].off * map->block_sz / 512; if (ide_read_sectors(drive, start, ptr, map->map[i].len * map->block_sz)) return -1; ptr += map->map[i].len * map->block_sz; } return 0;}static void copy_map(struct map *map, u8 *from){ u32 *p = (u32 *)from; int i = 0; map->magic = *p++; map->block_sz = *p++; while (p[0] && p[1]) { map->map[i].off = *p++; map->map[i].len = *p++; i += 1; }}extern char *cmdline;static int ide_load(void){ struct ide_drive *drive = NULL; struct map map; u8 *boot_map_file = (u8 *)0x4000; u32 part_start = 0; u32 *p; int nr, i, bmf_size; extern int img_nr; /* If J17 P13-14 is made, then don't boot off the HD */ if (!((*(u8 *)0x40012000) & 0x10)) return -1; for (i = 0; i < NR_HW; i++) { struct ide_hw *hw = ide_hw_list[i]; int drvnr; if (!hw) continue; for (drvnr = 0; drvnr < 2; drvnr ++) { drive = hw->drive[drvnr]; if (drive) { debug_printf("checking hd%c: ", drive->name); part_start = part_getbootstart(drive); debug_printf("boot start %08x\n", part_start); } if (part_start) break; } if (part_start) break; } if (!drive || part_start == 0) return -1; debug_printf("Using hd%c...\n", drive->name); if (ide_read_sectors(drive, part_start, &map, sizeof(map))) return -1; debug_printf("read boot sectors: magic = %08x\n", map.magic); if (read_mapped_file(drive, part_start, &map, boot_map_file)) return -1; debug_printf("read map sectors: magic = %08x\n", *(u32 *)boot_map_file); if (*(u32 *)boot_map_file != 0xc35ae183) return -1; bmf_size = boot_map_file[4]; nr = boot_map_file[8]; printf("Available configurations:\n"); for (i = 0; i < nr; i++) { p = (u32 *)(boot_map_file + bmf_size * (i + 1)); if (p[0] != 1) continue; printf(" %d %-10s\n", i + 1, boot_map_file + p[1]); } if (img_nr >= nr || img_nr < 0) img_nr = 0; p = (u32 *)(boot_map_file + bmf_size * (img_nr + 1)); printf("Loading %s...", boot_map_file + p[1]); if (p[2]) cmdline = boot_map_file + p[2]; copy_map(&map, boot_map_file + p[3]); if (read_mapped_file(drive, part_start, &map, (u8 *)load_addr)) return -1; if (root_dev == 0) root_dev = p[5]; root_flags = p[7]; return 0;}static int ide_stop(void){ return 0;}struct bootdev boot_ide = { "ide", ide_probe, ide_start, ide_load, ide_stop};
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -