When the earlycon of the system to Earlycon after the kernel commandline is passed in the DRIVERS/TTY/SERIAL/EARLYCON.C
static int __init Param_setup_earlycon (char *buf)
{
int err;
/*
* Just ' Earlycon ' is a valid param for devicetree earlycons;
* don ' t generate a warning from parse_early_params ()
*/
if (!buf | |!buf[0]) {
if (is_enabled (config_acpi_spcr_table)) {
Earlycon_init_is_deferred = true;
return 0;
} else {
return Early_init_dt_scan_chosen_stdout ();
}
}
Err = Setup_earlycon (BUF);
if (err = =-enoent | | err = =-ealready)
return 0;
return err;
}
Early_param ("Earlycon", Param_setup_earlycon);
When BUF is not 0, the Earlycon is followed by a set of settings, such as earlycon=pl011,mmio,0x12345678. This time it will call Setup_earlycon
int __init Setup_earlycon (char *buf)
{
const struct EARLYCON_ID *match;
if (!buf | |!buf[0])
Return-einval;
if (Early_con.flags & con_enabled)
Return-ealready;
for (match = __earlycon_table; match < __earlycon_table_end; match++) {
size_t len = strlen (match->name);
if (strncmp (buf, Match->name, Len))
Continue
if (Buf[len]) {
if (Buf[len]!= ', ')
Continue
BUF + = len + 1;
} else
BUF = NULL;
Return Register_earlycon (buf, match);
}
Return-enoent;
}
Setup_earlycon traversal __earlycon_table to __earlycon_table_end, find and Kernel commandline match, for example we are here to match the pl011 this string. Call Register_earlycon If a match is made
static int __init Register_earlycon (char *buf, const struct EARLYCON_ID *match)
{
int err;
struct Uart_port *port = &early_console_dev.port;
/* On parsing error, pass the options buf to the Setup function * *
if (buf &&!parse_options (&early_console_dev, buf))
BUF = NULL;
/* Scan backwards from-end of of to-for-a-non-numeral *
for (s = name + strlen (name);
s > Name && s[-1] >= ' 0 ' && s[-1] <= ' 9 ';
s--)
;
if (*s)
Earlycon->index = Simple_strtoul (S, NULL, 10);
len = S-name;
strlcpy (earlycon->name, Name, min (len + 1, sizeof (earlycon->name)));
Earlycon->data = &early_console_dev;
if (Port->iotype = = Upio_mem | | port->iotype = = UPIO_MEM16 | |
Port->iotype = = Upio_mem32 | | Port->iotype = = upio_mem32be)
Pr_info ("%s%d at mmio%s%pa (options '%s ') \ n",
Earlycon->name, Earlycon->index,
(Port->iotype = = Upio_mem)? "" :
(Port->iotype = = UPIO_MEM16)? "16":
(Port->iotype = = upio_mem32)? "A": "32be",
&port->mapbase, device->options);
Else
Pr_info ("%s%d at I/O port 0x%lx (options '%s ') \ n",
Earlycon->name, Earlycon->index,
Port->iobase, device->options);
}
There is a key assignment in earlycon_init Earlycon->data = &early_console_dev;
static struct Console Early_con = {
. Name = "UART",/* fixed up at Earlycon registration * *
. Flags = Con_printbuffer | Con_boot,
. index = 0,
};
static struct Earlycon_device Early_console_dev = {
. con = &early_con,
};
We know from here that the original Con_boot this flag is assigned here.
Go back to Register_earlycon and call err = Match->setup (&early_console_dev, buf); For this example,
Of_earlycon_declare (pl011, "arm,pl011", Pl011_early_console_setup);
and #define Of_earlycon_declare (_name, Compat, fn) \
static const struct EARLYCON_ID __unique_id (__earlycon_# #_name) \
earlycon_used_or_unused __section (__earlycon_table) \
= {. Name = __stringify (_name), \
. compatible = Compat, \
. Setup = fn}
Visible is through Of_earlycon_declare will pl011_early_console_setup to __earlycon_table to __earlycon_table_end between, So here's the corresponding setup function for Pl011_early_console_setup.
static int __init pl011_early_console_setup (struct Earlycon_device *device,
const char *opt)
{
if (!device->port.membase)
Return-enodev;
Pl011_check_busy_workaround ();
Device->con->write = Pl011_early_write;
return 0;
}
From the Pl011_early_console_setup, you can learn that device->con->write points to a function of Pl011_early_write
static void Pl011_early_write (struct console *con, const char *s, unsigned n)
{
struct Earlycon_device *dev = con->data;
Uart_console_write (&dev->port, S, N, PL011_PUTC);
}
Finally call PL011_PUTC in Uart_console_write to display the string to the serial port
static void Pl011_putc (struct uart_port *port, int c)
{
while (Readl (Port->membase + uart01x_fr) & Uart01x_fr_txff)
Cpu_relax ();
if (Port->iotype = = upio_mem32)
Writel (c, port->membase + UART01X_DR);
Else
Writeb (c, port->membase + UART01X_DR);
if (unlikely (pl011_workaround_busy)) {
while (!) ( Readl (Port->membase + uart01x_fr) & Uart011_fr_txfe))
Cpu_relax ();
} else {
while (Readl (Port->membase + uart01x_fr) & Uart01x_fr_busy)
Cpu_relax ();
}
}
From the PL011_PUTC implementation can see that the actual is directly through the Writel to write registers.
So from the realization of Earlycon can know, Earlycon is directly write registers, so Earlycon flag contains con_boot this flag. So when the real console uses DMA output characters, the console containing the con_boot is unloaded
if (Bcon &&
(Newcon->flags & (Con_consdev | con_boot) = = Con_consdev) &&
!keep_bootcon) {
/* We need to iterate through all boot consoles
* Sure we print everything out, before we unregister them.
*/
For_each_console (Bcon)
if (Bcon->flags & Con_boot)
Unregister_console (Bcon);
}
This code is register_console in the uninstall containing con_boot this flag.
The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion;
products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the
content of the page makes you feel confusing, please write us an email, we will handle the problem
within 5 days after receiving your email.
If you find any instances of plagiarism from the community, please send an email to:
info-contact@alibabacloud.com
and provide relevant evidence. A staff member will contact you within 5 working days.