Exemple #1
0
static Pcidev *
mgapcimatch(void)
{
	Pcidev *p;
	
	p = pcimatch(nil, MATROX, MGA4xx);
	if(p == nil)
		p = pcimatch(nil, MATROX, MGA550);
	if(p == nil)
		p = pcimatch(nil, MATROX, MGA200);
	return p;
}
Exemple #2
0
int
dbpci(Vga *vga, Ndbtuple *tuple)
{
	int did, vid;
	Ndbtuple *t, *td;
	Pcidev *pci;

	for(t = tuple->entry; t; t = t->entry){
		if(strcmp(t->attr, "vid") != 0 || (vid=atoi(t->val)) == 0)
			continue;
		for(td = t->line; td != t; td = td->line){
			if(strcmp(td->attr, "did") != 0)
				continue;
			if(strcmp(td->val, "*") == 0)
				did = 0;
			else if((did=atoi(td->val)) == 0)
				continue;
			for(pci=nil; pci=pcimatch(pci, vid, did);)
				if(pci->ccrb == 3)
					break;
			if(pci == nil)
				continue;
			vga->pci = pci;
			addattr(&vga->attr, t);
			addattr(&vga->attr, td);
			return 1;
		}
	}
	return 0;
}
Exemple #3
0
static void
hiqvideoenable(VGAscr* scr)
{
	Pcidev *p;
	int vmsize;

	/*
	 * Only once, can't be disabled for now.
	 */
	if(scr->mmio)
		return;
	if(p = pcimatch(nil, 0x102C, 0)){
		switch(p->did){
		case 0x00C0:		/* 69000 HiQVideo */
			vmsize = 2*1024*1024;
			break;
		case 0x00E0:		/* 65550 HiQV32 */
		case 0x00E4:		/* 65554 HiQV32 */
		case 0x00E5:		/* 65555 HiQV32 */
			switch((hiqvideoxi(Xrx, 0x43)>>1) & 0x03){
			default:
			case 0:
				vmsize = 1*1024*1024;
				break;
			case 1:
				vmsize = 2*1024*1024;
				break;
			}
			break;
		default:
			return;
		}
	}
	else
		return;
Exemple #4
0
void
main(void)
{
	cgapost(0);
	mach0init();
	options();
	ioinit();
	i8250console();
	quotefmtinstall();
	screeninit();

	print("\nPlan 9\n");

	trapinit0();
	mmuinit0();

	kbdinit();
	i8253init();
	cpuidentify();
	meminit();
	confinit();
	archinit();
	if(!isa20on())
		panic("bootstrap didn't leave a20 address line enabled");
	xinit();
	if(i8237alloc != nil)
		i8237alloc();
	trapinit();
	printinit();
	cpuidprint();
	mmuinit();
	fpsavealloc();
	if(arch->intrinit)	/* launches other processors on an mp */
		arch->intrinit();
	timersinit();
	mathinit();
	kbdenable();
	if(arch->clockenable)
		arch->clockenable();
	procinit0();
	initseg();
	if(delaylink){
		bootlinks();
		pcimatch(0, 0, 0);
	}else
		links();
	conf.monitor = 1;
	chandevreset();
	cgapost(0xcd);

	pageinit();
	i8253link();
	swapinit();
	userinit();
	active.thunderbirdsarego = 1;

	cgapost(0x99);
	schedinit();
}
Exemple #5
0
static Vdev*
viopnpdevs(int typ)
{
	Vdev *vd, *h, *t;
	Pcidev *p;
	int n, i;

	h = t = nil;
	for(p = nil; p = pcimatch(p, 0, 0);){
		if(p->vid != 0x1AF4)
			continue;
		if((p->did < 0x1000) || (p->did >= 0x1040))
			continue;
		if(p->rid != 0)
			continue;
		if(pcicfgr16(p, 0x2E) != typ)
			continue;
		if((vd = malloc(sizeof(*vd))) == nil){
			print("virtio: no memory for Vdev\n");
			break;
		}
		vd->port = p->mem[0].bar & ~0x1;
		if(ioalloc(vd->port, p->mem[0].size, 0, "virtio") < 0){
			print("virtio: port %lux in use\n", vd->port);
			free(vd);
			continue;
		}
		vd->typ = typ;
		vd->pci = p;

		/* reset */
		outb(vd->port+Status, 0);

		vd->feat = inl(vd->port+Devfeat);
		outb(vd->port+Status, Acknowledge|Driver);
		for(i=0; i<nelem(vd->queue); i++){
			outs(vd->port+Qselect, i);
			n = ins(vd->port+Qsize);
			if(n == 0 || (n & (n-1)) != 0)
				break;
			if((vd->queue[i] = mkvqueue(n)) == nil)
				break;
			coherence();
			outl(vd->port+Qaddr, PADDR(vd->queue[i]->desc)/BY2PG);
		}
		vd->nqueue = i;
	
		if(h == nil)
			h = vd;
		else
			t->next = vd;
		t = vd;
	}

	return h;
}
Exemple #6
0
void
pcireset(void)
{
	Pcidev *p;

	for(p = nil; p = pcimatch(p, 0, 0); )
		/* don't mess with the bridges */
		if(p->ccrb != 0x06)
			pciclrbme(p);
}
Exemple #7
0
Pcidev*
pcimatchtbdf(int tbdf)
{
	Pcidev *p;

	for(p = nil; p = pcimatch(p, 0, 0); )
		if(p->tbdf == tbdf)
			break;
	return p;
}
Exemple #8
0
static void
pcireservemem(void)
{
	int i;
	Pcidev *p;

	for(p = nil; p = pcimatch(p, 0, 0); )
		for(i=0; i<nelem(p->mem); i++)
			if(p->mem[i].bar && (p->mem[i].bar&1) == 0)
				asmmapinit(p->mem[i].bar&~0x0F, p->mem[i].size, 5);
}
Exemple #9
0
static void
tdfxenable(VGAscr* scr)
{
	Pcidev *p;
	int i, *mmio;

	if(scr->mmio)
		return;
	if(p = pcimatch(nil, 0x121A, 0)){
		switch(p->did){
		case 0x0003:		/* Banshee */
		case 0x0005:		/* Avenger (a.k.a. Voodoo3) */
			break;
		default:
			return;
		}
	}
	else
		return;
	
	scr->mmio = vmap(p->mem[0].bar&~0x0F, p->mem[0].size);
	if(scr->mmio == nil)
		return;
	scr->pci = p;
	
	addvgaseg("3dfxmmio", p->mem[0].bar&~0x0F, p->mem[0].size);
	vgalinearpci(scr);
	if(scr->apsize)
		addvgaseg("3dfxscreen", scr->paddr, scr->apsize);

	/*
	 * Find a place for the cursor data in display memory.
	 * If SDRAM then there's 16MB memory else it's SGRAM
	 * and can count it based on the power-on straps -
	 * chip size can be 8Mb or 16Mb, and there can be 4 or
	 * 8 of them.
	 * Use the last 1KB of the framebuffer.
	 */
	mmio = (void*)((uchar*)scr->mmio+dramInit0);
	if(*(mmio+1) & 0x40000000)
		i = 16*1024*1024;
	else{
		if(*mmio & 0x08000000)
			i = 16*1024*1024/8;
		else
			i = 8*1024*1024/8;
		if(*mmio & 0x04000000)
			i *= 8;
		else
			i *= 4;
	}
	scr->storage = i - 1024;
}
Exemple #10
0
static Uart*
axppnp(void)
{
	Pcidev *p;
	int ctlrno;
	Uart *head, *tail, *uart;

	/*
	 * Loop through all PCI devices looking for simple serial
	 * controllers (ccrb == 0x07) and configure the ones which
	 * are familiar.
	 */
	head = tail = nil;
	ctlrno = 0;
	for(p = pcimatch(nil, 0, 0); p != nil; p = pcimatch(p, 0, 0)){
		if(p->ccrb != 0x07)
			continue;

		switch((p->did<<16)|p->vid){
		default:
			continue;
		case (0x6001<<16)|0x114F:	/* AvanstarXp */
			if((uart = axpalloc(ctlrno, p)) == nil)
				continue;
			break;
		}

		if(head != nil)
			tail->next = uart;
		else
			head = uart;
		for(tail = uart; tail->next != nil; tail = tail->next)
			;
		ctlrno++;
	}

	return head;
}
Exemple #11
0
static void
ne2000pnp(Ether* edev)
{
	int i, id;
	Pcidev *p;
	Ctlr *ctlr;

	/*
	 * Make a list of all ethernet controllers
	 * if not already done.
	 */
	if(ctlrhead == nil){
		p = nil;
		while(p = pcimatch(p, 0, 0)){
			if(p->ccrb != 0x02 || p->ccru != 0)
				continue;
			ctlr = malloc(sizeof(Ctlr));
			if(ctlr == nil)
				error(Enomem);
			ctlr->pcidev = p;

			if(ctlrhead != nil)
				ctlrtail->next = ctlr;
			else
				ctlrhead = ctlr;
			ctlrtail = ctlr;
		}
	}

	/*
	 * Is it a card with an unrecognised vid+did?
	 * Normally a search is made through all the found controllers
	 * for one which matches any of the known vid+did pairs.
	 * If a vid+did pair is specified a search is made for that
	 * specific controller only.
	 */
	id = 0;
	for(i = 0; i < edev->nopt; i++){
		if(cistrncmp(edev->opt[i], "id=", 3) == 0)
			id = strtol(&edev->opt[i][3], nil, 0);
	}

	if(id != 0)
		ne2000match(edev, id);
	else for(i = 0; ne2000pci[i].name; i++){
		if(ne2000match(edev, ne2000pci[i].id) != nil)
			break;
	}
}
Exemple #12
0
static void
wpipci(void)
{
	Pcidev *pdev;

	pdev = nil;
	while(pdev = pcimatch(pdev, 0x8086, 0)){
		Ctlr *ctlr;
		void *mem;
		switch(pdev->did){
		default:
			continue;
		case 0x4227:
			break;
		}

		/* Clear device-specific "PCI retry timeout" register (41h). */
		if(pcicfgr8(pdev, 0x41) != 0)
			pcicfgw8(pdev, 0x41, 0);

		pcisetbme(pdev);
		pcisetpms(pdev, 0);

		ctlr = malloc(sizeof(Ctlr));
		if(ctlr == nil) {
			print("wpi: unable to alloc Ctlr\n");
			continue;
		}
		ctlr->port = pdev->mem[0].bar & ~0x0F;
		mem = vmap(pdev->mem[0].bar & ~0x0F, pdev->mem[0].size);
		if(mem == nil) {
			print("wpi: can't map %8.8luX\n", pdev->mem[0].bar);
			free(ctlr);
			continue;
		}
		ctlr->nic = mem;
		ctlr->pdev = pdev;

		if(wpihead != nil)
			wpitail->link = ctlr;
		else
			wpihead = ctlr;
		wpitail = ctlr;
	}
}
Exemple #13
0
void
vgalinearpciid(VGAscr *scr, int vid, int did)
{
	Pcidev *p;

	p = nil;
	while((p = pcimatch(p, vid, 0)) != nil){
		if(p->ccrb != 3)	/* video card */
			continue;
		if(did != 0 && p->did != did)
			continue;
		break;
	}
	if(p == nil)
		error("pci video card not found");

	scr->pci = p;
	vgalinearpci(scr);
}
Exemple #14
0
/*  figure out what kind of interface we could have */
void
lm78reset(void)
{
	int pcs;
	Pcidev *p;

	lm78.ifc = None;
	p = nil;
	while((p = pcimatch(p, IntelVendID, 0)) != nil){
		switch(p->did){
		/*  these bridges use the PCSC to map the lm78 into port space. */
		/*  for this case the lm78's CS# select is connected to the PIIX's */
		/*  PCS# output and the bottom 3 bits of address are passed to the */
		/*  LM78's A0-A2 inputs. */
		case PiixID:
		case Piix3ID:
			pcs = pcicfgr16(p, PCSC);
			if(pcs & 3) {
				/* already enabled */
				lm78.port = pcs & ~3;
				lm78.ifc = Parallel;
				return;	
			}

			/*  enable the chip, use default address 0x50 */
			pcicfgw16(p, PCSC, 0x50|PCSC8bytes);
			pcs = pcicfgr16(p, PCSC);
			lm78.port = pcs & ~3;
			lm78.ifc = Parallel;
			return;

		/*  this bridge puts the lm78's serial interface on the smbus */
		case Piix4PMID:
			lm78.smbus = piix4smbus();
			if(lm78.smbus == nil)
				continue;
			print("found piix4 smbus, base %lud\n", lm78.smbus->base);
			lm78.ifc = Smbus;
			return;
		}
	}
}
Exemple #15
0
static void
iigreset(void)
{
	iig.scr.pci = pcimatch(nil, 0x8086, 0x0116);
	if (iig.scr.pci)
		print("Found sandybridge at 0x%x\n", iig.scr.pci->tbdf);
	else {
		print("NO sandybridge found\n");
		return;
	}
	/* on coreboot systems, which is what this is mainly for, the graphics memory is allocated and
	 * reserved. This little hack won't be permanent but we might as well see if we can get to that
	 * memory.
	 */
	void *x = vmap(iig.scr.pci->mem[1].bar, iig.scr.pci->mem[1].size);
	print("x is THIS! %p\n", x);
	if (x) {
		iig.scr.vaddr = x;
		iig.scr.paddr = iig.scr.pci->mem[1].bar;
		iig.scr.apsize = iig.scr.pci->mem[1].size;
	}
}
Exemple #16
0
static Uart *
oxpnp(void)
{
	Pcidev *p;
	Ctlr *ctlr;
	Port *port;
	int i;
	char *model;
	char name[12+1];
	Uart *head, *tail;
	static int ctlrno;

	p = nil;
	head = tail = nil;
	while(p = pcimatch(p, 0x1415, 0)){
		switch(p->did){
		case 0xc101:
		case 0xc105:
		case 0xc11b:
		case 0xc11f:
		case 0xc120:
		case 0xc124:
		case 0xc138:
		case 0xc13d:
		case 0xc140:
		case 0xc141:
		case 0xc144:
		case 0xc145:
		case 0xc158:
		case 0xc15d:
			model = "OXPCIe952";
			break;
		case 0xc208:
		case 0xc20d:
			model = "OXPCIe954";
			break;
		case 0xc308:
		case 0xc30d:
			model = "OXPCIe958";
			break;
		default:
			continue;
		}
		ctlr = malloc(sizeof *ctlr);
		if(ctlr == nil){
			print("oxpnp: out of memory\n");
			continue;
		}
		ctlr->pcidev = p;
		ctlr->mem = vmap(p->mem[0].bar & ~0xf, p->mem[0].size);
		if(ctlr->mem == nil){
			print("oxpnp: vmap failed\n");
			free(ctlr);
			continue;
		}
		snprint(name, sizeof name, "uartox%d", ctlrno);
		kstrdup(&ctlr->name, name);
		ctlr->nport = ctlr->mem[Nuart] & 0x1f;
		for(i = 0; i < ctlr->nport; ++i){
			port = &ctlr->port[i];
			port->ctlr = ctlr;
			port->mem = (u8int *)ctlr->mem + 0x1000 + 0x200*i;
			port->regs = port;
			snprint(name, sizeof name, "%s.%d", ctlr->name, i);
			kstrdup(&port->name, name);
			port->phys = &oxphysuart;
			if(head == nil)
				head = port;
			else
				tail->next = port;
			tail = port;
		}
		print("%s: %s: %d ports irq %d\n",
		    ctlr->name, model, ctlr->nport, p->intl);
		ctlrno++;
	}
	return head;
}
Exemple #17
0
static Uart*
uartpcipnp(void)
{
	Pcidev *p;
	char *name;
	int ctlrno, n, subid;
	Uart *head, *tail, *uart;

	/*
	 * Loop through all PCI devices looking for simple serial
	 * controllers (ccrb == 0x07) and configure the ones which
	 * are familiar. All suitable devices are configured to
	 * simply point to the generic i8250 driver.
	 */
	head = tail = nil;
	ctlrno = 0;
	for(p = pcimatch(nil, 0, 0); p != nil; p = pcimatch(p, 0, 0)){
		if(p->ccrb != 0x07 || p->ccru > 2)
			continue;

		switch((p->did<<16)|p->vid){
		default:
			continue;
		case (0x9835<<16)|0x9710:	/* StarTech PCI2S550 */
			uart = uartpci(ctlrno, p, 0, 1, 1843200, "PCI2S550-0");
			if(uart == nil)
				continue;
			uart->next = uartpci(ctlrno, p, 1, 1, 1843200, "PCI2S550-1");
			break;
		case (0x950A<<16)|0x1415:	/* Oxford Semi OX16PCI954 */
			/*
			 * These are common devices used by 3rd-party
			 * manufacturers.
			 * Must check the subsystem VID and DID for correct
			 * match, mostly to get the clock frequency right.
			 */
			subid = pcicfgr16(p, PciSVID);
			subid |= pcicfgr16(p, PciSID)<<16;
			switch(subid){
			default:
				continue;
			case (0x2000<<16)|0x131F:/* SIIG CyberSerial PCIe */
				uart = uartpci(ctlrno, p, 0, 1, 18432000, "CyberSerial-1S");
				if(uart == nil)
					continue;
				break;
			}
			break;
		case (0x9501<<16)|0x1415:	/* Oxford Semi OX16PCI954 */
			/*
			 * These are common devices used by 3rd-party
			 * manufacturers.
			 * Should check the subsystem VID and DID for correct
			 * match, mostly to get the clock frequency right.
			 */
			subid = pcicfgr16(p, PciSVID);
			subid |= pcicfgr16(p, PciSID)<<16;
			switch(subid){
			default:
				continue;
			case (0<<16)|0x1415:	/* StarTech PCI4S550 */
				uart = uartpci(ctlrno, p, 0, 1, 18432000, "PCI4S550-0");
				if(uart == nil)
					continue;
				break;
			}
			break;
		case (0x9050<<16)|0x10B5:	/* Perle PCI-Fast4 series */
		case (0x9030<<16)|0x10B5:	/* Perle Ultraport series */
			/*
			 * These devices consists of a PLX bridge (the above
			 * PCI VID+DID) behind which are some 16C654 UARTs.
			 * Must check the subsystem VID and DID for correct
			 * match.
			 */
			subid = pcicfgr16(p, PciSVID);
			subid |= pcicfgr16(p, PciSID)<<16;
			switch(subid){
			default:
				continue;
			case (0x0011<<16)|0x12E0:	/* Perle PCI-Fast16 */
				n = 16;
				name = "PCI-Fast16";
				break;
			case (0x0021<<16)|0x12E0:	/* Perle PCI-Fast8 */
				n = 8;
				name = "PCI-Fast8";
				break;
			case (0x0031<<16)|0x12E0:	/* Perle PCI-Fast4 */
				n = 4;
				name = "PCI-Fast4";
				break;
			case (0x0021<<16)|0x155F:	/* Perle Ultraport8 */
				n = 8;
				name = "Ultraport8";	/* 16C754 UARTs */
				break;
			}
			uart = uartpci(ctlrno, p, 2, n, 7372800, name);
			if(uart == nil)
				continue;
			break;
		}

		if(head != nil)
			tail->next = uart;
		else
			head = uart;
		for(tail = uart; tail->next != nil; tail = tail->next)
			;
		ctlrno++;
	}

	return head;
}
Exemple #18
0
void
main(void)
{
	Proc *savup;
	static ulong vfy = Datamagic;
	static char novga[] = "\nno vga; serial console only\n";

	savup = up;
	up = nil;
	/* m has been set by l32v.s */

	/*
	 * disable address wraps at 1MB boundaries.
	 * if we're 9boot, ldecomp.s already did this.
	 */
	a20init();

	mach0init();
//	options();		/* we don't get options passed to us */
	ioinit();
	/* we later call i8250console after plan9.ini has been read */
	i8250config("0");	/* configure serial port 0 with defaults */
	quotefmtinstall();
 	fmtinstall('i', eipfmt);
 	fmtinstall('I', eipfmt);
 	fmtinstall('E', eipfmt);
 	fmtinstall('V', eipfmt);
 	fmtinstall('M', eipfmt);
	screeninit();			/* cga setup */
	cgapost(0xc);

	trapinit0();
	mmuinit0();

	kbdinit();
	i8253init();
	cpuidentify();
	readlsconf();
	meminit();
	confinit();
	archinit();
	xinit();
	if(i8237alloc != nil)
		i8237alloc();		/* dma (for floppy) init */
	trapinit();
	printinit();
	sanity();
	cgapost(1);

	/*
	 * soekris servers have no built-in video but each has a serial port.
	 * they must see serial output, if any, before cga output because
	 * otherwise the soekris bios will translate cga output to serial
	 * output, which will garble serial console output.
	 */
	pcimatch(nil, 0, 0);		/* force scan of pci table */
	if (!pcivga) {
		screenputs = nil;
		uartputs(novga, sizeof novga - 1);
	}
	print(" %s\n\n", hellomsg);

	if (vfy != Datamagic)
		panic("data segment incorrectly aligned or loaded");
	if (savup)
		print("up was non-nil (%#p) upon entry to main; bss wasn't zeroed!\n",
			savup);

//	xsummary();
	cpuidprint();
	mmuinit();
	if(arch->intrinit)	/* launches other processors on an mp */
		arch->intrinit();
	timersinit();
	mathinit();
	kbdenable();
	/*
	 * 9loadusb runs much faster if we don't use the clock.
	 * perhaps we're competing with the bios for the use of it?
	 */
	if(!noclock && arch->clockenable)
		arch->clockenable();
	procinit0();
	initseg();
	if(delaylink){
		bootlinks();
		pcimatch(0, 0, 0);
	}else
		links();
	conf.monitor = 1;
	cgapost(0xcd);
	chandevreset();
	cgapost(2);
	pageinit();	/* must follow xinit, and conf.mem must be populated */
	i8253link();
	userinit();

	active.thunderbirdsarego = 1;
	cgapost(0xb0);
	schedinit();
}
Exemple #19
0
static void
i82563pci(void)
{
	int port, type, cls;
	Pcidev *p;
	Ctlr *ctlr;
	static int first = 1;

	if (first)
		first = 0;
	else
		return;

	p = nil;
	while(p = pcimatch(p, 0x8086, 0)){
		if(p->ccrb != 0x02 || p->ccru != 0)
			continue;
//print("i82563pci: did %4.4#x\n", p->did);
		switch(p->did){
		case 0x1096:
		case 0x10ba:
			type = i82563;
			break;
		case 0x1049:		/* mm */
		case 0x104a:		/* dm */
		case 0x104d:		/* v */
		case 0x10bd:		/* dm */
			type = i82566;
			break;
		case 0x10cd:		/* lf */
			type = i82567;
			break;
		case 0x10a4:
		case 0x105e:
			type = i82571;
			break;
		case 0x10b9:		/* sic, 82572 */
			type = i82572;
			break;
		case 0x108b:		/*  e */
		case 0x108c:		/*  e (iamt) */
		case 0x109a:		/*  l */
			type = i82573;
			break;
		case 0x10a7:		/* 82575eb */
			type = i82575;
			break;
		default:
			continue;
		}

		port = upamalloc(p->mem[0].bar & ~0x0F, p->mem[0].size, 0);
		if(port == 0){
			print("%s: can't map %d @ 0x%8.8lux\n", tname[type],
				p->mem[0].size, p->mem[0].bar);
			continue;
		}

		if(p->pcr & MemWrInv){
			cls = pcicfgr8(p, PciCLS) * 4;
			if(cls != CACHELINESZ)
				pcicfgw8(p, PciCLS, CACHELINESZ/4);
		}

		cls = pcicfgr8(p, PciCLS);
		switch(cls){
		default:
			print("%s: unexpected CLS - %d bytes\n",
				tname[type], cls*sizeof(long));
			break;
		case 0x00:
		case 0xFF:
			/* alphapc 164lx returns 0 */
			print("%s: unusable PciCLS: %d, using %d longs\n",
				tname[type], cls, CACHELINESZ/sizeof(long));
			cls = CACHELINESZ/sizeof(long);
			pcicfgw8(p, PciCLS, cls);
			break;
		case 0x08:
		case 0x10:
			break;
		}

		ctlr = malloc(sizeof(Ctlr));
		ctlr->port = port;
		ctlr->pcidev = p;
		ctlr->cls = cls*4;
		ctlr->type = type;
		ctlr->nic = KADDR(ctlr->port);
		if(i82563reset(ctlr)){
			free(ctlr);
			continue;
		}
		pcisetbme(p);

		if(ctlrhead != nil)
			ctlrtail->next = ctlr;
		else
			ctlrhead = ctlr;
		ctlrtail = ctlr;
	}
}
Exemple #20
0
static void
vesalinear(VGAscr *scr, int _1, int _2)
{
	int i, mode, size, havesize;
	uint8_t *p;
	uint32_t paddr;
	Pcidev *pci;

	if(hardscreen) {
		scr->vaddr = 0;
		scr->paddr = scr->apsize = 0;
		return;
	}

	vbecheck();
	mode = vbegetmode();
	/*
	 * bochs loses the top bits - cannot use this
	if((mode&(1<<14)) == 0)
		error("not in linear graphics mode");
	 */
	mode &= 0x3FFF;
	p = vbemodeinfo(mode);
	if(!(WORD(p+0) & (1<<4)))
		error("not in VESA graphics mode");
	if(!(WORD(p+0) & (1<<7)))
		error("not in linear graphics mode");

	paddr = LONG(p+40);
	size = WORD(p+20)*WORD(p+16);
	size = ROUNDUP(size, PGSZ);

	/*
	 * figure out max size of memory so that we have
	 * enough if the screen is resized.
	 */
	pci = nil;
	havesize = 0;
	while(!havesize && (pci = pcimatch(pci, 0, 0)) != nil){
		if(pci->ccrb != Pcibcdisp)
			continue;
		for(i=0; i<nelem(pci->mem); i++)
			if(paddr == (pci->mem[i].bar&~0x0F)){
				if(pci->mem[i].size > size)
					size = pci->mem[i].size;
				havesize = 1;
				break;
			}
	}

	/* no pci - heuristic guess */
	if (!havesize)
		if(size < 4*1024*1024)
			size = 4*1024*1024;
		else
			size = ROUND(size, 1024*1024);
	if(size > 16*1024*1024)		/* arbitrary */
		size = 16*1024*1024;

	vgalinearaddr(scr, paddr, size);
	if(scr->apsize)
		addvgaseg("vesascreen", scr->paddr, scr->apsize);

	if(Usesoftscreen){
		hardscreen = scr->vaddr;
		scr->vaddr = 0;
		scr->paddr = scr->apsize = 0;
	}
}