Module Name: src
Committed By: jmcneill
Date: Mon Feb 5 23:07:42 UTC 2024
Modified Files:
src/sys/dev/usb: ehcireg.h
Log Message:
Ensure proper alignment/padding of EHCI hardware descriptors.
These descriptor structs are embedded in structs that contain additional
context for software. With a non cache coherent device and non-padded
descriptors, the device may issue a read/modify/write past the end of
the descriptor, clobbering software state in the process. This was the
root cause of multiple crashes on evbppc with a non cache coherent EHCI.
To generate a diff of this commit:
cvs rdiff -u -r1.37 -r1.38 src/sys/dev/usb/ehcireg.h
Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.
Modified files:
Index: src/sys/dev/usb/ehcireg.h
diff -u src/sys/dev/usb/ehcireg.h:1.37 src/sys/dev/usb/ehcireg.h:1.38
--- src/sys/dev/usb/ehcireg.h:1.37 Sat Apr 23 10:15:31 2016
+++ src/sys/dev/usb/ehcireg.h Mon Feb 5 23:07:42 2024
@@ -1,4 +1,4 @@
-/* $NetBSD: ehcireg.h,v 1.37 2016/04/23 10:15:31 skrll Exp $ */
+/* $NetBSD: ehcireg.h,v 1.38 2024/02/05 23:07:42 jmcneill Exp $ */
/*
* Copyright (c) 2001, 2004 The NetBSD Foundation, Inc.
@@ -203,6 +203,7 @@ typedef uint32_t ehci_isoc_trans_t;
typedef uint32_t ehci_isoc_bufr_ptr_t;
/* Isochronous Transfer Descriptor */
+#define EHCI_ITD_ALIGN 32
#define EHCI_ITD_NUFRAMES USB_UFRAMES_PER_FRAME
#define EHCI_ITD_NBUFFERS 7
typedef struct {
@@ -247,10 +248,10 @@ typedef struct {
#define EHCI_ITD_GET_MULTI(x) __SHIFTOUT((x), EHCI_ITD_MULTI_MASK)
#define EHCI_ITD_SET_MULTI(x) __SHIFTIN((x), EHCI_ITD_MULTI_MASK)
volatile ehci_isoc_bufr_ptr_t itd_bufr_hi[EHCI_ITD_NBUFFERS];
-} ehci_itd_t;
-#define EHCI_ITD_ALIGN 32
+} __aligned(EHCI_ITD_ALIGN) ehci_itd_t;
/* Split Transaction Isochronous Transfer Descriptor */
+#define EHCI_SITD_ALIGN 32
typedef struct {
volatile ehci_link_t sitd_next;
volatile uint32_t sitd_endp;
@@ -294,12 +295,12 @@ typedef struct {
volatile ehci_link_t sitd_back;
volatile uint32_t sitd_buffer_hi[EHCI_SITD_BUFFERS];
-} ehci_sitd_t;
-#define EHCI_SITD_ALIGN 32
+} __aligned(EHCI_SITD_ALIGN) ehci_sitd_t;
/* Queue Element Transfer Descriptor */
#define EHCI_QTD_NBUFFERS 5
#define EHCI_QTD_MAXTRANSFER (EHCI_QTD_NBUFFERS * EHCI_PAGE_SIZE)
+#define EHCI_QTD_ALIGN 32
typedef struct {
volatile ehci_link_t qtd_next;
volatile ehci_link_t qtd_altnext;
@@ -338,10 +339,10 @@ typedef struct {
#define EHCI_QTD_SET_TOGGLE(x) __SHIFTIN((x), EHCI_QTD_TOGGLE_MASK)
volatile ehci_physaddr_t qtd_buffer[EHCI_QTD_NBUFFERS];
volatile ehci_physaddr_t qtd_buffer_hi[EHCI_QTD_NBUFFERS];
-} ehci_qtd_t;
-#define EHCI_QTD_ALIGN 32
+} __aligned(EHCI_QTD_ALIGN) ehci_qtd_t;
/* Queue Head */
+#define EHCI_QH_ALIGN 32
typedef struct {
volatile ehci_link_t qh_link;
volatile uint32_t qh_endp;
@@ -388,16 +389,26 @@ typedef struct {
#define EHCI_QH_GET_MULT(x) __SHIFTOUT((x), EHCI_QH_MULTI_MASK)
#define EHCI_QH_SET_MULT(x) __SHIFTIN((x), EHCI_QH_MULTI_MASK)
volatile ehci_link_t qh_curqtd;
- ehci_qtd_t qh_qtd;
-} ehci_qh_t;
-#define EHCI_QH_ALIGN 32
+ /*
+ * The QH descriptor contains a TD overlay, but it is not
+ * 32-byte aligned, so declare the fields instead of embedding
+ * a ehci_qtd_t directly.
+ */
+ struct {
+ volatile ehci_link_t qtd_next;
+ volatile ehci_link_t qtd_altnext;
+ volatile uint32_t qtd_status;
+ volatile ehci_physaddr_t qtd_buffer[EHCI_QTD_NBUFFERS];
+ volatile ehci_physaddr_t qtd_buffer_hi[EHCI_QTD_NBUFFERS];
+ } qh_qtd;
+} __aligned(EHCI_QH_ALIGN) ehci_qh_t;
/* Periodic Frame Span Traversal Node */
+#define EHCI_FSTN_ALIGN 32
typedef struct {
volatile ehci_link_t fstn_link;
volatile ehci_link_t fstn_back;
-} ehci_fstn_t;
-#define EHCI_FSTN_ALIGN 32
+} __aligned(EHCI_FSTN_ALIGN) ehci_fstn_t;
/* Debug Port */
#define PCI_CAP_DEBUGPORT_OFFSET __BITS(28,16)