cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

earlycon.c (7884B)


      1// SPDX-License-Identifier: GPL-2.0
      2/*
      3 * Copyright (C) 2014 Linaro Ltd.
      4 * Author: Rob Herring <robh@kernel.org>
      5 *
      6 * Based on 8250 earlycon:
      7 * (c) Copyright 2004 Hewlett-Packard Development Company, L.P.
      8 *	Bjorn Helgaas <bjorn.helgaas@hp.com>
      9 */
     10
     11#define pr_fmt(fmt)	KBUILD_MODNAME ": " fmt
     12
     13#include <linux/console.h>
     14#include <linux/kernel.h>
     15#include <linux/init.h>
     16#include <linux/io.h>
     17#include <linux/serial_core.h>
     18#include <linux/sizes.h>
     19#include <linux/of.h>
     20#include <linux/of_fdt.h>
     21#include <linux/acpi.h>
     22
     23#ifdef CONFIG_FIX_EARLYCON_MEM
     24#include <asm/fixmap.h>
     25#endif
     26
     27#include <asm/serial.h>
     28
     29static struct console early_con = {
     30	.name =		"uart",		/* fixed up at earlycon registration */
     31	.flags =	CON_PRINTBUFFER | CON_BOOT,
     32	.index =	0,
     33};
     34
     35static struct earlycon_device early_console_dev = {
     36	.con = &early_con,
     37};
     38
     39static void __iomem * __init earlycon_map(resource_size_t paddr, size_t size)
     40{
     41	void __iomem *base;
     42#ifdef CONFIG_FIX_EARLYCON_MEM
     43	set_fixmap_io(FIX_EARLYCON_MEM_BASE, paddr & PAGE_MASK);
     44	base = (void __iomem *)__fix_to_virt(FIX_EARLYCON_MEM_BASE);
     45	base += paddr & ~PAGE_MASK;
     46#else
     47	base = ioremap(paddr, size);
     48#endif
     49	if (!base)
     50		pr_err("%s: Couldn't map %pa\n", __func__, &paddr);
     51
     52	return base;
     53}
     54
     55static void __init earlycon_init(struct earlycon_device *device,
     56				 const char *name)
     57{
     58	struct console *earlycon = device->con;
     59	const char *s;
     60	size_t len;
     61
     62	/* scan backwards from end of string for first non-numeral */
     63	for (s = name + strlen(name);
     64	     s > name && s[-1] >= '0' && s[-1] <= '9';
     65	     s--)
     66		;
     67	if (*s)
     68		earlycon->index = simple_strtoul(s, NULL, 10);
     69	len = s - name;
     70	strlcpy(earlycon->name, name, min(len + 1, sizeof(earlycon->name)));
     71	earlycon->data = &early_console_dev;
     72}
     73
     74static void __init earlycon_print_info(struct earlycon_device *device)
     75{
     76	struct console *earlycon = device->con;
     77	struct uart_port *port = &device->port;
     78
     79	if (port->iotype == UPIO_MEM || port->iotype == UPIO_MEM16 ||
     80	    port->iotype == UPIO_MEM32 || port->iotype == UPIO_MEM32BE)
     81		pr_info("%s%d at MMIO%s %pa (options '%s')\n",
     82			earlycon->name, earlycon->index,
     83			(port->iotype == UPIO_MEM) ? "" :
     84			(port->iotype == UPIO_MEM16) ? "16" :
     85			(port->iotype == UPIO_MEM32) ? "32" : "32be",
     86			&port->mapbase, device->options);
     87	else
     88		pr_info("%s%d at I/O port 0x%lx (options '%s')\n",
     89			earlycon->name, earlycon->index,
     90			port->iobase, device->options);
     91}
     92
     93static int __init parse_options(struct earlycon_device *device, char *options)
     94{
     95	struct uart_port *port = &device->port;
     96	int length;
     97	resource_size_t addr;
     98
     99	if (uart_parse_earlycon(options, &port->iotype, &addr, &options))
    100		return -EINVAL;
    101
    102	switch (port->iotype) {
    103	case UPIO_MEM:
    104		port->mapbase = addr;
    105		break;
    106	case UPIO_MEM16:
    107		port->regshift = 1;
    108		port->mapbase = addr;
    109		break;
    110	case UPIO_MEM32:
    111	case UPIO_MEM32BE:
    112		port->regshift = 2;
    113		port->mapbase = addr;
    114		break;
    115	case UPIO_PORT:
    116		port->iobase = addr;
    117		break;
    118	default:
    119		return -EINVAL;
    120	}
    121
    122	if (options) {
    123		device->baud = simple_strtoul(options, NULL, 0);
    124		length = min(strcspn(options, " ") + 1,
    125			     (size_t)(sizeof(device->options)));
    126		strlcpy(device->options, options, length);
    127	}
    128
    129	return 0;
    130}
    131
    132static int __init register_earlycon(char *buf, const struct earlycon_id *match)
    133{
    134	int err;
    135	struct uart_port *port = &early_console_dev.port;
    136
    137	/* On parsing error, pass the options buf to the setup function */
    138	if (buf && !parse_options(&early_console_dev, buf))
    139		buf = NULL;
    140
    141	spin_lock_init(&port->lock);
    142	port->uartclk = BASE_BAUD * 16;
    143	if (port->mapbase)
    144		port->membase = earlycon_map(port->mapbase, 64);
    145
    146	earlycon_init(&early_console_dev, match->name);
    147	err = match->setup(&early_console_dev, buf);
    148	earlycon_print_info(&early_console_dev);
    149	if (err < 0)
    150		return err;
    151	if (!early_console_dev.con->write)
    152		return -ENODEV;
    153
    154	register_console(early_console_dev.con);
    155	return 0;
    156}
    157
    158/**
    159 *	setup_earlycon - match and register earlycon console
    160 *	@buf:	earlycon param string
    161 *
    162 *	Registers the earlycon console matching the earlycon specified
    163 *	in the param string @buf. Acceptable param strings are of the form
    164 *	   <name>,io|mmio|mmio32|mmio32be,<addr>,<options>
    165 *	   <name>,0x<addr>,<options>
    166 *	   <name>,<options>
    167 *	   <name>
    168 *
    169 *	Only for the third form does the earlycon setup() method receive the
    170 *	<options> string in the 'options' parameter; all other forms set
    171 *	the parameter to NULL.
    172 *
    173 *	Returns 0 if an attempt to register the earlycon was made,
    174 *	otherwise negative error code
    175 */
    176int __init setup_earlycon(char *buf)
    177{
    178	const struct earlycon_id *match;
    179	bool empty_compatible = true;
    180
    181	if (!buf || !buf[0])
    182		return -EINVAL;
    183
    184	if (early_con.flags & CON_ENABLED)
    185		return -EALREADY;
    186
    187again:
    188	for (match = __earlycon_table; match < __earlycon_table_end; match++) {
    189		size_t len = strlen(match->name);
    190
    191		if (strncmp(buf, match->name, len))
    192			continue;
    193
    194		/* prefer entries with empty compatible */
    195		if (empty_compatible && *match->compatible)
    196			continue;
    197
    198		if (buf[len]) {
    199			if (buf[len] != ',')
    200				continue;
    201			buf += len + 1;
    202		} else
    203			buf = NULL;
    204
    205		return register_earlycon(buf, match);
    206	}
    207
    208	if (empty_compatible) {
    209		empty_compatible = false;
    210		goto again;
    211	}
    212
    213	return -ENOENT;
    214}
    215
    216/*
    217 * This defers the initialization of the early console until after ACPI has
    218 * been initialized.
    219 */
    220bool earlycon_acpi_spcr_enable __initdata;
    221
    222/* early_param wrapper for setup_earlycon() */
    223static int __init param_setup_earlycon(char *buf)
    224{
    225	int err;
    226
    227	/* Just 'earlycon' is a valid param for devicetree and ACPI SPCR. */
    228	if (!buf || !buf[0]) {
    229		if (IS_ENABLED(CONFIG_ACPI_SPCR_TABLE)) {
    230			earlycon_acpi_spcr_enable = true;
    231			return 0;
    232		} else if (!buf) {
    233			return early_init_dt_scan_chosen_stdout();
    234		}
    235	}
    236
    237	err = setup_earlycon(buf);
    238	if (err == -ENOENT || err == -EALREADY)
    239		return 0;
    240	return err;
    241}
    242early_param("earlycon", param_setup_earlycon);
    243
    244#ifdef CONFIG_OF_EARLY_FLATTREE
    245
    246int __init of_setup_earlycon(const struct earlycon_id *match,
    247			     unsigned long node,
    248			     const char *options)
    249{
    250	int err;
    251	struct uart_port *port = &early_console_dev.port;
    252	const __be32 *val;
    253	bool big_endian;
    254	u64 addr;
    255
    256	spin_lock_init(&port->lock);
    257	port->iotype = UPIO_MEM;
    258	addr = of_flat_dt_translate_address(node);
    259	if (addr == OF_BAD_ADDR) {
    260		pr_warn("[%s] bad address\n", match->name);
    261		return -ENXIO;
    262	}
    263	port->mapbase = addr;
    264
    265	val = of_get_flat_dt_prop(node, "reg-offset", NULL);
    266	if (val)
    267		port->mapbase += be32_to_cpu(*val);
    268	port->membase = earlycon_map(port->mapbase, SZ_4K);
    269
    270	val = of_get_flat_dt_prop(node, "reg-shift", NULL);
    271	if (val)
    272		port->regshift = be32_to_cpu(*val);
    273	big_endian = of_get_flat_dt_prop(node, "big-endian", NULL) != NULL ||
    274		(IS_ENABLED(CONFIG_CPU_BIG_ENDIAN) &&
    275		 of_get_flat_dt_prop(node, "native-endian", NULL) != NULL);
    276	val = of_get_flat_dt_prop(node, "reg-io-width", NULL);
    277	if (val) {
    278		switch (be32_to_cpu(*val)) {
    279		case 1:
    280			port->iotype = UPIO_MEM;
    281			break;
    282		case 2:
    283			port->iotype = UPIO_MEM16;
    284			break;
    285		case 4:
    286			port->iotype = (big_endian) ? UPIO_MEM32BE : UPIO_MEM32;
    287			break;
    288		default:
    289			pr_warn("[%s] unsupported reg-io-width\n", match->name);
    290			return -EINVAL;
    291		}
    292	}
    293
    294	val = of_get_flat_dt_prop(node, "current-speed", NULL);
    295	if (val)
    296		early_console_dev.baud = be32_to_cpu(*val);
    297
    298	val = of_get_flat_dt_prop(node, "clock-frequency", NULL);
    299	if (val)
    300		port->uartclk = be32_to_cpu(*val);
    301
    302	if (options) {
    303		early_console_dev.baud = simple_strtoul(options, NULL, 0);
    304		strlcpy(early_console_dev.options, options,
    305			sizeof(early_console_dev.options));
    306	}
    307	earlycon_init(&early_console_dev, match->name);
    308	err = match->setup(&early_console_dev, options);
    309	earlycon_print_info(&early_console_dev);
    310	if (err < 0)
    311		return err;
    312	if (!early_console_dev.con->write)
    313		return -ENODEV;
    314
    315
    316	register_console(early_console_dev.con);
    317	return 0;
    318}
    319
    320#endif /* CONFIG_OF_EARLY_FLATTREE */