lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <alpine.DEB.2.21.2211160220250.54611@angie.orcam.me.uk>
Date:   Wed, 16 Nov 2022 21:36:01 +0000 (GMT)
From:   "Maciej W. Rozycki" <macro@...am.me.uk>
To:     Sudip Mukherjee <sudipm.mukherjee@...il.com>
cc:     linux-kernel@...r.kernel.org
Subject: [PATCH 3/6] parport_pc: Let chipset drivers mask ECR bits on
 writes

Provide an `ecr_writable' parameter to `__parport_pc_probe_port' so that 
callers can specify a mask of bits to modify on ECR writes.

To avoid the need for separate bit set and bit clear masks always set 
bit 0 whenever a non-zero mask has been set, as all the currently known 
cases where a mask is required, that is Oxford Semiconductor devices, do 
require this bit to be set.  If further cases are discovered where the 
bit is required to be clear, we can update code accordingly, but chances 
are very low as the bit is supposed to be read-only[1].

Skip ECR probing, which can be problematic as the Oxford Semiconductor 
OX12PCI840 part has been reported to lock up on setting bit 2, whenever 
a non-zero mask has been requested by a port subdriver, assuming that 
the ECR must be there if the subdriver has requested a specific way to 
access it.

References:

[1] "Extended Capabilities Port Protocol and ISA Interface Standard", 
    Microsoft Corporation, Revision: 1.14, July 14, 1993, Table 14 
    "Extended Control Register"

Signed-off-by: Maciej W. Rozycki <macro@...am.me.uk>
---
 drivers/parport/parport_pc.c |   46 +++++++++++++++++++++++++++----------------
 include/linux/parport_pc.h   |    3 ++
 2 files changed, 32 insertions(+), 17 deletions(-)

linux-parport-pc-ecr-write.diff
Index: linux-macro/drivers/parport/parport_pc.c
===================================================================
--- linux-macro.orig/drivers/parport/parport_pc.c
+++ linux-macro/drivers/parport/parport_pc.c
@@ -106,15 +106,22 @@ static int pnp_registered_parport;
 static void frob_econtrol(struct parport *pb, unsigned char m,
 			   unsigned char v)
 {
+	const struct parport_pc_private *priv = pb->physport->private_data;
+	unsigned char ecr_writable = priv->ecr_writable;
 	unsigned char ectr = 0;
+	unsigned char new;
 
 	if (m != 0xff)
 		ectr = inb(ECONTROL(pb));
 
-	pr_debug("frob_econtrol(%02x,%02x): %02x -> %02x\n",
-		 m, v, ectr, (ectr & ~m) ^ v);
+	new = (ectr & ~m) ^ v;
+	if (ecr_writable)
+		/* All known users of the ECR mask require bit 0 to be set. */
+		new = (new & ecr_writable) | 1;
 
-	outb((ectr & ~m) ^ v, ECONTROL(pb));
+	pr_debug("frob_econtrol(%02x,%02x): %02x -> %02x\n", m, v, ectr, new);
+
+	outb(new, ECONTROL(pb));
 }
 
 static inline void frob_set_mode(struct parport *p, int mode)
@@ -1479,21 +1486,24 @@ static int parport_ECR_present(struct pa
 	struct parport_pc_private *priv = pb->private_data;
 	unsigned char r = 0xc;
 
-	outb(r, CONTROL(pb));
-	if ((inb(ECONTROL(pb)) & 0x3) == (r & 0x3)) {
-		outb(r ^ 0x2, CONTROL(pb)); /* Toggle bit 1 */
+	if (!priv->ecr_writable) {
+		outb(r, CONTROL(pb));
+		if ((inb(ECONTROL(pb)) & 0x3) == (r & 0x3)) {
+			outb(r ^ 0x2, CONTROL(pb)); /* Toggle bit 1 */
 
-		r = inb(CONTROL(pb));
-		if ((inb(ECONTROL(pb)) & 0x2) == (r & 0x2))
-			goto no_reg; /* Sure that no ECR register exists */
-	}
+			r = inb(CONTROL(pb));
+			if ((inb(ECONTROL(pb)) & 0x2) == (r & 0x2))
+				/* Sure that no ECR register exists */
+				goto no_reg;
+		}
 
-	if ((inb(ECONTROL(pb)) & 0x3) != 0x1)
-		goto no_reg;
+		if ((inb(ECONTROL(pb)) & 0x3) != 0x1)
+			goto no_reg;
 
-	ECR_WRITE(pb, 0x34);
-	if (inb(ECONTROL(pb)) != 0x35)
-		goto no_reg;
+		ECR_WRITE(pb, 0x34);
+		if (inb(ECONTROL(pb)) != 0x35)
+			goto no_reg;
+	}
 
 	priv->ecr = 1;
 	outb(0xc, CONTROL(pb));
@@ -2005,7 +2015,8 @@ static struct parport *__parport_pc_prob
 					       int irq, int dma,
 					       struct device *dev,
 					       int irqflags,
-					       unsigned int mode_mask)
+					       unsigned int mode_mask,
+					       unsigned char ecr_writable)
 {
 	struct parport_pc_private *priv;
 	struct parport_operations *ops;
@@ -2054,6 +2065,7 @@ static struct parport *__parport_pc_prob
 	priv->ctr = 0xc;
 	priv->ctr_writable = ~0x10;
 	priv->ecr = 0;
+	priv->ecr_writable = ecr_writable;
 	priv->fifo_depth = 0;
 	priv->dma_buf = NULL;
 	priv->dma_handle = 0;
@@ -2256,7 +2268,7 @@ struct parport *parport_pc_probe_port(un
 				      int irqflags)
 {
 	return __parport_pc_probe_port(base, base_hi, irq, dma,
-				       dev, irqflags, 0);
+				       dev, irqflags, 0, 0);
 }
 EXPORT_SYMBOL(parport_pc_probe_port);
 
Index: linux-macro/include/linux/parport_pc.h
===================================================================
--- linux-macro.orig/include/linux/parport_pc.h
+++ linux-macro/include/linux/parport_pc.h
@@ -26,6 +26,9 @@ struct parport_pc_private {
 	/* Whether or not there's an ECR. */
 	int ecr;
 
+	/* Bitmask of writable ECR bits. */
+	unsigned char ecr_writable;
+
 	/* Number of PWords that FIFO will hold. */
 	int fifo_depth;
 

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ