Initial commit
Signed-off-by: Robert Allan James <robert.allan.james@gmail.com>
This commit is contained in:
@@ -68,6 +68,18 @@ extern void kernel_main(BootInfo *boot_info);
|
||||
|
||||
#if defined(ARCH_AMD64)
|
||||
#define COM1_BASE 0x3F8
|
||||
|
||||
/* Set by raw_serial_init() only after a 16550 presence probe succeeds.
|
||||
* When 0, raw_serial_putc() drops bytes immediately so boot can never
|
||||
* wedge on a board whose 0x3F8 decode has no UART behind it (real
|
||||
* mini-PCs like the Beelink SER5 typically expose no legacy COM port,
|
||||
* whereas QEMU always emulates one — this is why this hang only bites
|
||||
* on hardware). */
|
||||
static int raw_serial_ready = 0;
|
||||
|
||||
/* Bounded THRE poll bound: provides the same "drop, don't hang" safety
|
||||
* even if the probe above passes on a phantom decode. */
|
||||
#define RAW_SERIAL_THRE_MAX_SPIN 100000u
|
||||
/**
|
||||
* @brief Write a byte to an x86 I/O port via @c OUT (early-boot raw path).
|
||||
*
|
||||
@@ -137,6 +149,29 @@ static void raw_serial_init(void)
|
||||
raw_outb(COM1_BASE + 2, 0xC7);
|
||||
/* RTS/DSR set */
|
||||
raw_outb(COM1_BASE + 4, 0x0B);
|
||||
|
||||
/* 16550 presence probe: the scratch register (COM1+7) reads back what
|
||||
* was written only when a real UART owns this decode. Unclaimed ports
|
||||
* (or no I/O bridge routing) return garbage/0xFF, so the probe fails
|
||||
* and serial is disabled — otherwise raw_serial_putc()'s THRE poll
|
||||
* could spin forever on a board with no COM port. */
|
||||
raw_outb(COM1_BASE + 7, 0x5A);
|
||||
raw_serial_ready = (raw_inb(COM1_BASE + 7) == 0x5A) ? 1 : 0;
|
||||
|
||||
if (raw_serial_ready)
|
||||
{
|
||||
/* Sanity-check that THRE can actually be observed; if not, the
|
||||
* decode is a phantom — disable serial rather than risk a spin. */
|
||||
unsigned int spin = 0;
|
||||
while ((raw_inb(COM1_BASE + 5) & 0x20) == 0 && spin < RAW_SERIAL_THRE_MAX_SPIN)
|
||||
{
|
||||
++spin;
|
||||
}
|
||||
if (spin >= RAW_SERIAL_THRE_MAX_SPIN)
|
||||
{
|
||||
raw_serial_ready = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -154,7 +189,20 @@ static void raw_serial_init(void)
|
||||
*/
|
||||
static void raw_serial_putc(char c)
|
||||
{
|
||||
while ((raw_inb(COM1_BASE + 5) & 0x20) == 0) { }
|
||||
/* No UART behind 0x3F8 (or probe failed): drop the byte, never block. */
|
||||
if (!raw_serial_ready) return;
|
||||
|
||||
unsigned int spin = 0;
|
||||
while ((raw_inb(COM1_BASE + 5) & 0x20) == 0)
|
||||
{
|
||||
/* Bounded: on hardware whose probe passed but THRE never asserts
|
||||
* (phantom decode), drop the character instead of hanging boot. */
|
||||
if (++spin >= RAW_SERIAL_THRE_MAX_SPIN)
|
||||
{
|
||||
raw_serial_ready = 0;
|
||||
return;
|
||||
}
|
||||
}
|
||||
raw_outb(COM1_BASE + 0, (uint8_t)c);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user