⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ide.c

📁 开源的BIOS启动软件
💻 C
📖 第 1 页 / 共 2 页
字号:
	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 + -