Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add kernel console swapping & port ttyS0 registration on broken platf…
…orms
- Loading branch information
1 parent
76c36a4
commit c390f74
Showing
10 changed files
with
232 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,183 @@ | ||
#include "uart_fixer.h" | ||
#include "../common.h" | ||
#include "../../config/runtime_config.h" //hw_config | ||
#include "../../internal/call_protected.h" //early_serial_setup(), update_console_cmdline() | ||
#include <asm/serial.h> //flags for pc_com* | ||
#include <linux/serial_core.h> //struct uart_port | ||
#include <linux/serial_8250.h> //serial8250_unregister_port | ||
#include <linux/console.h> //console_lock(), console_unlock() | ||
#include <linux/sched.h> //for_each_process, kill_pgrp | ||
|
||
//They changed name of flags const: https://github.com/torvalds/linux/commit/196cf358422517b3ff3779c46a1f3e26fb084172 | ||
#if LINUX_VERSION_CODE < KERNEL_VERSION(3,18,0) | ||
#define STD_COMX_FLAGS STD_COM_FLAGS | ||
#endif | ||
|
||
#define CONSOLE_NAME_UART "ttyS" | ||
#define CONSOLE_BAUD_UART "115200n8" | ||
//These definitions are taken from asm/serial.h for a normal (i.e. non-swapped) UART1/COM1 port on an x86 PC | ||
static const struct uart_port pc_com1_port = { | ||
.iobase = 0x3f8, | ||
.uartclk = BASE_BAUD, | ||
.irq = 4, | ||
.flags = STD_COMX_FLAGS | ||
}; | ||
static const struct uart_port pc_com2_port = { | ||
.iobase = 0x2f8, | ||
.uartclk = BASE_BAUD, | ||
.irq = 3, | ||
.flags = STD_COMX_FLAGS | ||
}; | ||
|
||
static bool serial_swapped = false; //Whether ttyS0 and ttyS1 were swapped | ||
static bool ttyS0_force_initted = false; //Was ttyS0 forcefully initialized by us? | ||
|
||
/** | ||
* After re-registering a console any TTYs (user terminals) will be unusable. This function restarts them. | ||
* | ||
* This is only applicable/effective when inserting the module after any tty has started. So in our scenario pretty much | ||
* only for debugging as during normal operation TTYs are started way later than this module. | ||
*/ | ||
static void restart_ttys(void) | ||
{ | ||
pr_loc_dbg("Restarting TTYs"); | ||
|
||
struct task_struct *proc; | ||
for_each_process(proc) { | ||
if (proc->parent->pid > 2 || | ||
(strcmp(proc->parent->comm, "init") != 0 && strcmp(proc->parent->comm, "kthreadd") != 0)) | ||
continue; | ||
|
||
//@todo this will only work for not-loggedin consoles hmm | ||
if(strcmp(proc->comm, "ash") == 0 || strcmp(proc->comm, "sh") == 0) { | ||
pr_loc_dbg("Killing TTY process %s (%d)", proc->comm, proc->pid); | ||
kill_pgrp(task_pid(proc), SIGKILL, 1); | ||
} | ||
} | ||
} | ||
|
||
/** | ||
* Swaps first two serial ports & updates kernel console indexing | ||
* | ||
* Some kernels are compiled with CONFIG_SYNO_X86_SERIAL_PORT_SWAP set which effectively swaps first two serial ports. | ||
* This function reverses that. It also makes sure to move kernel console output between them (if configured) | ||
* | ||
* Swapping the serials involves two things: swapping console drivers and swapping kernel console printk itself. | ||
* The first one can be done on any kernel by modifying exported "console_drivers". The second one requires an access | ||
* to either struct serial8250_ports (drivers/tty/serial/8250/8250_core.c) or to struct console_cmdline | ||
* (kernel/printk/printk.c). Both of them are static so they're no-go. | ||
* Kernels before v4.1 had a convenient method update_console_cmdline(). Unfortunately this method was removed: | ||
* https://github.com/torvalds/linux/commit/c7cef0a84912cab3c9df8949b034e4aa62982ec9 so there's currently no method | ||
* of un-swapping on v4 ;< | ||
* | ||
* Things we've tried: | ||
* - Set the new console as preferred (making it default for /dev/console) -> /dev/ttyS0 and 1 are still wrong | ||
* - Unregistering both ports and re-registering them -> we tried a bit and it's a nightmare to re-do and crashes the | ||
* kernel | ||
* - Unregistering and re-registering consoles | ||
* - Recreating the flow for serial8250_isa_init_ports() -> it appears to work (i.e. doesn't crash) but the serial port | ||
* is dead afterwards and doesn't pass any traffic | ||
* | ||
* Since there are no platforms running v4 with swapped serials (and hopefully there wouldn't be anymore) we're not | ||
* digging any deeper into that. The current implementation is less-than-ideal on v3 as well as /dev/ttyS0 and 1 are | ||
* still pointing to broken places... ehh, ffs why. | ||
* | ||
* Hours wasted trying to reverse stupid ports: 37 (increment when you think you've got it and you failed) | ||
*/ | ||
static int swap_uarts(int from, int to) | ||
{ | ||
int out = 0; | ||
struct console *con; | ||
struct console *ttyS0_con = NULL; //Populated by a console which was set to be on a *REAL* ttyS0 (ttyS1 swapped) | ||
struct console *ttyS1_con = NULL; //Populated by a console which was set to be on a *REAL* ttyS1 (ttyS0 swapped) | ||
|
||
console_lock(); //Stops (and buffers) printk calls while pulling console semaphore down | ||
for_each_console(con) { | ||
if (strcmp(con->name, CONSOLE_NAME_UART) != 0) | ||
continue; | ||
|
||
pr_loc_dbg("Swapping console %s%d index", con->name, con->index); | ||
if (con->index == 1) { | ||
con->index = 0; | ||
ttyS1_con = con; | ||
} else if (con->index == 0) { | ||
con->index = 1; | ||
ttyS0_con = con; | ||
} | ||
} | ||
console_unlock(); //Flushes printks and releases semaphore | ||
|
||
pr_loc_inf("Swapped %s0 & %s1, updating console %s%d => %s%d", CONSOLE_NAME_UART, CONSOLE_NAME_UART, | ||
CONSOLE_NAME_UART, from, CONSOLE_NAME_UART, to); | ||
|
||
//This call is only successful when loading early (not in the shell) so it CAN fail | ||
_update_console_cmdline(CONSOLE_NAME_UART, from, CONSOLE_NAME_UART, to, CONSOLE_BAUD_UART); | ||
serial_swapped = true; | ||
restart_ttys(); | ||
|
||
return 0; | ||
} | ||
|
||
/** | ||
* On some platforms (e.g. 918+) the first serial port appears to not be functional as it's not initialized properly. | ||
* | ||
* It is speculated that it has to do with "CONFIG_SYNO_X86_TTY_CONSOLE_OUTPUT=y" but it's not confirmed. If this is not | ||
* fixed by this function setting kernel console output to ttyS0 will result in earlycon working as expected (as it | ||
* doesn't use the normal 8250 driver) with nothing being transmitted as soon as earlycon is switched to the proper | ||
* "console=" port. | ||
*/ | ||
static int fix_muted_ttyS0(void) | ||
{ | ||
int out = 0; | ||
struct uart_port port = pc_com1_port; | ||
|
||
if ((out = _early_serial_setup(&port)) != 0) { | ||
pr_loc_err("Failed to register ttyS0 to hw port @ %lx", port.iobase); | ||
return out; | ||
} | ||
|
||
pr_loc_dbg("Fixed muted ttyS0 to hw port @ %lx", port.iobase); | ||
ttyS0_force_initted = true; | ||
return out; | ||
} | ||
|
||
static int mute_ttyS0(void) | ||
{ | ||
pr_loc_dbg("Re-muting ttyS0"); | ||
serial8250_unregister_port(0); | ||
|
||
return 0; | ||
} | ||
|
||
int register_uart_fixer(const hw_config_uart_fixer *hw) | ||
{ | ||
int out = 0; | ||
|
||
if ( | ||
(hw->swap_serial && (out = swap_uarts(1, 0)) != 0) || | ||
(hw->reinit_ttyS0 && (out = fix_muted_ttyS0()) != 0) | ||
) { | ||
pr_loc_err("Failed to register UART fixer"); | ||
|
||
return out; | ||
} | ||
|
||
pr_loc_inf("UART fixer registered"); | ||
return out; | ||
} | ||
|
||
int unregister_uart_fixer(void) | ||
{ | ||
int out = 0; | ||
|
||
if ( | ||
(serial_swapped && (out = swap_uarts(0, 1)) != 0) || | ||
(ttyS0_force_initted && (out = mute_ttyS0()) != 0) | ||
) { | ||
pr_loc_err("Failed to unregister UART fixer"); | ||
return out; | ||
} | ||
|
||
pr_loc_inf("UART fixer unregistered"); | ||
return out; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
#ifndef REDPILL_UART_FIXER_H | ||
#define REDPILL_UART_FIXER_H | ||
|
||
typedef struct hw_config hw_config_uart_fixer; | ||
int register_uart_fixer(const hw_config_uart_fixer *hw); | ||
int unregister_uart_fixer(void); | ||
|
||
#endif //REDPILL_UART_FIXER_H |
c390f74
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
must be:
but it crash:
c390f74
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ffffffff81928109 T early_serial_setup
I found this line on System.map of DSM7.0
should ffffffff81928292->ffffffff81928109?
c390f74
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Issue for the path: #9
Issue for the serial setup: #10
p.s. GitHub comments for commits don't trigger any notifications so we missed that initially ;)