mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
* [PATCH v2] early: usb: xhci-dbc: Handle out of bounds xhci-xdbc capability
@ 2026-09-15  7:40 Umang Jain
  2026-09-15 12:11 ` Mathias Nyman
  0 siblings, 1 reply; 3+ messages in thread
From: Umang Jain @ 2026-09-15  7:40 UTC (permalink / raw)
  To: Greg Kroah-Hartman, Lucas De Marchi, Mathias Nyman
  Cc: linux-usb, linux-kernel, kernel-dev, Umang Jain

Currently, the early xhci-dbc assumes that the entire PCIe memory IO
can be entirely mapped  within the fixed boot time mappings
dictated by NR_FIX_BTMAPS. This patch handles the case where the PCIe
memory IO size can be larger than the fixed boot time mappings and
query the xhci debug extended capability in xdbc_map_pci_mmio().

This commit ensures that the xHCI debug capability can still be queried
when the PCIe memory IO space exceeds the fixmap size. In this scenario,
the base address is mapped uptil fixmap size and debug capabilities are
queried thereafter. Iterating over the entire PCIe BAR address size is
left for future improvement as and when, such a case arises.

Additionally, this brings the need to track the early_ioremap() mapped
size separately hence, introduce additional struct member xhci_base_length
in struct xdbc_state.

Signed-off-by: Umang Jain <uajain@igalia.com>
---
Changes in v2:
- Commit message update
- Changed and tested behaviour for mapping only first fixmap_size
  of PCIe Base address size instead of iteration over entire BAR size
- Updated comments
- Updated XDBC MAPPING SIZE to 64

v1:
- https://lore.kernel.org/all/20260720191249.1272328-1-uajain@igalia.com/
---
 drivers/usb/early/xhci-dbc.c | 78 ++++++++++++++++++++++++++++++++----
 drivers/usb/early/xhci-dbc.h |  1 +
 2 files changed, 71 insertions(+), 8 deletions(-)

diff --git a/drivers/usb/early/xhci-dbc.c b/drivers/usb/early/xhci-dbc.c
index 41118bba9197..d2e6ae410b0d 100644
--- a/drivers/usb/early/xhci-dbc.c
+++ b/drivers/usb/early/xhci-dbc.c
@@ -35,10 +35,23 @@ static bool early_console_keep;
 static inline void xdbc_trace(const char *fmt, ...) { }
 #endif /* XDBC_TRACE */
 
+/* Size of xHCI debug capability structure as per section 7.6.8 of xHCI spec. */
+#define XDBC_MAPPING_SIZE	64
+
+enum xdbc_capability_flags {
+	XDBC_CAP_FLAG_NONE		= 0,
+	XDBC_CAP_FLAG_LEGACY		= 1 << 0,
+	XDBC_CAP_FLAG_PROTOCOL		= 1 << 1,
+	XDBC_CAP_FLAG_DEBUG		= 1 << 2,
+};
+
 static void __iomem * __init xdbc_map_pci_mmio(u32 bus, u32 dev, u32 func)
 {
-	u64 val64, sz64, mask64;
+	u64 val64, sz64, mask64, fixmap_size, mapped_size;
+	enum xdbc_capability_flags cap_flags = XDBC_CAP_FLAG_NONE;
+	bool found_all_caps = false;
 	void __iomem *base;
+	int offset;
 	u32 val, sz;
 	u8 byte;
 
@@ -85,7 +98,56 @@ static void __iomem * __init xdbc_map_pci_mmio(u32 bus, u32 dev, u32 func)
 
 	xdbc.xhci_start = val64;
 	xdbc.xhci_length = sz64;
-	base = early_ioremap(val64, sz64);
+
+	fixmap_size = NR_FIX_BTMAPS << PAGE_SHIFT;
+	if (sz64 < fixmap_size) {
+		xdbc.xhci_base_length = sz64;
+		return early_ioremap(val64, sz64);
+	}
+
+	/*
+	 * Base address size is greater than fixed size boot time mappings
+	 * hence, map maximum allowed fixmap size from base address and
+	 * determine if the required extended capabilities lies within the
+	 * fixmap.
+	 */
+	base = early_ioremap(val64, fixmap_size);
+	offset = xhci_find_next_ext_cap(base, 0, 0);
+	mapped_size = fixmap_size;
+
+	while (offset < fixmap_size) {
+		val = readl(base + offset);
+		switch (XHCI_EXT_CAPS_ID(val)) {
+		case XHCI_EXT_CAPS_DEBUG:
+			if (offset + XDBC_MAPPING_SIZE < fixmap_size)
+				cap_flags |= XDBC_CAP_FLAG_DEBUG;
+			break;
+		case XHCI_EXT_CAPS_PROTOCOL:
+			cap_flags |= XDBC_CAP_FLAG_PROTOCOL;
+			break;
+		case XHCI_EXT_CAPS_LEGACY:
+			cap_flags |= XDBC_CAP_FLAG_LEGACY;
+			break;
+		}
+
+		if ((cap_flags & XDBC_CAP_FLAG_DEBUG) &&
+		    (cap_flags & XDBC_CAP_FLAG_PROTOCOL) &&
+		    (cap_flags & XDBC_CAP_FLAG_LEGACY)) {
+			found_all_caps = true;
+			break;
+		}
+
+		offset = xhci_find_next_ext_cap(base, offset, 0);
+		if (!offset)
+			break;
+	}
+
+	if (found_all_caps) {
+		xdbc.xhci_base_length = fixmap_size;
+	} else {
+		xdbc.xhci_base_length = 0;
+		base = NULL;
+	}
 
 	return base;
 }
@@ -643,9 +705,9 @@ int __init early_xdbc_parse_parameter(char *s, int keep_early)
 	offset = xhci_find_next_ext_cap(xdbc.xhci_base, 0, XHCI_EXT_CAPS_DEBUG);
 	if (!offset) {
 		pr_notice("xhci host doesn't support debug capability\n");
-		early_iounmap(xdbc.xhci_base, xdbc.xhci_length);
+		early_iounmap(xdbc.xhci_base, xdbc.xhci_base_length);
 		xdbc.xhci_base = NULL;
-		xdbc.xhci_length = 0;
+		xdbc.xhci_base_length = 0;
 
 		return -ENODEV;
 	}
@@ -682,9 +744,9 @@ int __init early_xdbc_setup_hardware(void)
 		xdbc.table_base = NULL;
 		xdbc.out_buf = NULL;
 
-		early_iounmap(xdbc.xhci_base, xdbc.xhci_length);
+		early_iounmap(xdbc.xhci_base, xdbc.xhci_base_length);
 		xdbc.xhci_base = NULL;
-		xdbc.xhci_length = 0;
+		xdbc.xhci_base_length = 0;
 	}
 
 	return ret;
@@ -987,7 +1049,7 @@ static int __init xdbc_init(void)
 	}
 
 	raw_spin_lock_irqsave(&xdbc.lock, flags);
-	early_iounmap(xdbc.xhci_base, xdbc.xhci_length);
+	early_iounmap(xdbc.xhci_base, xdbc.xhci_base_length);
 	xdbc.xhci_base = base;
 	offset = xhci_find_next_ext_cap(xdbc.xhci_base, 0, XHCI_EXT_CAPS_DEBUG);
 	xdbc.xdbc_reg = (struct xdbc_regs __iomem *)(xdbc.xhci_base + offset);
@@ -1004,7 +1066,7 @@ static int __init xdbc_init(void)
 	memblock_phys_free(xdbc.table_dma, PAGE_SIZE);
 	memblock_phys_free(xdbc.out_dma, PAGE_SIZE);
 	writel(0, &xdbc.xdbc_reg->control);
-	early_iounmap(xdbc.xhci_base, xdbc.xhci_length);
+	early_iounmap(xdbc.xhci_base, xdbc.xhci_base_length);
 
 	return ret;
 }
diff --git a/drivers/usb/early/xhci-dbc.h b/drivers/usb/early/xhci-dbc.h
index 8b4d71de45fc..e2aefb796084 100644
--- a/drivers/usb/early/xhci-dbc.h
+++ b/drivers/usb/early/xhci-dbc.h
@@ -144,6 +144,7 @@ struct xdbc_state {
 	u32			dev;
 	u32			func;
 	void __iomem		*xhci_base;
+	size_t			xhci_base_length;
 	u64			xhci_start;
 	size_t			xhci_length;
 	int			port_number;
-- 
2.55.0


^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: [PATCH v2] early: usb: xhci-dbc: Handle out of bounds xhci-xdbc capability
  2026-09-15  7:40 [PATCH v2] early: usb: xhci-dbc: Handle out of bounds xhci-xdbc capability Umang Jain
@ 2026-09-15 12:11 ` Mathias Nyman
  2026-09-15 13:22   ` Umang Jain
  0 siblings, 1 reply; 3+ messages in thread
From: Mathias Nyman @ 2026-09-15 12:11 UTC (permalink / raw)
  To: Umang Jain, Greg Kroah-Hartman, Lucas De Marchi
  Cc: linux-usb, linux-kernel, kernel-dev

On 9/15/26 10:40, Umang Jain wrote:
> Currently, the early xhci-dbc assumes that the entire PCIe memory IO
> can be entirely mapped  within the fixed boot time mappings
> dictated by NR_FIX_BTMAPS. This patch handles the case where the PCIe
> memory IO size can be larger than the fixed boot time mappings and
> query the xhci debug extended capability in xdbc_map_pci_mmio().
> 
> This commit ensures that the xHCI debug capability can still be queried
> when the PCIe memory IO space exceeds the fixmap size. In this scenario,
> the base address is mapped uptil fixmap size and debug capabilities are
> queried thereafter. Iterating over the entire PCIe BAR address size is
> left for future improvement as and when, such a case arises.
> 
> Additionally, this brings the need to track the early_ioremap() mapped
> size separately hence, introduce additional struct member xhci_base_length
> in struct xdbc_state.
> 
> Signed-off-by: Umang Jain <uajain@igalia.com>
> ---
> Changes in v2:
> - Commit message update
> - Changed and tested behaviour for mapping only first fixmap_size
>    of PCIe Base address size instead of iteration over entire BAR size
> - Updated comments
> - Updated XDBC MAPPING SIZE to 64

Thanks, this starts to look good.

Some small fixes and cleanups still needed.

> 
> v1:
> - https://lore.kernel.org/all/20260720191249.1272328-1-uajain@igalia.com/
> ---
>   drivers/usb/early/xhci-dbc.c | 78 ++++++++++++++++++++++++++++++++----
>   drivers/usb/early/xhci-dbc.h |  1 +
>   2 files changed, 71 insertions(+), 8 deletions(-)
> 
> diff --git a/drivers/usb/early/xhci-dbc.c b/drivers/usb/early/xhci-dbc.c
> index 41118bba9197..d2e6ae410b0d 100644
> --- a/drivers/usb/early/xhci-dbc.c
> +++ b/drivers/usb/early/xhci-dbc.c
> @@ -35,10 +35,23 @@ static bool early_console_keep;
>   static inline void xdbc_trace(const char *fmt, ...) { }
>   #endif /* XDBC_TRACE */
>   
> +/* Size of xHCI debug capability structure as per section 7.6.8 of xHCI spec. */
> +#define XDBC_MAPPING_SIZE	64
> +
> +enum xdbc_capability_flags {
> +	XDBC_CAP_FLAG_NONE		= 0,
> +	XDBC_CAP_FLAG_LEGACY		= 1 << 0,
> +	XDBC_CAP_FLAG_PROTOCOL		= 1 << 1,
> +	XDBC_CAP_FLAG_DEBUG		= 1 << 2,
> +};
> +
>   static void __iomem * __init xdbc_map_pci_mmio(u32 bus, u32 dev, u32 func)
>   {
> -	u64 val64, sz64, mask64;
> +	u64 val64, sz64, mask64, fixmap_size, mapped_size;

mapped_size in no longer needed. Can be removed

> +	enum xdbc_capability_flags cap_flags = XDBC_CAP_FLAG_NONE;
> +	bool found_all_caps = false;
>   	void __iomem *base;
> +	int offset;
>   	u32 val, sz;
>   	u8 byte;
>   
> @@ -85,7 +98,56 @@ static void __iomem * __init xdbc_map_pci_mmio(u32 bus, u32 dev, u32 func)
>   
>   	xdbc.xhci_start = val64;
>   	xdbc.xhci_length = sz64;
> -	base = early_ioremap(val64, sz64);
> +
> +	fixmap_size = NR_FIX_BTMAPS << PAGE_SHIFT;
> +	if (sz64 < fixmap_size) {
> +		xdbc.xhci_base_length = sz64;
> +		return early_ioremap(val64, sz64);
> +	}
> +
> +	/*
> +	 * Base address size is greater than fixed size boot time mappings
> +	 * hence, map maximum allowed fixmap size from base address and
> +	 * determine if the required extended capabilities lies within the
> +	 * fixmap.
> +	 */
> +	base = early_ioremap(val64, fixmap_size);

if (!base)
	return NULL;

> +	offset = xhci_find_next_ext_cap(base, 0, 0);
> +	mapped_size = fixmap_size;

mapped_size not used

> +
> +	while (offset < fixmap_size) {
> +		val = readl(base + offset);
> +		switch (XHCI_EXT_CAPS_ID(val)) {
> +		case XHCI_EXT_CAPS_DEBUG:
> +			if (offset + XDBC_MAPPING_SIZE < fixmap_size)
> +				cap_flags |= XDBC_CAP_FLAG_DEBUG;
> +			break;
> +		case XHCI_EXT_CAPS_PROTOCOL:
> +			cap_flags |= XDBC_CAP_FLAG_PROTOCOL;
> +			break;
> +		case XHCI_EXT_CAPS_LEGACY:
> +			cap_flags |= XDBC_CAP_FLAG_LEGACY;
> +			break;
> +		}
> +
> +		if ((cap_flags & XDBC_CAP_FLAG_DEBUG) &&
> +		    (cap_flags & XDBC_CAP_FLAG_PROTOCOL) &&
> +		    (cap_flags & XDBC_CAP_FLAG_LEGACY)) {
> +			found_all_caps = true;
> +			break;
> +		}
> +
> +		offset = xhci_find_next_ext_cap(base, offset, 0);
> +		if (!offset)
> +			break;
> +	}
> +
> +	if (found_all_caps) {
> +		xdbc.xhci_base_length = fixmap_size;
> +	} else {
> +		xdbc.xhci_base_length = 0;
> +		base = NULL;

we need to early_iounmap() in this fail path before returning NULL.

> +	}
>   
>   	return base;
>   }

Thanks
Mathias


^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: [PATCH v2] early: usb: xhci-dbc: Handle out of bounds xhci-xdbc capability
  2026-09-15 12:11 ` Mathias Nyman
@ 2026-09-15 13:22   ` Umang Jain
  0 siblings, 0 replies; 3+ messages in thread
From: Umang Jain @ 2026-09-15 13:22 UTC (permalink / raw)
  To: Mathias Nyman
  Cc: Greg Kroah-Hartman, Lucas De Marchi, linux-usb, linux-kernel, kernel-dev

On 2026-09-15 12:11, Mathias Nyman wrote:
> On 9/15/26 10:40, Umang Jain wrote:
>> Currently, the early xhci-dbc assumes that the entire PCIe memory IO
>> can be entirely mapped  within the fixed boot time mappings
>> dictated by NR_FIX_BTMAPS. This patch handles the case where the PCIe
>> memory IO size can be larger than the fixed boot time mappings and
>> query the xhci debug extended capability in xdbc_map_pci_mmio().
>> 
>> This commit ensures that the xHCI debug capability can still be queried
>> when the PCIe memory IO space exceeds the fixmap size. In this scenario,
>> the base address is mapped uptil fixmap size and debug capabilities are
>> queried thereafter. Iterating over the entire PCIe BAR address size is
>> left for future improvement as and when, such a case arises.
>> 
>> Additionally, this brings the need to track the early_ioremap() mapped
>> size separately hence, introduce additional struct member xhci_base_length
>> in struct xdbc_state.
>> 
>> Signed-off-by: Umang Jain <uajain@igalia.com>
>> ---
>> Changes in v2:
>> - Commit message update
>> - Changed and tested behaviour for mapping only first fixmap_size
>>    of PCIe Base address size instead of iteration over entire BAR size
>> - Updated comments
>> - Updated XDBC MAPPING SIZE to 64
> 
> Thanks, this starts to look good.
> 
> Some small fixes and cleanups still needed.
> 
>> 
>> v1:
>> - https://lore.kernel.org/all/20260720191249.1272328-1-uajain@igalia.com/
>> ---
>>   drivers/usb/early/xhci-dbc.c | 78 ++++++++++++++++++++++++++++++++----
>>   drivers/usb/early/xhci-dbc.h |  1 +
>>   2 files changed, 71 insertions(+), 8 deletions(-)
>> 
>> diff --git a/drivers/usb/early/xhci-dbc.c b/drivers/usb/early/xhci-dbc.c
>> index 41118bba9197..d2e6ae410b0d 100644
>> --- a/drivers/usb/early/xhci-dbc.c
>> +++ b/drivers/usb/early/xhci-dbc.c
>> @@ -35,10 +35,23 @@ static bool early_console_keep;
>>   static inline void xdbc_trace(const char *fmt, ...) { }
>>   #endif /* XDBC_TRACE */
>>   +/* Size of xHCI debug capability structure as per section 7.6.8 of xHCI spec. */
>> +#define XDBC_MAPPING_SIZE	64
>> +
>> +enum xdbc_capability_flags {
>> +	XDBC_CAP_FLAG_NONE		= 0,
>> +	XDBC_CAP_FLAG_LEGACY		= 1 << 0,
>> +	XDBC_CAP_FLAG_PROTOCOL		= 1 << 1,
>> +	XDBC_CAP_FLAG_DEBUG		= 1 << 2,
>> +};
>> +
>>   static void __iomem * __init xdbc_map_pci_mmio(u32 bus, u32 dev, u32 func)
>>   {
>> -	u64 val64, sz64, mask64;
>> +	u64 val64, sz64, mask64, fixmap_size, mapped_size;
> 
> mapped_size in no longer needed. Can be removed

ah right, fallout from last version / changing implementation
> 
>> +	enum xdbc_capability_flags cap_flags = XDBC_CAP_FLAG_NONE;
>> +	bool found_all_caps = false;
>>   	void __iomem *base;
>> +	int offset;
>>   	u32 val, sz;
>>   	u8 byte;
>>   @@ -85,7 +98,56 @@ static void __iomem * __init xdbc_map_pci_mmio(u32 bus, u32 dev, u32 func)
>>     	xdbc.xhci_start = val64;
>>   	xdbc.xhci_length = sz64;
>> -	base = early_ioremap(val64, sz64);
>> +
>> +	fixmap_size = NR_FIX_BTMAPS << PAGE_SHIFT;
>> +	if (sz64 < fixmap_size) {
>> +		xdbc.xhci_base_length = sz64;
>> +		return early_ioremap(val64, sz64);
>> +	}
>> +
>> +	/*
>> +	 * Base address size is greater than fixed size boot time mappings
>> +	 * hence, map maximum allowed fixmap size from base address and
>> +	 * determine if the required extended capabilities lies within the
>> +	 * fixmap.
>> +	 */
>> +	base = early_ioremap(val64, fixmap_size);
> 
> if (!base)
> 	return NULL;
> 
>> +	offset = xhci_find_next_ext_cap(base, 0, 0);
>> +	mapped_size = fixmap_size;
> 
> mapped_size not used
> 
>> +
>> +	while (offset < fixmap_size) {
>> +		val = readl(base + offset);
>> +		switch (XHCI_EXT_CAPS_ID(val)) {
>> +		case XHCI_EXT_CAPS_DEBUG:
>> +			if (offset + XDBC_MAPPING_SIZE < fixmap_size)
>> +				cap_flags |= XDBC_CAP_FLAG_DEBUG;
>> +			break;
>> +		case XHCI_EXT_CAPS_PROTOCOL:
>> +			cap_flags |= XDBC_CAP_FLAG_PROTOCOL;
>> +			break;
>> +		case XHCI_EXT_CAPS_LEGACY:
>> +			cap_flags |= XDBC_CAP_FLAG_LEGACY;
>> +			break;
>> +		}
>> +
>> +		if ((cap_flags & XDBC_CAP_FLAG_DEBUG) &&
>> +		    (cap_flags & XDBC_CAP_FLAG_PROTOCOL) &&
>> +		    (cap_flags & XDBC_CAP_FLAG_LEGACY)) {
>> +			found_all_caps = true;
>> +			break;
>> +		}
>> +
>> +		offset = xhci_find_next_ext_cap(base, offset, 0);
>> +		if (!offset)
>> +			break;
>> +	}
>> +
>> +	if (found_all_caps) {
>> +		xdbc.xhci_base_length = fixmap_size;
>> +	} else {
>> +		xdbc.xhci_base_length = 0;
>> +		base = NULL;
> 
> we need to early_iounmap() in this fail path before returning NULL.

good catch ;-)

Thanks for review, I'll address and send out new version soon.

Are we sure we intend to keep this implementation? And leave passing
over the entire PCIe BAR range for later ?
> 
>> +	}
>>     	return base;
>>   }
> 
> Thanks
> Mathias

^ permalink raw reply	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2026-09-15 13:22 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-09-15  7:40 [PATCH v2] early: usb: xhci-dbc: Handle out of bounds xhci-xdbc capability Umang Jain
2026-09-15 12:11 ` Mathias Nyman
2026-09-15 13:22   ` Umang Jain

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

all inboxes | Powered by JetHome®