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

📄 pci.c

📁 开源的BIOS启动软件
💻 C
字号:
#include <bios/types.h>#include <bios/dec21285.h>#include <bios/debug.h>#include <bios/pci.h>#include <bios/machine.h>#include <bios/malloc.h>#include <bios/stdio.h>#include <bios/string.h>#include <bios/x86.h>static unsigned long	pci_io_free;static unsigned long	pci_mem_free;static struct pci_dev *	pci_root_dev;extern unsigned int	ram_size;#ifndef DEBUG#define debug_printf(x...)#endifstatic inline unsigned long pci_alloc(unsigned long *resource, unsigned long size){	unsigned long base;	*resource += size - 1;	*resource &= ~(size - 1);	base = *resource;	*resource += size;	return base;}static unsigned long pci_alloc_io(unsigned long size){	unsigned long res = pci_io_free;	/*	 * Align resource to the requested size	 */	res += size - 1;	res &= ~(size - 1);	/*	 * Check for overlap with an ISA region	 */	if (res & 0x300)		res = (res + 0x400) & ~0x3ff;	pci_io_free = res + size;	return res;}static unsigned long pci_alloc_mem(unsigned long size){	return pci_alloc(&pci_mem_free, size);}struct pci_dev *pci_lookupclass(struct pci_dev *dev, unsigned short class){	if (!dev)		dev = pci_root_dev;	else		dev = dev->next;	while (dev) {		if (dev->class == class &&		    dev->command & (PCI_COMMAND_MEM_SPACE|PCI_COMMAND_IO_SPACE))			break;		dev = dev->next;	}	return dev;}struct pci_dev *pci_lookup_vendor_device(struct pci_dev *dev,			 unsigned short vendor_id, unsigned short device_id){	if (!dev)		dev = pci_root_dev;	else		dev = dev->next;	while (dev) {		if (dev->vendor == vendor_id &&		    dev->device == device_id)			break;		dev = dev->next;	}	return dev;}struct pci_dev *pci_dev_next(struct pci_dev *dev){	if (!dev)		dev = pci_root_dev;	else		dev = dev->next;	return dev;}/* * Enable busmaster mode on the specified device.  We also set up * the cache line size and latency timer here. */int pci_set_master(struct pci_dev *dev){	u16 oldcmd = dev->command;	dev->command |= PCI_COMMAND_BUS_MASTER;	debug_printf("%d.%d: enabling busmaster; 0x%04x to 0x%04x\n",		SLOT(dev->dev), FUNC(dev->dev), oldcmd, dev->command);	pci_write_config_byte(dev->pci_base, PCI_CACHELINESIZE, 8);	pci_write_config_byte(dev->pci_base, PCI_LATENCY_TIMER, 32);	pci_write_config_word(dev->pci_base, PCI_COMMAND, dev->command);	return 0;}/* * Enable a PCI device.  The MEM_SPACE and IO_SPACE bits are set * according to the requirements of the PCI device. */int pci_enable(struct pci_dev *dev){	u16 oldcmd = dev->command;	int i;	for (i = 0; i < 6; i++) {		if (dev->bar[i]) {			if (dev->bar[i] & 1)				dev->command |= PCI_COMMAND_IO_SPACE;			else				dev->command |= PCI_COMMAND_MEM_SPACE;		}	}	switch (dev->class >> 8) {	case PCI_CLASS_NOT_DEFINED:	case PCI_BASE_CLASS_DISPLAY:	case PCI_BASE_CLASS_STORAGE:		dev->command |= PCI_COMMAND_IO_SPACE;		break;	}	if (dev->bar[7])		dev->command |= PCI_COMMAND_MEM_SPACE;	debug_printf("%d.%d: enabling device; 0x%04x to 0x%04x\n",		SLOT(dev->dev), FUNC(dev->dev), oldcmd, dev->command);	pci_write_config_word(dev->pci_base, PCI_COMMAND, dev->command);	return 0;}/* * Disable all accesses to the PCI device */int pci_disable(struct pci_dev *dev){	u16 oldcmd = dev->command;	dev->command &= ~(PCI_COMMAND_IO_SPACE | PCI_COMMAND_MEM_SPACE);	debug_printf("%d.%d: disabling device; 0x%04x to 0x%04x\n",		SLOT(dev->dev), FUNC(dev->dev), oldcmd, dev->command);	pci_write_config_word(dev->pci_base, PCI_COMMAND, dev->command);	return 0;}static int pci_init_hw(void){	unsigned int ctrl = csr_read_long(CSR_CTRL);	unsigned int rsz, sz;	csr_write_long(0, CSR_PCIEXTN);	/*	 * Set up the mask registers	 */	csr_write_long(12, CSR_OIMR);	csr_write_long(0, CSR_DPMR);	csr_write_long(0, CSR_DSMR);	/*	 * Calculate the size of the SDRAM (for the base address mask	 * register)	 */	rsz = (ram_size - 1) >> 19;	for (sz = 0x00040000; rsz; rsz >>= 1, sz = sz | sz << 1);	/*	 * Set up the PCI -> Host mappings	 */	csr_write_long(sz, CSR_SDRAMBASEADDRMASK);	csr_write_long(0, CSR_SDRAMBASEOFF);	csr_write_long(0, CSR_CSRBASEADDRMASK);			/* 128bytes */	csr_write_long(0, CSR_CSRBASEADDR);	csr_write_long(0x80f00000, CSR_ROMBASEADDRMASK);	/* disabled */	csr_write_long(0, CSR_ROMBASEADDR);	if (ctrl & CSR_CTRL_PCICFN) {		/*		 * Disable PCI reset		 */		ctrl |= CSR_CTRL_PCINRST;		csr_write_long(ctrl, CSR_CTRL);		/*		 * Disable our PCI interface		 */		csr_write_word(0, CSR_PCI_CMD);		csr_write_word(8, CSR_PCI_CACHELINESZ);		csr_write_word(32, CSR_PCI_LATENCY_TIMER);		/*		 * Disable prefetchable memory region.		 * (might use this some day)		 */		csr_write_long(CSR_PREFETCHRANGE_LEN8, CSR_PREFETCHRANGE);		/*		 * SDRAM is mapped at PCI space address 0x10000000		 */		csr_write_long(0x10000000, CSR_SDRAMBASE);		csr_write_long(0xf0000000, CSR_CSRMEMBASE);		csr_write_long(0x0000f000, CSR_CSRIOBASE);		/*		 * Now enable memwinv, master, memory, but not IO		 */		csr_write_word(0x16, CSR_PCI_CMD);	} else {		/*		 * Add-in peripheral board initialisation		 */		csr_write_long(0, CSR_PREFETCHRANGE);	}	/*	 * Set Init Complete.  If we are an add-in board, this	 * will allow the host POST to continue.	 */	csr_write_long(ctrl | CSR_CTRL_INITCOMPLETE, CSR_CTRL);	return ctrl & CSR_CTRL_PCICFN;}/* * Scan the PCI bus looking for devices, and * add them to our "pci_root_dev" list. */static void pci_scan_bus(void){	struct pci_dev *pdev, **p;	int dev, multi = 0;	for (dev = 0; dev < MAX_DEV; dev++) {		unsigned long pci_base;		u32 vendor, device;		if (FUNC(dev) && !multi)			continue;		pci_base = pci_config_addr(SLOT(dev), FUNC(dev));		vendor = pci_read_config_word(pci_base, PCI_VENDOR_ID);		device = pci_read_config_word(pci_base, PCI_DEVICE_ID);		if (vendor == 0xffff || vendor == 0x0000 ||		    device == 0xffff || device == 0x0000)			continue;		pdev = malloc(sizeof(*pdev));		memset(pdev, 0, sizeof(*pdev));		pdev->vendor   = vendor;		pdev->device   = device;		pdev->pci_base = pci_base;		pdev->header   = pci_read_config_byte(pci_base, PCI_HEADER_TYPE);		pdev->command  = pci_read_config_word(pci_base, PCI_COMMAND);		pdev->class    = pci_read_config_word(pci_base, PCI_CLASS_CODE + 2);		pdev->progif   = pci_read_config_byte(pci_base, PCI_CLASS_CODE + 1);		pdev->dev      = dev;		multi = pdev->header & 0x80;		/*		 * Add this device to the list		 */		for (p = &pci_root_dev; *p; p = &(*p)->next);		*p = pdev;	}}static void pci_setup_cards_0(struct pci_dev *dev){	unsigned long pci_base = dev->pci_base;	unsigned long base, size;	unsigned int i;	for (i = 0; i < 6; i ++) {		dev->bar[i] = 0;		pci_write_config_long(pci_base, PCI_BASE0 + i * 4, 0xffffffff);		base = pci_read_config_long(pci_base, PCI_BASE0 + i * 4);		if (base == 0)			continue;		if (base & 1) {	/* IO space */			size = -(base & ~3);			size &= 0xffff;			base = pci_alloc_io(size) | 1;			dev->command |= PCI_COMMAND_IO_SPACE;		} else {	/* MEM space */			size = -(base & ~15);			base = pci_alloc_mem(size);			dev->command |= PCI_COMMAND_MEM_SPACE;		}		dev->bar[i] = base;		pci_write_config_long(pci_base, PCI_BASE0 + i * 4, base);		if (pci_read_config_long(pci_base, PCI_BASE0 + i * 4) != base)			debug_printf("Unable to set base\n");	}	/*	 * If this device has a BIOS rom, allocate space for it,	 * but leave the ROM disabled.  We don't want to go around	 * enabling all the ROMs needlessly.	 */	pci_write_config_long(pci_base, PCI_BIOSROMCONTROL, -2);	base = pci_read_config_long(pci_base, PCI_BIOSROMCONTROL);	if (base) {		size = -(base & ~1);		dev->bar[7] = pci_alloc_mem(size);		pci_write_config_long(pci_base, PCI_BIOSROMCONTROL, dev->bar[7]);		dev->command |= PCI_COMMAND_MEM_SPACE;	}	switch (dev->class >> 8) {	case PCI_CLASS_NOT_DEFINED:	case PCI_BASE_CLASS_DISPLAY:	case PCI_BASE_CLASS_STORAGE:		dev->command |= PCI_COMMAND_IO_SPACE;		break;	case PCI_BASE_CLASS_BRIDGE:		dev->command |= PCI_COMMAND_IO_SPACE |				PCI_COMMAND_MEM_SPACE |				PCI_COMMAND_BUS_MASTER;		break;	}}static void pci_setup_cards(void){	struct pci_dev *dev;	for (dev = pci_root_dev; dev; dev = dev->next) {		dev->command &= ~(PCI_COMMAND_BUS_MASTER |				  PCI_COMMAND_MEM_SPACE |				  PCI_COMMAND_IO_SPACE);		if ((dev->header & 0x7f) == 0)			pci_setup_cards_0(dev);		debug_printf("%d.%d: command = %04X\n", SLOT(dev->dev),			FUNC(dev->dev), dev->command);		pci_write_config_word(dev->pci_base, PCI_COMMAND, dev->command);	}}static int__pci_exec_bios(struct pci_dev *dev, struct pci_data *data, unsigned int base){	struct rom_header rom;	memcpy(&rom, (void *)base, sizeof(rom));	if (rom.magic != ROM_MAGIC) {		debug_printf("%d.%d: bad rom magic\n", SLOT(dev->dev),			FUNC(dev->dev));		return 0;	}	memcpy(data, (void *)(base + rom.pci_off), sizeof(*data));	if (data->pcir_magic != PCIR_MAGIC) {		debug_printf("%d.%d: bad pcir magic (0x%08x != 0x%08x) - "			"rom.pci_off = %d\n", SLOT(dev->dev),			FUNC(dev->dev), data->pcir_magic, PCIR_MAGIC,			rom.pci_off);		return 0;	}	if (dev->vendor != data->vendor_id || dev->device != data->device_id) {		debug_printf("%d.%d: wrong rom image: device = %04x:%04x, rom = %04x:%04x\n",			SLOT(dev->dev), FUNC(dev->dev),			dev->vendor, dev->device,			data->vendor_id, data->device_id);		return 0;	}	return 1;}void pci_exec_bios(struct pci_dev *dev){	unsigned int base = 0x80000000 + (dev->bar[7] & ~1);	unsigned int x86_base = 0xc0000;	struct pci_data data;	int ret;	/*	 * Enable the ROM	 */	pci_write_config_long(dev->pci_base, PCI_BIOSROMCONTROL,			      dev->bar[7] | 1);	ret = __pci_exec_bios(dev, &data, base);	if (ret) {		switch (data.type) {		case TYPE_X86:			/*			 * Copy the ROM image into the emulator.			 */			x86_copy_in(x86_base, (void *)base,				    data.img_len * 512);			/*			 * Disable the PCI BIOS before calling			 * the 'shadow' version			 */			pci_write_config_long(dev->pci_base,					      PCI_BIOSROMCONTROL, dev->bar[7]);			/*			 * Call code at base+3, AH = busnr,			 * AL7:3 = slot, AL2:0 = func			 */			x86_call(x86_base + 3, dev->dev);			return;		default:			debug_printf("%d.%d: unknown data type %d\n", SLOT(dev->dev),				FUNC(dev->dev), data.type);		}	}	pci_write_config_long(dev->pci_base, PCI_BIOSROMCONTROL, dev->bar[7]);}void pci_print_config(void){	struct pci_dev *dev;	int i, nr_addr = 4;	printf("---------------------- PCI Configuration -----------------------\n");	printf("Slot Vendor Device Class BMI ");	for (i = 0; i < nr_addr; i++)		printf(i == 6 ? "Bios" : "Address%d ", i);	printf("\n");	for (dev = pci_root_dev; dev; dev = dev->next) {		int i;		printf("%2d.%d", SLOT(dev->dev), FUNC(dev->dev));		printf("  %04X   %04X  %04X  %c%c%c",		       dev->vendor, dev->device, dev->class,		       dev->command & PCI_COMMAND_BUS_MASTER ? '*' : ' ',		       dev->command & PCI_COMMAND_MEM_SPACE  ? '*' : ' ',		       dev->command & PCI_COMMAND_IO_SPACE   ? '*' : ' ');		for (i = 0; i < nr_addr; i++)			if (dev->bar[i])				printf(" %08x", dev->bar[i]);			else				printf("         ");		printf("\n");	}	printf("----------------------------------------------------------------\n");}void pci_init(void){	int host;	/*	 * Initialise the PCI hardware (DC21285)	 */	host = pci_init_hw();	/*	 * We only scan the PCI bus if we were in host mode.	 * If we were in add-in mode, chances are that the host BIOS	 * hasn't set anything up yet.	 */	if (host) {		pci_io_free  = 0x6000;		pci_mem_free = PCIMEM_BASE;		pci_scan_bus();		pci_setup_cards();	}}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -