On 5/20/07, Andrew Morton <[email protected]> wrote:
hm, OK. I hope you guys have it under control ;)
With http://userweb.kernel.org/~akpm/config-vmm.txt I get
drivers/built-in.o:(.data+0x5790): undefined reference to `serial8250_find_port_for_earlycon'
please check this one
Bjorn,
I can not find fixmap.h for ia64.....hope you can use ioremap instead,
then we can create one dummy fixmap.h in include/asm-ia64
[PATCH]serial: make early_uart to use early_prarm instead of console_initcall
Make early_uart to use early_param, so uart console can be used earlier.
Make it to be bootconsole with CON_BOOT flag, so can use console handover
feature. and it will switch to corresponding normal serial console
automatically.
new command line will be
earlycon=uart,io,0x3f8,9600n8
earlycon=uart,io,0x3f8,9600n8 console=tty0
earlycon=uart,mmio,0xff5e0000,115200n8
it will print in very early stage
Early serial console at I/O port 0x3f8 (options '9600n8')
later for console it will print
console handover: boot [uart0] -> real [ttyS0]
Signed-off-by: <[email protected]>
diff --git a/arch/i386/kernel/head.S b/arch/i386/kernel/head.S
index f74dfc4..2d37850 100644
--- a/arch/i386/kernel/head.S
+++ b/arch/i386/kernel/head.S
@@ -168,6 +168,12 @@ page_pde_offset = (__PAGE_OFFSET >> 20);
.section .init.text,"ax",@progbits
#endif
+ /* Do an early initialization of the fixmap area */
+ movl $(swapper_pg_dir - __PAGE_OFFSET), %edx
+ movl $(swapper_pg_pmd - __PAGE_OFFSET), %eax
+ addl $0x007, %eax /* 0x007 = PRESENT+RW+USER */
+ movl %eax, 4092(%edx)
+
#ifdef CONFIG_SMP
ENTRY(startup_32_smp)
cld
@@ -507,6 +513,8 @@ ENTRY(_stext)
.section ".bss.page_aligned","w"
ENTRY(swapper_pg_dir)
.fill 1024,4,0
+ENTRY(swapper_pg_pmd)
+ .fill 1024,4,0
ENTRY(empty_zero_page)
.fill 4096,1,0
diff --git a/arch/x86_64/kernel/head.S b/arch/x86_64/kernel/head.S
index 1fab487..2da30ad 100644
--- a/arch/x86_64/kernel/head.S
+++ b/arch/x86_64/kernel/head.S
@@ -73,7 +73,11 @@ startup_64:
addq %rbp, init_level4_pgt + (511*8)(%rip)
addq %rbp, level3_ident_pgt + 0(%rip)
+
addq %rbp, level3_kernel_pgt + (510*8)(%rip)
+ addq %rbp, level3_kernel_pgt + (511*8)(%rip)
+
+ addq %rbp, level2_fixmap_pgt + (506*8)(%rip)
/* Add an Identity mapping if I am above 1G */
leaq _text(%rip), %rdi
@@ -314,7 +318,16 @@ NEXT_PAGE(level3_kernel_pgt)
.fill 510,8,0
/* (2^48-(2*1024*1024*1024)-((2^39)*511))/(2^30) = 510 */
.quad level2_kernel_pgt - __START_KERNEL_map + _KERNPG_TABLE
- .fill 1,8,0
+ .quad level2_fixmap_pgt - __START_KERNEL_map + _PAGE_TABLE
+
+NEXT_PAGE(level2_fixmap_pgt)
+ .fill 506,8,0
+ .quad level1_fixmap_pgt - __START_KERNEL_map + _KERNPG_TABLE
+ /* 8MB reserved for vsyscalls + a 2MB hole = 4 + 1 entries */
+ .fill 5,8,0
+
+NEXT_PAGE(level1_fixmap_pgt)
+ .fill 512,8,0
NEXT_PAGE(level2_ident_pgt)
/* Since I easily can, map the first 1G.
diff --git a/drivers/serial/8250.c b/drivers/serial/8250.c
index c84dab0..5a91ac5 100644
--- a/drivers/serial/8250.c
+++ b/drivers/serial/8250.c
@@ -2367,6 +2367,9 @@ static struct uart_ops serial8250_pops = {
.request_port = serial8250_request_port,
.config_port = serial8250_config_port,
.verify_port = serial8250_verify_port,
+#ifdef CONFIG_SERIAL_8250_CONSOLE
+ .find_port_for_earlycon = serial8250_find_port_for_earlycon,
+#endif
};
static struct uart_8250_port serial8250_ports[UART_NR];
@@ -2533,7 +2536,7 @@ static int __init serial8250_console_init(void)
}
console_initcall(serial8250_console_init);
-static int __init find_port(struct uart_port *p)
+int __init find_port_serial8250(struct uart_port *p)
{
int line;
struct uart_port *port;
@@ -2546,26 +2549,6 @@ static int __init find_port(struct uart_port *p)
return -ENODEV;
}
-int __init serial8250_start_console(struct uart_port *port, char *options)
-{
- int line;
-
- line = find_port(port);
- if (line < 0)
- return -ENODEV;
-
- add_preferred_console("ttyS", line, options);
- printk("Adding console on ttyS%d at %s 0x%lx (options '%s')\n",
- line, port->iotype == UPIO_MEM ? "MMIO" : "I/O port",
- port->iotype == UPIO_MEM ? (unsigned long) port->mapbase :
- (unsigned long) port->iobase, options);
- if (!(serial8250_console.flags & CON_ENABLED)) {
- serial8250_console.flags &= ~CON_PRINTBUFFER;
- register_console(&serial8250_console);
- }
- return line;
-}
-
#define SERIAL8250_CONSOLE &serial8250_console
#else
#define SERIAL8250_CONSOLE NULL
diff --git a/drivers/serial/8250_early.c b/drivers/serial/8250_early.c
index 7e51119..0572a1c 100644
--- a/drivers/serial/8250_early.c
+++ b/drivers/serial/8250_early.c
@@ -17,13 +17,9 @@
* we locate the device directly by its MMIO or I/O port address.
*
* The user can specify the device directly, e.g.,
- * console=uart,io,0x3f8,9600n8
- * console=uart,mmio,0xff5e0000,115200n8
- * or platform code can call early_uart_console_init() to set
- * the early UART device.
+ * earlycon=uart,io,0x3f8,9600n8
+ * earlycon=uart,mmio,0xff5e0000,115200n8
*
- * After the normal serial driver starts, we try to locate the
- * matching ttyS device and start a console there.
*/
#include <linux/tty.h>
@@ -32,8 +28,11 @@
#include <linux/serial_core.h>
#include <linux/serial_reg.h>
#include <linux/serial.h>
+#include <linux/serial_8250.h>
#include <asm/io.h>
#include <asm/serial.h>
+#include <asm/pgtable.h>
+#include <asm/fixmap.h>
struct early_uart_device {
struct uart_port port;
@@ -42,7 +41,6 @@ struct early_uart_device {
};
static struct early_uart_device early_device __initdata;
-static int early_uart_registered __initdata;
static unsigned int __init serial_in(struct uart_port *port, int offset)
{
@@ -133,7 +131,6 @@ static void __init init_port(struct early_uart_device *device)
static int __init parse_options(struct early_uart_device *device, char *options)
{
struct uart_port *port = &device->port;
- int mapsize = 64;
int mmio, length;
if (!options)
@@ -143,12 +140,9 @@ static int __init parse_options(struct early_uart_device *device, char *options)
if (!strncmp(options, "mmio,", 5)) {
port->iotype = UPIO_MEM;
port->mapbase = simple_strtoul(options + 5, &options, 0);
- port->membase = ioremap(port->mapbase, mapsize);
- if (!port->membase) {
- printk(KERN_ERR "%s: Couldn't ioremap 0x%lx\n",
- __FUNCTION__, port->mapbase);
- return -ENOMEM;
- }
+ 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;
mmio = 1;
} else if (!strncmp(options, "io,", 3)) {
port->iotype = UPIO_PORT;
@@ -175,6 +169,13 @@ static int __init parse_options(struct early_uart_device *device, char *options)
return 0;
}
+static struct console early_uart_console __initdata = {
+ .name = "uart",
+ .write = early_uart_write,
+ .flags = CON_PRINTBUFFER,
+ .index = -1,
+};
+
static int __init early_uart_setup(struct console *console, char *options)
{
struct early_uart_device *device = &early_device;
@@ -190,61 +191,43 @@ static int __init early_uart_setup(struct console *console, char *options)
return 0;
}
-static struct console early_uart_console __initdata = {
- .name = "uart",
- .write = early_uart_write,
- .setup = early_uart_setup,
- .flags = CON_PRINTBUFFER,
- .index = -1,
-};
-
-static int __init early_uart_console_init(void)
-{
- if (!early_uart_registered) {
- register_console(&early_uart_console);
- early_uart_registered = 1;
- }
- return 0;
-}
-console_initcall(early_uart_console_init);
-
-int __init early_serial_console_init(char *cmdline)
+static int __init setup_early_serial_console(char *cmdline)
{
char *options;
int err;
- options = strstr(cmdline, "console=uart,");
+ options = strstr(cmdline, "uart,");
if (!options)
return -ENODEV;
options = strchr(cmdline, ',') + 1;
if ((err = early_uart_setup(NULL, options)) < 0)
return err;
- return early_uart_console_init();
+
+ early_uart_console.flags |= CON_BOOT;
+ register_console(&early_uart_console);
+
+ /* add one dummy entry in console_cmdline*/
+ add_preferred_console("ttyS", 255, early_device.options);
+
+ return 0;
}
-static int __init early_uart_console_switch(void)
+int serial8250_find_port_for_earlycon(void)
{
struct early_uart_device *device = &early_device;
struct uart_port *port = &device->port;
- int mmio, line;
+ int line;
- if (!(early_uart_console.flags & CON_ENABLED))
- return 0;
+ line = find_port_serial8250(port);
- /* Try to start the normal driver on a matching line. */
- mmio = (port->iotype == UPIO_MEM);
- line = serial8250_start_console(port, device->options);
if (line < 0)
- printk("No ttyS device at %s 0x%lx for console\n",
- mmio ? "MMIO" : "I/O port",
- mmio ? port->mapbase :
- (unsigned long) port->iobase);
-
- unregister_console(&early_uart_console);
- if (mmio)
- iounmap(port->membase);
+ return -ENODEV;
+
+ /* update the dummy entry to what we want console type */
+ update_console_cmdline_console_index("ttyS", 255, line);
return 0;
}
-late_initcall(early_uart_console_switch);
+
+early_param("earlycon", setup_early_serial_console);
diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig
index 315ea99..b1de60d 100644
--- a/drivers/serial/Kconfig
+++ b/drivers/serial/Kconfig
@@ -62,6 +62,12 @@ config SERIAL_8250_CONSOLE
kernel will automatically use the first serial line, /dev/ttyS0, as
system console.
+ you can set that using a kernel command line option such as
+ "earlycon=uart,io,0x3f8,9600n8" or
+ "earlycon=uart,mmio,0xfe000008,115200n8".
+ and it will switch to normal serial console when correponding port is
+ ready.
+
If unsure, say N.
config SERIAL_8250_GSC
diff --git a/drivers/serial/serial_core.c b/drivers/serial/serial_core.c
index 326020f..956d435 100644
--- a/drivers/serial/serial_core.c
+++ b/drivers/serial/serial_core.c
@@ -2303,8 +2303,11 @@ int uart_add_one_port(struct uart_driver *drv, struct uart_port *port)
* It may be that the port was not available.
*/
if (port->type != PORT_UNKNOWN &&
- port->cons && !(port->cons->flags & CON_ENABLED))
+ port->cons && !(port->cons->flags & CON_ENABLED)) {
+ if(port->ops && port->ops->find_port_for_earlycon)
+ port->ops->find_port_for_earlycon();
register_console(port->cons);
+ }
/*
* Ensure UPF_DEAD is not set.
diff --git a/include/asm-i386/fixmap.h b/include/asm-i386/fixmap.h
index 80ea052..249e753 100644
--- a/include/asm-i386/fixmap.h
+++ b/include/asm-i386/fixmap.h
@@ -54,6 +54,8 @@ extern unsigned long __FIXADDR_TOP;
enum fixed_addresses {
FIX_HOLE,
FIX_VDSO,
+ FIX_DBGP_BASE,
+ FIX_EARLYCON_MEM_BASE,
#ifdef CONFIG_X86_LOCAL_APIC
FIX_APIC_BASE, /* local (CPU) APIC) -- required for SMP or not */
#endif
diff --git a/include/asm-x86_64/fixmap.h b/include/asm-x86_64/fixmap.h
index e90e167..2acb9b7 100644
--- a/include/asm-x86_64/fixmap.h
+++ b/include/asm-x86_64/fixmap.h
@@ -35,6 +35,8 @@ enum fixed_addresses {
VSYSCALL_LAST_PAGE,
VSYSCALL_FIRST_PAGE = VSYSCALL_LAST_PAGE + ((VSYSCALL_END-VSYSCALL_START) >> PAGE_SHIFT) - 1,
VSYSCALL_HPET,
+ FIX_DBGP_BASE,
+ FIX_EARLYCON_MEM_BASE,
FIX_HPET_BASE,
FIX_APIC_BASE, /* local (CPU) APIC) -- required for SMP or not */
FIX_IO_APIC_BASE_0,
@@ -84,7 +86,7 @@ static __always_inline unsigned long fix_to_virt(const unsigned int idx)
if (idx >= __end_of_fixed_addresses)
__this_fixmap_does_not_exist();
- return __fix_to_virt(idx);
+ return __fix_to_virt(idx);
}
#endif
diff --git a/include/linux/console.h b/include/linux/console.h
index 62ef6e1..4cb7749 100644
--- a/include/linux/console.h
+++ b/include/linux/console.h
@@ -107,6 +107,7 @@ struct console {
};
extern int add_preferred_console(char *name, int idx, char *options);
+extern int update_console_cmdline_console_index(char *name, int idx_old, int idx_new);
extern void register_console(struct console *);
extern int unregister_console(struct console *);
extern struct console *console_drivers;
diff --git a/include/linux/serial.h b/include/linux/serial.h
index 33fc8cb..deb7143 100644
--- a/include/linux/serial.h
+++ b/include/linux/serial.h
@@ -177,11 +177,5 @@ struct serial_icounter_struct {
#ifdef __KERNEL__
#include <linux/compiler.h>
-/* Allow architectures to override entries in serial8250_ports[] at run time: */
-struct uart_port; /* forward declaration */
-extern int early_serial_setup(struct uart_port *port);
-extern int early_serial_console_init(char *options);
-extern int serial8250_start_console(struct uart_port *port, char *options);
-
#endif /* __KERNEL__ */
#endif /* _LINUX_SERIAL_H */
diff --git a/include/linux/serial_8250.h b/include/linux/serial_8250.h
index 71310d8..0d79fc5 100644
--- a/include/linux/serial_8250.h
+++ b/include/linux/serial_8250.h
@@ -60,4 +60,7 @@ void serial8250_unregister_port(int line);
void serial8250_suspend_port(int line);
void serial8250_resume_port(int line);
+extern int find_port_serial8250(struct uart_port *p);
+extern int serial8250_find_port_for_earlycon(void);
+
#endif
diff --git a/include/linux/serial_core.h b/include/linux/serial_core.h
index a3ac4c8..b74fa4a 100644
--- a/include/linux/serial_core.h
+++ b/include/linux/serial_core.h
@@ -199,6 +199,11 @@ struct uart_ops {
void (*config_port)(struct uart_port *, int);
int (*verify_port)(struct uart_port *, struct serial_struct *);
int (*ioctl)(struct uart_port *, unsigned int, unsigned long);
+
+ /*
+ * for earlycon to console switch
+ */
+ int (*find_port_for_earlycon)(void);
};
#define UART_CONFIG_TYPE (1 << 0)
diff --git a/kernel/printk.c b/kernel/printk.c
index 0bbdeac..253c0f7 100644
--- a/kernel/printk.c
+++ b/kernel/printk.c
@@ -726,6 +726,21 @@ int __init add_preferred_console(char *name, int idx, char *options)
return 0;
}
+int __init update_console_cmdline_console_index(char *name, int idx_old, int idx_new)
+{
+ int i;
+
+ for(i = 0; i < MAX_CMDLINECONSOLES && console_cmdline[i].name[0]; i++)
+ if (strcmp(console_cmdline[i].name, name) == 0 &&
+ console_cmdline[i].index == idx_old) {
+ console_cmdline[i].index = idx_new;
+ return 0;
+ }
+
+ return 0;
+}
+
+
#ifndef CONFIG_DISABLE_CONSOLE_SUSPEND
/**
* suspend_console - suspend the console subsystem
[Index of Archives]
[Kernel Newbies]
[Netfilter]
[Bugtraq]
[Photo]
[Stuff]
[Gimp]
[Yosemite News]
[MIPS Linux]
[ARM Linux]
[Linux Security]
[Linux RAID]
[Video 4 Linux]
[Linux for the blind]
[Linux Resources]