serial: Add baudrate setting for BIOS
Co-authored-by: Bryce Lanham <blanham@gmail.com>
diff --git a/CONFIG.md b/CONFIG.md
index 0652673c..85675598 100644
--- a/CONFIG.md
+++ b/CONFIG.md
@@ -59,6 +59,7 @@ Miscellaneous:
* `TIMEOUT` - Specifies the timeout in seconds before the first *entry* is automatically booted. If set to `no`, disable automatic boot. If set to `0`, boots default entry instantly (see `DEFAULT_ENTRY` key).
* `QUIET` - If set to `yes`, enable quiet mode, where all screen output except panics and important warnings is suppressed. If `TIMEOUT` is not 0, the `TIMEOUT` still occurs, and pressing any key during the timeout will reveal the menu and disable quiet mode.
* `SERIAL` - If set to `yes`, enable serial I/O for the bootloader.
+* `SERIAL_BAUDRATE` - If `SERIAL` is set to `yes`, this specifies the baudrate to use for serial I/O. Defaults to `9600`. BIOS only, ignored with Limine UEFI.
* `DEFAULT_ENTRY` - 1-based entry index of the entry which will be automatically selected at startup. If unspecified, it is `1`.
* `GRAPHICS` - If set to `no`, force CGA text mode for the boot menu, else use a video mode. Ignored with Limine UEFI.
* `VERBOSE` - If set to `yes`, print additional information during boot. Defaults to not verbose.
diff --git a/common/drivers/serial.s2.c b/common/drivers/serial.c
similarity index 62%
rename from common/drivers/serial.s2.c
rename to common/drivers/serial.c
index f2c885f3..4038caf9 100644
--- a/common/drivers/serial.s2.c
+++ b/common/drivers/serial.c
@@ -6,19 +6,32 @@
#include <drivers/serial.h>
#include <sys/cpu.h>
#include <lib/misc.h>
+#include <lib/config.h>
static bool serial_initialised = false;
+static uint32_t serial_baudrate;
static void serial_initialise(void) {
- if (serial_initialised) {
+ if (serial_initialised || config_ready == false) {
return;
}
+ char *baudrate_s = config_get_value(NULL, 0, "SERIAL_BAUDRATE");
+ if (baudrate_s == NULL) {
+ serial_baudrate = 9600;
+ } else {
+ serial_baudrate = strtoui(baudrate_s, NULL, 10);
+ }
+
// Init com1
outb(0x3f8 + 3, 0x00);
outb(0x3f8 + 1, 0x00);
outb(0x3f8 + 3, 0x80);
- outb(0x3f8 + 0, 0x0c); // 9600 baud
+
+ uint16_t divisor = (uint16_t)(115200 / serial_baudrate);
+ outb(0x3f8 + 0, divisor & 0xff);
+ outb(0x3f8 + 1, (divisor >> 8) & 0xff);
+
outb(0x3f8 + 1, 0x00);
outb(0x3f8 + 3, 0x03);
outb(0x3f8 + 2, 0xc7);
diff --git a/common/lib/print.s2.c b/common/lib/print.s2.c
index 45a4779f..d382c358 100644
--- a/common/lib/print.s2.c
+++ b/common/lib/print.s2.c
@@ -237,7 +237,7 @@ out:
}
#endif
#if defined (BIOS)
- if ((!quiet && serial) || COM_OUTPUT) {
+ if (stage3_loaded && ((!quiet && serial) || COM_OUTPUT)) {
switch (print_buf[i]) {
case '\n':
serial_out('\r');
diff --git a/common/linker_bios.ld.in b/common/linker_bios.ld.in
index 7a7d024f..095b075e 100644
--- a/common/linker_bios.ld.in
+++ b/common/linker_bios.ld.in
@@ -42,6 +42,7 @@ SECTIONS
term_notready = .;
terms = .;
terms_i = .;
+ serial_out = .;
stage3_addr = .;
#else
#ifdef LINKER_NOS2MAP
