Merge branch 'linux-linaro-lsk' into linux-linaro-lsk-android
authorMark Brown <broonie@linaro.org>
Thu, 5 Jun 2014 14:03:54 +0000 (15:03 +0100)
committerMark Brown <broonie@linaro.org>
Thu, 5 Jun 2014 14:03:54 +0000 (15:03 +0100)
arch/arm64/include/asm/pgtable.h
arch/arm64/mm/fault.c
drivers/tty/serial/8250/8250_early.c
drivers/tty/serial/8250/Kconfig
drivers/tty/serial/Kconfig
drivers/tty/serial/Makefile
drivers/tty/serial/earlycon.c [new file with mode: 0644]
include/linux/serial_core.h

index 3ed44240fcc7f4cc1ad9266d9d75c4178a168640..a184bc132131d23b46c7d45978738f13c48cf68a 100644 (file)
@@ -86,13 +86,12 @@ extern void __pgd_error(const char *file, int line, unsigned long val);
 #define PAGE_COPY_EXEC         __pgprot(_PAGE_DEFAULT | PTE_USER | PTE_NG | PTE_PXN)
 #define PAGE_READONLY          __pgprot(_PAGE_DEFAULT | PTE_USER | PTE_NG | PTE_PXN | PTE_UXN)
 #define PAGE_READONLY_EXEC     __pgprot(_PAGE_DEFAULT | PTE_USER | PTE_NG | PTE_PXN)
-#define PAGE_EXECONLY          __pgprot(_PAGE_DEFAULT | PTE_NG | PTE_PXN)
 
 #define __P000  PAGE_NONE
 #define __P001  PAGE_READONLY
 #define __P010  PAGE_COPY
 #define __P011  PAGE_COPY
-#define __P100  PAGE_EXECONLY
+#define __P100  PAGE_READONLY_EXEC
 #define __P101  PAGE_READONLY_EXEC
 #define __P110  PAGE_COPY_EXEC
 #define __P111  PAGE_COPY_EXEC
@@ -101,7 +100,7 @@ extern void __pgd_error(const char *file, int line, unsigned long val);
 #define __S001  PAGE_READONLY
 #define __S010  PAGE_SHARED
 #define __S011  PAGE_SHARED
-#define __S100  PAGE_EXECONLY
+#define __S100  PAGE_READONLY_EXEC
 #define __S101  PAGE_READONLY_EXEC
 #define __S110  PAGE_SHARED_EXEC
 #define __S111  PAGE_SHARED_EXEC
@@ -137,8 +136,8 @@ extern struct page *empty_zero_page;
 #define pte_write(pte)         (!!(pte_val(pte) & PTE_WRITE))
 #define pte_exec(pte)          (!(pte_val(pte) & PTE_UXN))
 
-#define pte_valid_ng(pte) \
-       ((pte_val(pte) & (PTE_VALID | PTE_NG)) == (PTE_VALID | PTE_NG))
+#define pte_valid_user(pte) \
+       ((pte_val(pte) & (PTE_VALID | PTE_USER)) == (PTE_VALID | PTE_USER))
 
 static inline pte_t pte_wrprotect(pte_t pte)
 {
@@ -192,7 +191,7 @@ extern void __sync_icache_dcache(pte_t pteval, unsigned long addr);
 static inline void set_pte_at(struct mm_struct *mm, unsigned long addr,
                              pte_t *ptep, pte_t pte)
 {
-       if (pte_valid_ng(pte)) {
+       if (pte_valid_user(pte)) {
                if (!pte_special(pte) && pte_exec(pte))
                        __sync_icache_dcache(pte, addr);
                if (pte_dirty(pte) && pte_write(pte))
index c1b42273c8faa7082543877d730121a498d79681..df4f2fd187c3bed7b54574fa0ac92e86da3727a7 100644 (file)
@@ -173,7 +173,8 @@ static int __do_page_fault(struct mm_struct *mm, unsigned long addr,
 good_area:
        /*
         * Check that the permissions on the VMA allow for the fault which
-        * occurred.
+        * occurred. If we encountered a write or exec fault, we must have
+        * appropriate permissions, otherwise we allow any permission.
         */
        if (!(vma->vm_flags & vm_flags)) {
                fault = VM_FAULT_BADACCESS;
@@ -195,7 +196,7 @@ static int __kprobes do_page_fault(unsigned long addr, unsigned int esr,
        struct task_struct *tsk;
        struct mm_struct *mm;
        int fault, sig, code;
-       unsigned long vm_flags = VM_READ | VM_WRITE;
+       unsigned long vm_flags = VM_READ | VM_WRITE | VM_EXEC;
        unsigned int mm_flags = FAULT_FLAG_ALLOW_RETRY | FAULT_FLAG_KILLABLE;
 
        if (esr & ESR_LNX_EXEC) {
index 721904f8efa92b8816665410822b355619679f47..e83c9db3300cac9525889d437fb4204cf53eb3ef 100644 (file)
 #include <linux/serial_8250.h>
 #include <asm/io.h>
 #include <asm/serial.h>
-#ifdef CONFIG_FIX_EARLYCON_MEM
-#include <asm/pgtable.h>
-#include <asm/fixmap.h>
-#endif
 
-struct early_serial8250_device {
-       struct uart_port port;
-       char options[16];               /* e.g., 115200n8 */
-       unsigned int baud;
-};
-
-static struct early_serial8250_device early_device;
+static struct earlycon_device *early_device;
 
 unsigned int __weak __init serial8250_early_in(struct uart_port *port, int offset)
 {
@@ -100,7 +90,7 @@ static void __init serial_putc(struct uart_port *port, int c)
 static void __init early_serial8250_write(struct console *console,
                                        const char *s, unsigned int count)
 {
-       struct uart_port *port = &early_device.port;
+       struct uart_port *port = &early_device->port;
        unsigned int ier;
 
        /* Save the IER and disable interrupts */
@@ -129,7 +119,7 @@ static unsigned int __init probe_baud(struct uart_port *port)
        return (port->uartclk / 16) / quot;
 }
 
-static void __init init_port(struct early_serial8250_device *device)
+static void __init init_port(struct earlycon_device *device)
 {
        struct uart_port *port = &device->port;
        unsigned int divisor;
@@ -148,127 +138,32 @@ static void __init init_port(struct early_serial8250_device *device)
        serial8250_early_out(port, UART_LCR, c & ~UART_LCR_DLAB);
 }
 
-static int __init parse_options(struct early_serial8250_device *device,
-                                                               char *options)
-{
-       struct uart_port *port = &device->port;
-       int mmio, mmio32, length;
-
-       if (!options)
-               return -ENODEV;
-
-       port->uartclk = BASE_BAUD * 16;
-
-       mmio = !strncmp(options, "mmio,", 5);
-       mmio32 = !strncmp(options, "mmio32,", 7);
-       if (mmio || mmio32) {
-               port->iotype = (mmio ? UPIO_MEM : UPIO_MEM32);
-               port->mapbase = simple_strtoul(options + (mmio ? 5 : 7),
-                                              &options, 0);
-               if (mmio32)
-                       port->regshift = 2;
-#ifdef CONFIG_FIX_EARLYCON_MEM
-               set_fixmap_nocache(FIX_EARLYCON_MEM_BASE,
-                                       port->mapbase & PAGE_MASK);
-               port->membase =
-                       (void __iomem *)__fix_to_virt(FIX_EARLYCON_MEM_BASE);
-               port->membase += port->mapbase & ~PAGE_MASK;
-#else
-               port->membase = ioremap_nocache(port->mapbase, 64);
-               if (!port->membase) {
-                       printk(KERN_ERR "%s: Couldn't ioremap 0x%llx\n",
-                               __func__,
-                              (unsigned long long) port->mapbase);
-                       return -ENOMEM;
-               }
-#endif
-       } else if (!strncmp(options, "io,", 3)) {
-               port->iotype = UPIO_PORT;
-               port->iobase = simple_strtoul(options + 3, &options, 0);
-               mmio = 0;
-       } else
-               return -EINVAL;
-
-       options = strchr(options, ',');
-       if (options) {
-               options++;
-               device->baud = simple_strtoul(options, NULL, 0);
-               length = min(strcspn(options, " "), sizeof(device->options));
-               strlcpy(device->options, options, length);
-       } else {
-               device->baud = probe_baud(port);
-               snprintf(device->options, sizeof(device->options), "%u",
-                       device->baud);
-       }
-
-       if (mmio || mmio32)
-               printk(KERN_INFO
-                      "Early serial console at MMIO%s 0x%llx (options '%s')\n",
-                       mmio32 ? "32" : "",
-                       (unsigned long long)port->mapbase,
-                       device->options);
-       else
-               printk(KERN_INFO
-                     "Early serial console at I/O port 0x%lx (options '%s')\n",
-                       port->iobase,
-                       device->options);
-
-       return 0;
-}
-
-static struct console early_serial8250_console __initdata = {
-       .name   = "uart",
-       .write  = early_serial8250_write,
-       .flags  = CON_PRINTBUFFER | CON_BOOT,
-       .index  = -1,
-};
-
-static int __init early_serial8250_setup(char *options)
+static int __init early_serial8250_setup(struct earlycon_device *device,
+                                        const char *options)
 {
-       struct early_serial8250_device *device = &early_device;
-       int err;
-
-       if (device->port.membase || device->port.iobase)
+       if (!(device->port.membase || device->port.iobase))
                return 0;
 
-       err = parse_options(device, options);
-       if (err < 0)
-               return err;
+       if (!device->baud)
+               device->baud = probe_baud(&device->port);
 
        init_port(device);
-       return 0;
-}
-
-int __init setup_early_serial8250_console(char *cmdline)
-{
-       char *options;
-       int err;
-
-       options = strstr(cmdline, "uart8250,");
-       if (!options) {
-               options = strstr(cmdline, "uart,");
-               if (!options)
-                       return 0;
-       }
-
-       options = strchr(cmdline, ',') + 1;
-       err = early_serial8250_setup(options);
-       if (err < 0)
-               return err;
-
-       register_console(&early_serial8250_console);
 
+       early_device = device;
+       device->con->write = early_serial8250_write;
        return 0;
 }
+EARLYCON_DECLARE(uart8250, early_serial8250_setup);
+EARLYCON_DECLARE(uart, early_serial8250_setup);
 
 int serial8250_find_port_for_earlycon(void)
 {
-       struct early_serial8250_device *device = &early_device;
-       struct uart_port *port = &device->port;
+       struct earlycon_device *device = early_device;
+       struct uart_port *port = device ? &device->port : NULL;
        int line;
        int ret;
 
-       if (!device->port.membase && !device->port.iobase)
+       if (!port || (!port->membase && !port->iobase))
                return -ENODEV;
 
        line = serial8250_find_port(port);
@@ -283,5 +178,3 @@ int serial8250_find_port_for_earlycon(void)
 
        return ret;
 }
-
-early_param("earlycon", setup_early_serial8250_console);
index 80fe91e64a527da06e82d9cf237be64a26faf662..902c4bf15f0bbd1de7e3066cf1507d4750339f11 100644 (file)
@@ -62,6 +62,7 @@ config SERIAL_8250_CONSOLE
        bool "Console on 8250/16550 and compatible serial port"
        depends on SERIAL_8250=y
        select SERIAL_CORE_CONSOLE
+       select SERIAL_EARLYCON
        ---help---
          If you say Y here, it will be possible to use a serial port as the
          system console (the system console is the device which receives all
index 7e7006fd404e62000b19b728274c0abf8a51bf38..1ad9aadc00552108f9e2d9b79e65458df9838923 100644 (file)
@@ -7,6 +7,13 @@ if TTY
 menu "Serial drivers"
        depends on HAS_IOMEM && GENERIC_HARDIRQS
 
+config SERIAL_EARLYCON
+       bool
+       help
+         Support for early consoles with the earlycon parameter. This enables
+         the console before standard serial driver is probed. The console is
+         enabled when early_param is processed.
+
 source "drivers/tty/serial/8250/Kconfig"
 
 comment "Non-8250 serial port support"
index eedfec40e3dda242220cf1dc73b9ec1787c63cee..e51c680d6044995a2d920832d09eb863fe828461 100644 (file)
@@ -5,6 +5,8 @@
 obj-$(CONFIG_SERIAL_CORE) += serial_core.o
 obj-$(CONFIG_SERIAL_21285) += 21285.o
 
+obj-$(CONFIG_SERIAL_EARLYCON) += earlycon.o
+
 # These Sparc drivers have to appear before others such as 8250
 # which share ttySx minor node space.  Otherwise console device
 # names change and other unplesantries.
diff --git a/drivers/tty/serial/earlycon.c b/drivers/tty/serial/earlycon.c
new file mode 100644 (file)
index 0000000..73bf1e2
--- /dev/null
@@ -0,0 +1,152 @@
+/*
+ * Copyright (C) 2014 Linaro Ltd.
+ * Author: Rob Herring <robh@kernel.org>
+ *
+ * Based on 8250 earlycon:
+ * (c) Copyright 2004 Hewlett-Packard Development Company, L.P.
+ *     Bjorn Helgaas <bjorn.helgaas@hp.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#include <linux/console.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/serial_core.h>
+
+#ifdef CONFIG_FIX_EARLYCON_MEM
+#include <asm/fixmap.h>
+#endif
+
+#include <asm/serial.h>
+
+static struct console early_con = {
+       .name =         "earlycon",
+       .flags =        CON_PRINTBUFFER | CON_BOOT,
+       .index =        -1,
+};
+
+static struct earlycon_device early_console_dev = {
+       .con = &early_con,
+};
+
+static void __iomem * __init earlycon_map(unsigned long paddr, size_t size)
+{
+       void __iomem *base;
+#ifdef CONFIG_FIX_EARLYCON_MEM
+       set_fixmap_io(FIX_EARLYCON_MEM_BASE, paddr & PAGE_MASK);
+       base = (void __iomem *)__fix_to_virt(FIX_EARLYCON_MEM_BASE);
+       base += paddr & ~PAGE_MASK;
+#else
+       base = ioremap(paddr, size);
+#endif
+       if (!base)
+               pr_err("%s: Couldn't map 0x%llx\n", __func__,
+                      (unsigned long long)paddr);
+
+       return base;
+}
+
+static int __init parse_options(struct earlycon_device *device,
+                               char *options)
+{
+       struct uart_port *port = &device->port;
+       int mmio, mmio32, length, ret;
+       unsigned long addr;
+
+       if (!options)
+               return -ENODEV;
+
+       mmio = !strncmp(options, "mmio,", 5);
+       mmio32 = !strncmp(options, "mmio32,", 7);
+       if (mmio || mmio32) {
+               port->iotype = (mmio ? UPIO_MEM : UPIO_MEM32);
+               options += mmio ? 5 : 7;
+               ret = kstrtoul(options, 0, &addr);
+               if (ret)
+                       return ret;
+               port->mapbase = addr;
+               if (mmio32)
+                       port->regshift = 2;
+       } else if (!strncmp(options, "io,", 3)) {
+               port->iotype = UPIO_PORT;
+               options += 3;
+               ret = kstrtoul(options, 0, &addr);
+               if (ret)
+                       return ret;
+               port->iobase = addr;
+               mmio = 0;
+       } else if (!strncmp(options, "0x", 2)) {
+               port->iotype = UPIO_MEM;
+               ret = kstrtoul(options, 0, &addr);
+               if (ret)
+                       return ret;
+               port->mapbase = addr;
+       } else {
+               return -EINVAL;
+       }
+
+       port->uartclk = BASE_BAUD * 16;
+
+       options = strchr(options, ',');
+       if (options) {
+               options++;
+               ret = kstrtouint(options, 0, &device->baud);
+               if (ret)
+                       return ret;
+               length = min(strcspn(options, " ") + 1,
+                            (size_t)(sizeof(device->options)));
+               strlcpy(device->options, options, length);
+       }
+
+       if (mmio || mmio32)
+               pr_info("Early serial console at MMIO%s 0x%llx (options '%s')\n",
+                       mmio32 ? "32" : "",
+                       (unsigned long long)port->mapbase,
+                       device->options);
+       else
+               pr_info("Early serial console at I/O port 0x%lx (options '%s')\n",
+                       port->iobase,
+                       device->options);
+
+       return 0;
+}
+
+int __init setup_earlycon(char *buf, const char *match,
+                         int (*setup)(struct earlycon_device *, const char *))
+{
+       int err;
+       size_t len;
+       struct uart_port *port = &early_console_dev.port;
+
+       if (!buf || !match || !setup)
+               return 0;
+
+       len = strlen(match);
+       if (strncmp(buf, match, len))
+               return 0;
+       if (buf[len] && (buf[len] != ','))
+               return 0;
+
+       buf += len + 1;
+
+       err = parse_options(&early_console_dev, buf);
+       /* On parsing error, pass the options buf to the setup function */
+       if (!err)
+               buf = NULL;
+
+       if (port->mapbase)
+               port->membase = earlycon_map(port->mapbase, 64);
+
+       early_console_dev.con->data = &early_console_dev;
+       err = setup(&early_console_dev, buf);
+       if (err < 0)
+               return err;
+       if (!early_console_dev.con->write)
+               return -ENODEV;
+
+       register_console(early_console_dev.con);
+       return 0;
+}
index a782f3ca71e9b84782ed0ec500baa6ad26df2434..21c074b2200e64ff1de4da77548898b3de351a88 100644 (file)
@@ -280,6 +280,22 @@ static inline int uart_poll_timeout(struct uart_port *port)
 /*
  * Console helpers.
  */
+struct earlycon_device {
+       struct console *con;
+       struct uart_port port;
+       char options[16];               /* e.g., 115200n8 */
+       unsigned int baud;
+};
+int setup_earlycon(char *buf, const char *match,
+                  int (*setup)(struct earlycon_device *, const char *));
+
+#define EARLYCON_DECLARE(name, func) \
+static int __init name ## _setup_earlycon(char *buf) \
+{ \
+       return setup_earlycon(buf, __stringify(name), func); \
+} \
+early_param("earlycon", name ## _setup_earlycon);
+
 struct uart_port *uart_get_console(struct uart_port *ports, int nr,
                                   struct console *c);
 void uart_parse_options(char *options, int *baud, int *parity, int *bits,