* [PATCH RESEND v4] ACPI: SPCR: Support UART clock frequency field
@ 2026-09-13 16:17 Markus Probst
2026-09-13 16:23 ` sashiko-bot
0 siblings, 1 reply; 5+ messages in thread
From: Markus Probst @ 2026-09-13 16:17 UTC (permalink / raw)
To: Greg Kroah-Hartman, Jiri Slaby, Rafael J. Wysocki, Len Brown
Cc: linux-kernel, linux-serial, linux-acpi, Markus Probst
Prior to this patch, we assume the uart clock frequency is 1843200 Hz in
the early console. This behaviour results in garbage console output if the
actual uart clock frequency differs.
The UART Clock Frequency field was added in the Microsoft Serial Port
Console Redirection (SPCR) specification revision 1.08. If present, use it
to configure the serial port with the correct uart clock frequency.
Fallback to old behaviour if missing.
Add function `setup_earlycon_with_uartclk` to set uart clock frequency
while still allowing to reuse the same console string with
`add_preferred_console`.
Link: https://learn.microsoft.com/en-us/windows-hardware/drivers/serports/serial-port-console-redirection-table
Signed-off-by: Markus Probst <markus.probst@posteo.de>
---
Changes in v4:
- merge patches together
- rewrite commit message
- Link to v3: https://patch.msgid.link/20260615-acpi_spcr-v3-0-9a59ebad74ea@posteo.de
Changes in v3:
- add separate function for earlycon with uartclk
- Link to v2: https://patch.msgid.link/20260525-acpi_spcr-v2-0-c042089d73ca@posteo.de
Changes in v2:
- fix uart_clk_freq possibly being interpreted as parity/bits/flow
- Link to v1: https://patch.msgid.link/20260505-acpi_spcr-v1-1-fd4bc6f4eb53@posteo.de
---
drivers/acpi/spcr.c | 3 ++-
drivers/tty/serial/earlycon.c | 17 ++++++++++++-----
include/linux/serial_core.h | 11 +++++++++--
3 files changed, 23 insertions(+), 8 deletions(-)
diff --git a/drivers/acpi/spcr.c b/drivers/acpi/spcr.c
index 73cb933fdc89..c79c809f49d4 100644
--- a/drivers/acpi/spcr.c
+++ b/drivers/acpi/spcr.c
@@ -228,7 +228,8 @@ int __init acpi_parse_spcr(bool enable_earlycon, bool enable_console)
pr_info("console: %s\n", opts);
if (enable_earlycon)
- setup_earlycon(opts);
+ setup_earlycon_with_uartclk(opts,
+ table->header.revision >= 3 ? table->uart_clk_freq : 0);
if (enable_console)
err = add_preferred_console(uart, 0, opts + strlen(uart) + 1);
diff --git a/drivers/tty/serial/earlycon.c b/drivers/tty/serial/earlycon.c
index ab9af37f6cda..5a20fe9e3fb6 100644
--- a/drivers/tty/serial/earlycon.c
+++ b/drivers/tty/serial/earlycon.c
@@ -135,11 +135,14 @@ static int __init parse_options(struct earlycon_device *device, char *options)
return 0;
}
-static int __init register_earlycon(char *buf, const struct earlycon_id *match)
+static int __init register_earlycon(char *buf, unsigned int uart_clk_freq,
+ const struct earlycon_id *match)
{
int err;
struct uart_port *port = &early_console_dev.port;
+ port->uartclk = uart_clk_freq;
+
/* On parsing error, pass the options buf to the setup function */
if (buf && !parse_options(&early_console_dev, buf))
buf = NULL;
@@ -163,8 +166,9 @@ static int __init register_earlycon(char *buf, const struct earlycon_id *match)
}
/**
- * setup_earlycon - match and register earlycon console
- * @buf: earlycon param string
+ * setup_earlycon_with_uartclk - match and register earlycon console
+ * @buf: earlycon param string
+ * @uart_clk_freq: uart clock frequency in Hz or 0 for BASE_BAUD*16
*
* Registers the earlycon console matching the earlycon specified
* in the param string @buf. Acceptable param strings are of the form
@@ -177,10 +181,13 @@ static int __init register_earlycon(char *buf, const struct earlycon_id *match)
* <options> string in the 'options' parameter; all other forms set
* the parameter to NULL.
*
+ * If the uart clock frequency is specified in the 'options' parameter,
+ * the value of the param @uart_clk_freq will be ignored.
+ *
* Returns 0 if an attempt to register the earlycon was made,
* otherwise negative error code
*/
-int __init setup_earlycon(char *buf)
+int __init setup_earlycon_with_uartclk(char *buf, unsigned int uart_clk_freq)
{
const struct earlycon_id *match;
bool empty_compatible = true;
@@ -209,7 +216,7 @@ int __init setup_earlycon(char *buf)
} else
buf = NULL;
- return register_earlycon(buf, match);
+ return register_earlycon(buf, uart_clk_freq, match);
}
if (empty_compatible) {
diff --git a/include/linux/serial_core.h b/include/linux/serial_core.h
index bdc214386e4a..9b2bcd4295a9 100644
--- a/include/linux/serial_core.h
+++ b/include/linux/serial_core.h
@@ -1099,11 +1099,18 @@ int of_setup_earlycon(const struct earlycon_id *match, unsigned long node,
#ifdef CONFIG_SERIAL_EARLYCON
extern bool earlycon_acpi_spcr_enable __initdata;
-int setup_earlycon(char *buf);
+int setup_earlycon_with_uartclk(char *buf, unsigned int uart_clk_freq);
#else
static const bool earlycon_acpi_spcr_enable EARLYCON_USED_OR_UNUSED;
-static inline int setup_earlycon(char *buf) { return 0; }
+static inline int setup_earlycon_with_uartclk(char *buf, unsigned int uart_clk_freq)
+{
+ return 0;
+}
#endif
+static inline int setup_earlycon(char *buf)
+{
+ return setup_earlycon_with_uartclk(buf, 0);
+}
/* Variant of uart_console_registered() when the console_list_lock is held. */
static inline bool uart_console_registered_locked(struct uart_port *port)
---
base-commit: 237a1c39e8dfd3e1c6f1f023eea37a48ec04cc63
change-id: 20260430-acpi_spcr-61902fd923f2
-----BEGIN PGP SIGNATURE-----
iQJPBAABCAA5FiEEgnQYxPSsWOdyMMRzNHYf+OetQ9IFAmqOIQQbFIAAAAAABAAO
bWFudTIsMi41KzEuMTIsMiwyAAoJEDR2H/jnrUPSt08QALWMim65nIIS428BheYg
aq6BqxDGGqORhlf7aCFGTtNaeNDsu1Tny7sNTe+TEXpKl+AwoFTJ+4+bxl50AYyp
8Niod0JGjEoxkQKsU/aScvCvEvMuPXOABfUGFtzieNpfswU2n6LHjywy+RP1mTEn
aPP1arQGGGhe5b5lvolREN0VbGvymtiLr6P+qOhs76ib/dkOegq2/njBX7UlQ7Fy
dIQo1A/NayUn5F7VWQKUz6ZHLX9bVZYSe2gstKpl5C8Ybwfaj/HgeT1TAdMoQ2K/
KG0HgcWwIyoIaIms+yED6WSQKJwexx4zn/t2w/Qi2eSVF6WSqNdY3rrHf3sY3luj
g5wYs2AvNnGjQU6iNGs7DLwwasHgqwZcOwRIdTvY8z3UP5Wpj5y01a+dJJG378zR
cZhEQUmDn21jBlJvpqSKUoNRZc1L/8uNfQLbnOMVBNOUBXIQ9Z29j2IkqGsYeTG8
uUndjyA/2SlEU29w2G6/MnJykNiW4oMxryXabXvh8dXc+SPQkUIM71ivo4y2/HgM
3XGz9l+cgJk61F0oAHtzie7MorsEGVLMA2n4TpibkUCLRIjK3e5QvEBDHZILWHPA
k2b8dkF2cdu8Q4nbI3PzXUFzuq/rsBpncSvYd/zDQrEMxzhNUVmuX7B9Ws7I0P36
VKkGQqUFJNNx7LLynD7XaJ7l
=nupY
-----END PGP SIGNATURE-----
--
Markus Probst <markus.probst@posteo.de>
^ permalink raw reply related [flat|nested] 5+ messages in thread
* Re: [PATCH RESEND v4] ACPI: SPCR: Support UART clock frequency field
2026-09-13 16:17 Markus Probst
@ 2026-09-13 16:23 ` sashiko-bot
0 siblings, 0 replies; 5+ messages in thread
From: sashiko-bot @ 2026-09-13 16:23 UTC (permalink / raw)
To: Markus Probst; +Cc: linux-serial
> Prior to this patch, we assume the uart clock frequency is 1843200 Hz in
> the early console. This behaviour results in garbage console output if the
> actual uart clock frequency differs.
>
> The UART Clock Frequency field was added in the Microsoft Serial Port
> Console Redirection (SPCR) specification revision 1.08. If present, use it
> to configure the serial port with the correct uart clock frequency.
> Fallback to old behaviour if missing.
>
> Add function `setup_earlycon_with_uartclk` to set uart clock frequency
> while still allowing to reuse the same console string with
> `add_preferred_console`.
>
> Link: https://learn.microsoft.com/en-us/windows-hardware/drivers/serports/serial-port-console-redirection-table
> Signed-off-by: Markus Probst <markus.probst@posteo.de>
Sashiko has reviewed this patch and found no issues. It looks great!
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260913-acpi_spcr-v4-1-965654188e67@posteo.de?part=1
^ permalink raw reply [flat|nested] 5+ messages in thread
* [PATCH RESEND v4] ACPI: SPCR: Support UART clock frequency field
@ 2026-09-30 15:33 Markus Probst
2026-09-30 15:45 ` sashiko-bot
0 siblings, 1 reply; 5+ messages in thread
From: Markus Probst @ 2026-09-30 15:33 UTC (permalink / raw)
To: Greg Kroah-Hartman, Jiri Slaby, Rafael J. Wysocki, Len Brown
Cc: linux-kernel, linux-serial, linux-acpi, Markus Probst
Prior to this patch, we assume the uart clock frequency is 1843200 Hz in
the early console. This behaviour results in garbage console output if the
actual uart clock frequency differs.
The UART Clock Frequency field was added in the Microsoft Serial Port
Console Redirection (SPCR) specification revision 1.08. If present, use it
to configure the serial port with the correct uart clock frequency.
Fallback to old behaviour if missing.
Add function `setup_earlycon_with_uartclk` to set uart clock frequency
while still allowing to reuse the same console string with
`add_preferred_console`.
Link: https://learn.microsoft.com/en-us/windows-hardware/drivers/serports/serial-port-console-redirection-table
Signed-off-by: Markus Probst <markus.probst@posteo.de>
---
Changes in v4:
- merge patches together
- rewrite commit message
- Link to v3: https://patch.msgid.link/20260615-acpi_spcr-v3-0-9a59ebad74ea@posteo.de
Changes in v3:
- add separate function for earlycon with uartclk
- Link to v2: https://patch.msgid.link/20260525-acpi_spcr-v2-0-c042089d73ca@posteo.de
Changes in v2:
- fix uart_clk_freq possibly being interpreted as parity/bits/flow
- Link to v1: https://patch.msgid.link/20260505-acpi_spcr-v1-1-fd4bc6f4eb53@posteo.de
---
drivers/acpi/spcr.c | 3 ++-
drivers/tty/serial/earlycon.c | 17 ++++++++++++-----
include/linux/serial_core.h | 11 +++++++++--
3 files changed, 23 insertions(+), 8 deletions(-)
diff --git a/drivers/acpi/spcr.c b/drivers/acpi/spcr.c
index 73cb933fdc89..c79c809f49d4 100644
--- a/drivers/acpi/spcr.c
+++ b/drivers/acpi/spcr.c
@@ -228,7 +228,8 @@ int __init acpi_parse_spcr(bool enable_earlycon, bool enable_console)
pr_info("console: %s\n", opts);
if (enable_earlycon)
- setup_earlycon(opts);
+ setup_earlycon_with_uartclk(opts,
+ table->header.revision >= 3 ? table->uart_clk_freq : 0);
if (enable_console)
err = add_preferred_console(uart, 0, opts + strlen(uart) + 1);
diff --git a/drivers/tty/serial/earlycon.c b/drivers/tty/serial/earlycon.c
index ab9af37f6cda..5a20fe9e3fb6 100644
--- a/drivers/tty/serial/earlycon.c
+++ b/drivers/tty/serial/earlycon.c
@@ -135,11 +135,14 @@ static int __init parse_options(struct earlycon_device *device, char *options)
return 0;
}
-static int __init register_earlycon(char *buf, const struct earlycon_id *match)
+static int __init register_earlycon(char *buf, unsigned int uart_clk_freq,
+ const struct earlycon_id *match)
{
int err;
struct uart_port *port = &early_console_dev.port;
+ port->uartclk = uart_clk_freq;
+
/* On parsing error, pass the options buf to the setup function */
if (buf && !parse_options(&early_console_dev, buf))
buf = NULL;
@@ -163,8 +166,9 @@ static int __init register_earlycon(char *buf, const struct earlycon_id *match)
}
/**
- * setup_earlycon - match and register earlycon console
- * @buf: earlycon param string
+ * setup_earlycon_with_uartclk - match and register earlycon console
+ * @buf: earlycon param string
+ * @uart_clk_freq: uart clock frequency in Hz or 0 for BASE_BAUD*16
*
* Registers the earlycon console matching the earlycon specified
* in the param string @buf. Acceptable param strings are of the form
@@ -177,10 +181,13 @@ static int __init register_earlycon(char *buf, const struct earlycon_id *match)
* <options> string in the 'options' parameter; all other forms set
* the parameter to NULL.
*
+ * If the uart clock frequency is specified in the 'options' parameter,
+ * the value of the param @uart_clk_freq will be ignored.
+ *
* Returns 0 if an attempt to register the earlycon was made,
* otherwise negative error code
*/
-int __init setup_earlycon(char *buf)
+int __init setup_earlycon_with_uartclk(char *buf, unsigned int uart_clk_freq)
{
const struct earlycon_id *match;
bool empty_compatible = true;
@@ -209,7 +216,7 @@ int __init setup_earlycon(char *buf)
} else
buf = NULL;
- return register_earlycon(buf, match);
+ return register_earlycon(buf, uart_clk_freq, match);
}
if (empty_compatible) {
diff --git a/include/linux/serial_core.h b/include/linux/serial_core.h
index bdc214386e4a..9b2bcd4295a9 100644
--- a/include/linux/serial_core.h
+++ b/include/linux/serial_core.h
@@ -1099,11 +1099,18 @@ int of_setup_earlycon(const struct earlycon_id *match, unsigned long node,
#ifdef CONFIG_SERIAL_EARLYCON
extern bool earlycon_acpi_spcr_enable __initdata;
-int setup_earlycon(char *buf);
+int setup_earlycon_with_uartclk(char *buf, unsigned int uart_clk_freq);
#else
static const bool earlycon_acpi_spcr_enable EARLYCON_USED_OR_UNUSED;
-static inline int setup_earlycon(char *buf) { return 0; }
+static inline int setup_earlycon_with_uartclk(char *buf, unsigned int uart_clk_freq)
+{
+ return 0;
+}
#endif
+static inline int setup_earlycon(char *buf)
+{
+ return setup_earlycon_with_uartclk(buf, 0);
+}
/* Variant of uart_console_registered() when the console_list_lock is held. */
static inline bool uart_console_registered_locked(struct uart_port *port)
---
base-commit: 237a1c39e8dfd3e1c6f1f023eea37a48ec04cc63
change-id: 20260430-acpi_spcr-61902fd923f2
-----BEGIN PGP SIGNATURE-----
iQJPBAABCAA5FiEEgnQYxPSsWOdyMMRzNHYf+OetQ9IFAmqOIQQbFIAAAAAABAAO
bWFudTIsMi41KzEuMTIsMiwyAAoJEDR2H/jnrUPSt08QALWMim65nIIS428BheYg
aq6BqxDGGqORhlf7aCFGTtNaeNDsu1Tny7sNTe+TEXpKl+AwoFTJ+4+bxl50AYyp
8Niod0JGjEoxkQKsU/aScvCvEvMuPXOABfUGFtzieNpfswU2n6LHjywy+RP1mTEn
aPP1arQGGGhe5b5lvolREN0VbGvymtiLr6P+qOhs76ib/dkOegq2/njBX7UlQ7Fy
dIQo1A/NayUn5F7VWQKUz6ZHLX9bVZYSe2gstKpl5C8Ybwfaj/HgeT1TAdMoQ2K/
KG0HgcWwIyoIaIms+yED6WSQKJwexx4zn/t2w/Qi2eSVF6WSqNdY3rrHf3sY3luj
g5wYs2AvNnGjQU6iNGs7DLwwasHgqwZcOwRIdTvY8z3UP5Wpj5y01a+dJJG378zR
cZhEQUmDn21jBlJvpqSKUoNRZc1L/8uNfQLbnOMVBNOUBXIQ9Z29j2IkqGsYeTG8
uUndjyA/2SlEU29w2G6/MnJykNiW4oMxryXabXvh8dXc+SPQkUIM71ivo4y2/HgM
3XGz9l+cgJk61F0oAHtzie7MorsEGVLMA2n4TpibkUCLRIjK3e5QvEBDHZILWHPA
k2b8dkF2cdu8Q4nbI3PzXUFzuq/rsBpncSvYd/zDQrEMxzhNUVmuX7B9Ws7I0P36
VKkGQqUFJNNx7LLynD7XaJ7l
=nupY
-----END PGP SIGNATURE-----
--
Markus Probst <markus.probst@posteo.de>
^ permalink raw reply related [flat|nested] 5+ messages in thread
* Re: [PATCH RESEND v4] ACPI: SPCR: Support UART clock frequency field
2026-09-30 15:33 [PATCH RESEND v4] ACPI: SPCR: Support UART clock frequency field Markus Probst
@ 2026-09-30 15:45 ` sashiko-bot
2026-09-30 17:35 ` Markus Probst
0 siblings, 1 reply; 5+ messages in thread
From: sashiko-bot @ 2026-09-30 15:45 UTC (permalink / raw)
To: Markus Probst; +Cc: linux-serial
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [Medium] acpi: out-of-bounds read of SPCR uart_clk_freq field
--
commit 541ea063ef44d64e511d2deae13a8adcab45ebc7
Author: Markus Probst <markus.probst@posteo.de>
ACPI: SPCR: Support UART clock frequency field
This commit adds support for the UART Clock Frequency field introduced in the
Microsoft SPCR specification revision 1.08. It introduces a new function
setup_earlycon_with_uartclk() to configure the serial port with the correct
clock frequency from the SPCR table if available.
Link: https://learn.microsoft.com/en-us/windows-hardware/drivers/serports/serial-port-console-redirection-table
> diff --git a/drivers/acpi/spcr.c b/drivers/acpi/spcr.c
> index 73cb933fdc89b..c79c809f49d46 100644
> --- a/drivers/acpi/spcr.c
> +++ b/drivers/acpi/spcr.c
> @@ -228,7 +228,8 @@ int __init acpi_parse_spcr(bool enable_earlycon, bool enable_console)
> pr_info("console: %s\n", opts);
>
> if (enable_earlycon)
> - setup_earlycon(opts);
> + setup_earlycon_with_uartclk(opts,
> + table->header.revision >= 3 ? table->uart_clk_freq : 0);
[Severity: Medium]
Does this code risk an out-of-bounds memory read when accessing
table->uart_clk_freq?
In acpi_parse_spcr(), the table is mapped using acpi_get_table(), which
only maps the number of bytes specified by table->header.length.
If a malformed ACPI SPCR table is provided by system firmware where
table->header.revision >= 3 but the length is too small to contain
uart_clk_freq, could this access read past the mapped length?
This could result in unmapped memory accesses leading to an early boot kernel
panic, or silently reading garbage data which results in an incorrect early
console UART clock frequency.
Should there be a validation of table->header.length against the expected
size containing the uart_clk_freq field before accessing it?
>
> if (enable_console)
> err = add_preferred_console(uart, 0, opts + strlen(uart) + 1);
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260930-acpi_spcr-v4-1-ab649aa1f09c@posteo.de?part=1
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH RESEND v4] ACPI: SPCR: Support UART clock frequency field
2026-09-30 15:45 ` sashiko-bot
@ 2026-09-30 17:35 ` Markus Probst
0 siblings, 0 replies; 5+ messages in thread
From: Markus Probst @ 2026-09-30 17:35 UTC (permalink / raw)
To: sashiko-reviews; +Cc: linux-serial
[-- Attachment #1: Type: text/plain, Size: 2339 bytes --]
On Wed, 2026-09-30 at 15:45 +0000, sashiko-bot@kernel.org wrote:
> Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
> - [Medium] acpi: out-of-bounds read of SPCR uart_clk_freq field
> --
>
> commit 541ea063ef44d64e511d2deae13a8adcab45ebc7
> Author: Markus Probst <markus.probst@posteo.de>
>
> ACPI: SPCR: Support UART clock frequency field
>
> This commit adds support for the UART Clock Frequency field introduced in the
> Microsoft SPCR specification revision 1.08. It introduces a new function
> setup_earlycon_with_uartclk() to configure the serial port with the correct
> clock frequency from the SPCR table if available.
>
> Link: https://learn.microsoft.com/en-us/windows-hardware/drivers/serports/serial-port-console-redirection-table
>
> > diff --git a/drivers/acpi/spcr.c b/drivers/acpi/spcr.c
> > index 73cb933fdc89b..c79c809f49d46 100644
> > --- a/drivers/acpi/spcr.c
> > +++ b/drivers/acpi/spcr.c
> > @@ -228,7 +228,8 @@ int __init acpi_parse_spcr(bool enable_earlycon, bool enable_console)
> > pr_info("console: %s\n", opts);
> >
> > if (enable_earlycon)
> > - setup_earlycon(opts);
> > + setup_earlycon_with_uartclk(opts,
> > + table->header.revision >= 3 ? table->uart_clk_freq : 0);
>
> [Severity: Medium]
> Does this code risk an out-of-bounds memory read when accessing
> table->uart_clk_freq?
>
> In acpi_parse_spcr(), the table is mapped using acpi_get_table(), which
> only maps the number of bytes specified by table->header.length.
>
> If a malformed ACPI SPCR table is provided by system firmware where
> table->header.revision >= 3 but the length is too small to contain
> uart_clk_freq, could this access read past the mapped length?
>
> This could result in unmapped memory accesses leading to an early boot kernel
> panic, or silently reading garbage data which results in an incorrect early
> console UART clock frequency.
>
> Should there be a validation of table->header.length against the expected
> size containing the uart_clk_freq field before accessing it?
>
> >
> > if (enable_console)
> > err = add_preferred_console(uart, 0, opts + strlen(uart) + 1);
Fields from revision 4 are being accessed, so I don't think accessing
one from revision 3 requires more checking.
[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 870 bytes --]
^ permalink raw reply [flat|nested] 5+ messages in thread
end of thread, other threads:[~2026-09-30 17:35 UTC | newest]
Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-09-30 15:33 [PATCH RESEND v4] ACPI: SPCR: Support UART clock frequency field Markus Probst
2026-09-30 15:45 ` sashiko-bot
2026-09-30 17:35 ` Markus Probst
-- strict thread matches above, loose matches on Subject: below --
2026-09-13 16:17 Markus Probst
2026-09-13 16:23 ` sashiko-bot
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox