shithub: riscv

Download patch

ref: a4c6dc1d3d3a2ef3ec4d4ac49b16ec039c353cd7
parent: 2063019560c6a3154e6ef0e6e9f24d70c8ba09da
author: cinap_lenrek <[email protected]>
date: Sun Nov 1 20:14:30 EST 2020

aux/realemu: use #$/pci/B.D.Fraw to access pci config space

This prevents VESA bios from accessing the pci
CONFIG_ADDRESS/CONFIG_DATA registers (0xCF8/0xCFC)
directly to access pci config space.

This makes sure the access to pci config space is
properly serialized by the kernel.

--- a/sys/src/cmd/aux/realemu/dat.h
+++ b/sys/src/cmd/aux/realemu/dat.h
@@ -3,6 +3,7 @@
 typedef struct Bus Bus;
 typedef struct Cpu Cpu;
 typedef struct Pit Pit;
+typedef struct Pcidev Pcidev;
 
 enum {
 	RAX,
@@ -103,6 +104,13 @@
 	/* argument buffers */
 	ulong iabuf;
 	Iarg abuf[0x80];
+};
+
+struct Pcidev
+{
+	Pcidev	*next;
+	int	bdf;
+	int	fd;
 };
 
 struct Pit
--- a/sys/src/cmd/aux/realemu/fns.h
+++ b/sys/src/cmd/aux/realemu/fns.h
@@ -29,3 +29,12 @@
 void setgate(Pit *ch, uchar gate);
 uchar rpit(Pit *pit, uchar addr);
 void wpit(Pit *pit, uchar addr, uchar data);
+
+/* pci */
+Pcidev *pciopen(int bdf);
+int pcicfgr(Pcidev *pci, void *data, int len, int addr);
+int pcicfgw(Pcidev *pci, void *data, int len, int addr);
+
+#define BDFBNO(bdf)	(((int)bdf >> 16) & 0xFF)
+#define BDFDNO(bdf)	(((int)bdf >> 11) & 0x1F)
+#define BDFFNO(bdf)	(((int)bdf >>  8) & 0x07)
--- a/sys/src/cmd/aux/realemu/main.c
+++ b/sys/src/cmd/aux/realemu/main.c
@@ -29,6 +29,7 @@
 static int cputrace;
 static int porttrace;
 static Pit pit[3];
+static ulong pcicfgaddr;
 static uchar rtcaddr;
 
 static vlong pitclock;
@@ -155,8 +156,9 @@
 static ulong
 rport(void *, ulong p, int len)
 {
+	Pcidev *pci;
 	uchar data[4];
-	ulong w;
+	ulong w, addr;
 
 	switch(p){
 	case 0x20:	/* PIC 1 */
@@ -210,6 +212,24 @@
 	case 0xa1:
 		w = 0;
 		break;
+	case 0xcf8:
+		w = pcicfgaddr & ~0x7F000003;
+		break;
+	case 0xcfc: case 0xcfd: case 0xcfe: case 0xcff:
+		w = -1;
+		if((pcicfgaddr & (1<<31)) == 0)
+			break;
+		addr = (pcicfgaddr & 0xFC) | (p & 3);
+		if((pci = pciopen(pcicfgaddr & 0xFFFF00)) == nil)
+			break;
+		if(pcicfgr(pci, data, len, addr) != len)
+			break;
+		w = gw[len](data);
+		if(porttrace)
+			fprint(2, "pcicfgr %d.%d.%d %.2lux %.*lux\n",
+				BDFBNO(pcicfgaddr), BDFDNO(pcicfgaddr), BDFFNO(pcicfgaddr),
+				addr, len<<1, w);
+		break;
 	default:
 		if(pread(portfd[len], data, len, p) != len){
 			fprint(2, "bad %d bit port read %.4lux: %r\n", len*8, p);
@@ -225,7 +245,9 @@
 static void
 wport(void *, ulong p, ulong w, int len)
 {
+	Pcidev *pci;
 	uchar data[4];
+	ulong addr;
 
 	if(porttrace)
 		fprint(2, "wport %.4lux %.*lux\n", p, len<<1, w);
@@ -274,6 +296,22 @@
 	case 0xA1:
 		break;
 	
+	case 0xcf8:
+		pcicfgaddr = w;
+		break;
+	case 0xcfc: case 0xcfd: case 0xcfe: case 0xcff:
+		if((pcicfgaddr & (1<<31)) == 0)
+			break;
+		addr = (pcicfgaddr & 0xFC) | (p & 3);
+		if(porttrace)
+			fprint(2, "pcicfgw %d.%d.%d %.2lux %.*lux\n",
+				BDFBNO(pcicfgaddr), BDFDNO(pcicfgaddr), BDFFNO(pcicfgaddr),
+				addr, len<<1, w);
+		if((pci = pciopen(pcicfgaddr & 0xFFFF00)) == nil)
+			break;
+		pw[len](data, w);
+		pcicfgw(pci, data, len, addr);
+		break;
 	default:
 		pw[len](data, w);
 		if(pwrite(portfd[len], data, len, p) != len){
--- a/sys/src/cmd/aux/realemu/mkfile
+++ b/sys/src/cmd/aux/realemu/mkfile
@@ -3,7 +3,7 @@
 BIN=/$objtype/bin/aux
 
 TARG=realemu
-OFILES=decode.$O arg.$O xec.$O fmt.$O pit.$O main.$O
+OFILES=decode.$O arg.$O xec.$O fmt.$O pci.$O pit.$O main.$O
 HFILES=dat.h fns.h
 
 </sys/src/cmd/mkone
--- /dev/null
+++ b/sys/src/cmd/aux/realemu/pci.c
@@ -1,0 +1,45 @@
+#include <u.h>
+#include <libc.h>
+#include "dat.h"
+#include "fns.h"
+
+static Pcidev *devs;
+
+Pcidev*
+pciopen(int bdf)
+{
+	char path[64];
+	Pcidev *pci;
+
+	for(pci = devs; pci != nil; pci = pci->next){
+		if(pci->bdf == bdf){
+			if(pci->fd < 0)
+				return nil;
+			return pci;
+		}
+	}
+
+	pci = malloc(sizeof(Pcidev));
+	pci->bdf = bdf;
+
+	snprint(path, sizeof(path), "#$/pci/%d.%d.%draw",
+		BDFBNO(bdf), BDFDNO(bdf), BDFFNO(bdf));
+	pci->fd = open(path, ORDWR);
+
+	pci->next = devs;
+	devs = pci;
+
+	return pci;
+}
+
+int
+pcicfgr(Pcidev *pci, void *data, int len, int addr)
+{
+	return pread(pci->fd, data, len, addr);
+}
+
+int
+pcicfgw(Pcidev *pci, void *data, int len, int addr)
+{
+	return pwrite(pci->fd, data, len, addr);
+}