All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 0/2] x86/earlyprintk: setup earlyprintk as early as possible
@ 2015-04-08  9:31 Alexander Kuleshov
  2015-04-08  9:31 ` [PATCH 1/2] x86/setup: update boot_command_line with builtin_cmdline in separate function Alexander Kuleshov
  2015-04-08  9:31 ` [PATCH 2/2] x86/earlyprintk: setup earlyprintk as early as possible Alexander Kuleshov
  0 siblings, 2 replies; 5+ messages in thread
From: Alexander Kuleshov @ 2015-04-08  9:31 UTC (permalink / raw)
  To: Thomas Gleixner, Ingo Molnar, H. Peter Anvin, Greg Kroah-Hartman,
	Yinghai Lu
  Cc: linux-kernel

As setup_early_printk passed to the early_param, it will be usable only after
'parse_early_param' function will be called from the 'setup_arch'. So we have
earlyprintk during early boot and decompression. Next point after decompression
of the kernel where we can use early_printk is after call of the
'parse_early_param'.

This patch provides initialization of earlyprintk serial console as early
as possible in the arch/x86/kerne/head{32,64}.c

Alexander Kuleshov (2):
  x86/setup: update boot_command_line with builtin_cmdline in separate
    function
  x86/earlyprintk: setup earlyprintk as early as possible

 arch/x86/kernel/early_printk.c |  2 +-
 arch/x86/kernel/head.c         | 14 ++++++++++++++
 arch/x86/kernel/head32.c       |  3 +++
 arch/x86/kernel/head64.c       |  8 +++++++-
 arch/x86/kernel/setup.c        | 31 ++++++++++++++++++-------------
 include/linux/init.h           |  6 +++++-
 include/linux/printk.h         |  4 ++++
 kernel/printk/printk.c         | 11 +++++++----
 8 files changed, 59 insertions(+), 20 deletions(-)

-- 
2.3.3.611.g09038fc.dirty


^ permalink raw reply	[flat|nested] 5+ messages in thread

* [PATCH 1/2] x86/setup: update boot_command_line with builtin_cmdline in separate function
  2015-04-08  9:31 [PATCH 0/2] x86/earlyprintk: setup earlyprintk as early as possible Alexander Kuleshov
@ 2015-04-08  9:31 ` Alexander Kuleshov
  2015-04-08  9:31 ` [PATCH 2/2] x86/earlyprintk: setup earlyprintk as early as possible Alexander Kuleshov
  1 sibling, 0 replies; 5+ messages in thread
From: Alexander Kuleshov @ 2015-04-08  9:31 UTC (permalink / raw)
  To: Thomas Gleixner, Ingo Molnar, H. Peter Anvin, Greg Kroah-Hartman,
	Yinghai Lu
  Cc: linux-kernel, Alexander Kuleshov

This patch introduces setup_cmdline function which appends/overrides
boot_command_linew with builtin_cmdline if CONFIG_CMDLINE_BOOL is set.
Previously this functional was in the setup_arch, but we need to move
it for getting actual command line as early as possible in the
arch/x86/kernel/head{32,64}.c

Signed-off-by: Alexander Kuleshov <kuleshovmail@gmail.com>
---
 arch/x86/kernel/head32.c |  1 +
 arch/x86/kernel/head64.c |  1 +
 arch/x86/kernel/setup.c  | 31 ++++++++++++++++++-------------
 include/linux/init.h     |  6 +++++-
 4 files changed, 25 insertions(+), 14 deletions(-)

diff --git a/arch/x86/kernel/head32.c b/arch/x86/kernel/head32.c
index 2911ef3..7ad0ad0 100644
--- a/arch/x86/kernel/head32.c
+++ b/arch/x86/kernel/head32.c
@@ -31,6 +31,7 @@ static void __init i386_default_early_setup(void)
 
 asmlinkage __visible void __init i386_start_kernel(void)
 {
+	setup_cmdline();
 	cr4_init_shadow();
 	sanitize_boot_params(&boot_params);
 
diff --git a/arch/x86/kernel/head64.c b/arch/x86/kernel/head64.c
index c4f8d46..6eea2de 100644
--- a/arch/x86/kernel/head64.c
+++ b/arch/x86/kernel/head64.c
@@ -171,6 +171,7 @@ asmlinkage __visible void __init x86_64_start_kernel(char * real_mode_data)
 	load_idt((const struct desc_ptr *)&idt_descr);
 
 	copy_bootdata(__va(real_mode_data));
+	setup_cmdline();
 
 	/*
 	 * Load microcode early on BSP.
diff --git a/arch/x86/kernel/setup.c b/arch/x86/kernel/setup.c
index 0a2421c..d578f37 100644
--- a/arch/x86/kernel/setup.c
+++ b/arch/x86/kernel/setup.c
@@ -841,6 +841,24 @@ dump_kernel_offset(struct notifier_block *self, unsigned long v, void *p)
 }
 
 /*
+ * Append/Override boot command line with builtin command line if need
+ */
+void __init setup_cmdline(void) {
+#ifdef CONFIG_CMDLINE_BOOL
+#ifdef CONFIG_CMDLINE_OVERRIDE
+	strlcpy(boot_command_line, builtin_cmdline, COMMAND_LINE_SIZE);
+#else
+	if (builtin_cmdline[0]) {
+		/* append boot loader cmdline to builtin */
+		strlcat(builtin_cmdline, " ", COMMAND_LINE_SIZE);
+		strlcat(builtin_cmdline, boot_command_line, COMMAND_LINE_SIZE);
+		strlcpy(boot_command_line, builtin_cmdline, COMMAND_LINE_SIZE);
+	}
+#endif
+#endif
+}
+
+/*
  * Determine if we were loaded by an EFI loader.  If so, then we have also been
  * passed the efi memmap, systab, etc., so we should use these data structures
  * for initialization.  Note, the efi init code path is determined by the
@@ -968,19 +986,6 @@ void __init setup_arch(char **cmdline_p)
 	bss_resource.start = __pa_symbol(__bss_start);
 	bss_resource.end = __pa_symbol(__bss_stop)-1;
 
-#ifdef CONFIG_CMDLINE_BOOL
-#ifdef CONFIG_CMDLINE_OVERRIDE
-	strlcpy(boot_command_line, builtin_cmdline, COMMAND_LINE_SIZE);
-#else
-	if (builtin_cmdline[0]) {
-		/* append boot loader cmdline to builtin */
-		strlcat(builtin_cmdline, " ", COMMAND_LINE_SIZE);
-		strlcat(builtin_cmdline, boot_command_line, COMMAND_LINE_SIZE);
-		strlcpy(boot_command_line, builtin_cmdline, COMMAND_LINE_SIZE);
-	}
-#endif
-#endif
-
 	strlcpy(command_line, boot_command_line, COMMAND_LINE_SIZE);
 	*cmdline_p = command_line;
 
diff --git a/include/linux/init.h b/include/linux/init.h
index 2df8e8d..af8f2ec 100644
--- a/include/linux/init.h
+++ b/include/linux/init.h
@@ -152,7 +152,11 @@ void setup_arch(char **);
 void prepare_namespace(void);
 void __init load_default_modules(void);
 int __init init_rootfs(void);
-
+#ifdef CONFIG_CMDLINE_BOOL
+void __init setup_cmdline(void);
+#else
+static void __init setup_cmdline(void) {};
+#endif
 extern void (*late_time_init)(void);
 
 extern bool initcall_debug;
-- 
2.3.3.611.g09038fc.dirty


^ permalink raw reply related	[flat|nested] 5+ messages in thread

* [PATCH 2/2] x86/earlyprintk: setup earlyprintk as early as possible
  2015-04-08  9:31 [PATCH 0/2] x86/earlyprintk: setup earlyprintk as early as possible Alexander Kuleshov
  2015-04-08  9:31 ` [PATCH 1/2] x86/setup: update boot_command_line with builtin_cmdline in separate function Alexander Kuleshov
@ 2015-04-08  9:31 ` Alexander Kuleshov
  2015-04-08 11:32   ` Peter Hurley
  1 sibling, 1 reply; 5+ messages in thread
From: Alexander Kuleshov @ 2015-04-08  9:31 UTC (permalink / raw)
  To: Thomas Gleixner, Ingo Molnar, H. Peter Anvin, Greg Kroah-Hartman,
	Yinghai Lu
  Cc: linux-kernel, Alexander Kuleshov

As setup_early_printk passed to the early_param, it will be usable only after
'parse_early_param' function will be called from the 'setup_arch'. So we have
earlyprintk during early boot and decompression. Next point after decompression
of the kernel where we can use early_printk is after call of the
'parse_early_param'.

This patch makes setup_early_printk visible for head{32,64}.c So 'early_printk'
function will be usabable after decompression of the kernel and before
parse_early_param will be called. It also must be safe if CONFIG_CMDLINE_BOOL
and CONFIG_CMDLINE_OVERRIDE are set, because setup_cmdline function will be
called before setup_early_printk.

Tested it with qemu, so early_printk() is usable and prints to serial console
right after setup_early_printk function called from arch/x86/kerne/head64.c

Changes v1->v2:

* Comment added before the setup_early_printk call;
* Added information about testing to the commit message.

Changes v2->v3:

* Call setup_cmdline before setup_early_printk;
* setup_early_printk call wrapped with the setup_early_serial_console which
checks that 'serial' given to the earlyprintk command line option. This
prevents call of the setup_early_printk with the given pciserial/dbgp/efi,
because they are using early_ioremap.

Signed-off-by: Alexander Kuleshov <kuleshovmail@gmail.com>
---
 arch/x86/kernel/early_printk.c |  2 +-
 arch/x86/kernel/head.c         | 14 ++++++++++++++
 arch/x86/kernel/head32.c       |  2 ++
 arch/x86/kernel/head64.c       |  7 ++++++-
 include/linux/printk.h         |  4 ++++
 kernel/printk/printk.c         | 11 +++++++----
 6 files changed, 34 insertions(+), 6 deletions(-)

diff --git a/arch/x86/kernel/early_printk.c b/arch/x86/kernel/early_printk.c
index a62536a..19a94e0 100644
--- a/arch/x86/kernel/early_printk.c
+++ b/arch/x86/kernel/early_printk.c
@@ -329,7 +329,7 @@ static inline void early_console_register(struct console *con, int keep_early)
 	register_console(early_console);
 }
 
-static int __init setup_early_printk(char *buf)
+int __init setup_early_printk(char *buf)
 {
 	int keep;
 
diff --git a/arch/x86/kernel/head.c b/arch/x86/kernel/head.c
index 992f442..b6e72aa 100644
--- a/arch/x86/kernel/head.c
+++ b/arch/x86/kernel/head.c
@@ -69,3 +69,17 @@ void __init reserve_ebda_region(void)
 	/* reserve all memory between lowmem and the 1MB mark */
 	memblock_reserve(lowmem, 0x100000 - lowmem);
 }
+
+void setup_early_serial_console() {
+#ifdef CONFIG_EARLY_PRINTK
+	char *arg;
+
+	arg = strstr(boot_command_line, "earlyprintk=serial");
+	if (!arg)
+		arg = strstr(boot_command_line, "earlyprintk=ttyS");
+	if (!arg)
+		return;
+
+	setup_early_printk(boot_command_line);
+#endif
+}
diff --git a/arch/x86/kernel/head32.c b/arch/x86/kernel/head32.c
index 7ad0ad0..64c7a80 100644
--- a/arch/x86/kernel/head32.c
+++ b/arch/x86/kernel/head32.c
@@ -32,6 +32,8 @@ static void __init i386_default_early_setup(void)
 asmlinkage __visible void __init i386_start_kernel(void)
 {
 	setup_cmdline();
+	/* setup serial console as early as possible */
+	setup_early_serial_console();
 	cr4_init_shadow();
 	sanitize_boot_params(&boot_params);
 
diff --git a/arch/x86/kernel/head64.c b/arch/x86/kernel/head64.c
index 6eea2de..f0c03bd 100644
--- a/arch/x86/kernel/head64.c
+++ b/arch/x86/kernel/head64.c
@@ -172,12 +172,15 @@ asmlinkage __visible void __init x86_64_start_kernel(char * real_mode_data)
 
 	copy_bootdata(__va(real_mode_data));
 	setup_cmdline();
+	/* setup serial console as early as possible */
+	setup_early_serial_console();
 
 	/*
 	 * Load microcode early on BSP.
 	 */
 	load_ucode_bsp();
 
+
 	if (console_loglevel >= CONSOLE_LOGLEVEL_DEBUG)
 		early_printk("Kernel alive\n");
 
@@ -193,8 +196,10 @@ asmlinkage __visible void __init x86_64_start_kernel(char * real_mode_data)
 void __init x86_64_start_reservations(char *real_mode_data)
 {
 	/* version is always not zero if it is copied */
-	if (!boot_params.hdr.version)
+	if (!boot_params.hdr.version) {
 		copy_bootdata(__va(real_mode_data));
+		setup_early_serial_console();
+	}
 
 	reserve_ebda_region();
 
diff --git a/include/linux/printk.h b/include/linux/printk.h
index baa3f97..17358dd 100644
--- a/include/linux/printk.h
+++ b/include/linux/printk.h
@@ -115,9 +115,13 @@ int no_printk(const char *fmt, ...)
 #ifdef CONFIG_EARLY_PRINTK
 extern asmlinkage __printf(1, 2)
 void early_printk(const char *fmt, ...);
+int setup_early_printk(char *buf);
+void setup_early_serial_console(void);
 #else
 static inline __printf(1, 2) __cold
 void early_printk(const char *s, ...) { }
+int setup_early_printk(char *buf) { }
+static void setup_early_serial_console(void) { }
 #endif
 
 typedef int(*printk_func_t)(const char *fmt, va_list args);
diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c
index bb0635b..e56285c 100644
--- a/kernel/printk/printk.c
+++ b/kernel/printk/printk.c
@@ -2409,11 +2409,14 @@ void register_console(struct console *newcon)
 	struct console_cmdline *c;
 
 	if (console_drivers)
-		for_each_console(bcon)
-			if (WARN(bcon == newcon,
-					"console '%s%d' already registered\n",
-					bcon->name, bcon->index))
+		for_each_console(bcon) {
+			/* not again */
+			if (bcon == newcon) {
+				printk(KERN_INFO "console '%s%d' already registered\n",
+					bcon->name, bcon->index);
 				return;
+			}
+		}
 
 	/*
 	 * before we register a new CON_BOOT console, make sure we don't
-- 
2.3.3.611.g09038fc.dirty


^ permalink raw reply related	[flat|nested] 5+ messages in thread

* Re: [PATCH 2/2] x86/earlyprintk: setup earlyprintk as early as possible
  2015-04-08  9:31 ` [PATCH 2/2] x86/earlyprintk: setup earlyprintk as early as possible Alexander Kuleshov
@ 2015-04-08 11:32   ` Peter Hurley
  2015-04-09  7:39     ` Alexander Kuleshov
  0 siblings, 1 reply; 5+ messages in thread
From: Peter Hurley @ 2015-04-08 11:32 UTC (permalink / raw)
  To: Alexander Kuleshov, Thomas Gleixner, Ingo Molnar, H. Peter Anvin,
	Greg Kroah-Hartman, Yinghai Lu
  Cc: linux-kernel

Hi Alexander,

On 04/08/2015 05:31 AM, Alexander Kuleshov wrote:
> As setup_early_printk passed to the early_param, it will be usable only after
> 'parse_early_param' function will be called from the 'setup_arch'. So we have
> earlyprintk during early boot and decompression. Next point after decompression
> of the kernel where we can use early_printk is after call of the
> 'parse_early_param'.
> 
> This patch makes setup_early_printk visible for head{32,64}.c So 'early_printk'
> function will be usabable after decompression of the kernel and before
> parse_early_param will be called. It also must be safe if CONFIG_CMDLINE_BOOL
> and CONFIG_CMDLINE_OVERRIDE are set, because setup_cmdline function will be
> called before setup_early_printk.
> 
> Tested it with qemu, so early_printk() is usable and prints to serial console
> right after setup_early_printk function called from arch/x86/kerne/head64.c
> 
> Changes v1->v2:
> 
> * Comment added before the setup_early_printk call;
> * Added information about testing to the commit message.
> 
> Changes v2->v3:
> 
> * Call setup_cmdline before setup_early_printk;
> * setup_early_printk call wrapped with the setup_early_serial_console which
> checks that 'serial' given to the earlyprintk command line option. This
> prevents call of the setup_early_printk with the given pciserial/dbgp/efi,
> because they are using early_ioremap.
> 
> Signed-off-by: Alexander Kuleshov <kuleshovmail@gmail.com>
> ---
>  arch/x86/kernel/early_printk.c |  2 +-
>  arch/x86/kernel/head.c         | 14 ++++++++++++++
>  arch/x86/kernel/head32.c       |  2 ++
>  arch/x86/kernel/head64.c       |  7 ++++++-
>  include/linux/printk.h         |  4 ++++
>  kernel/printk/printk.c         | 11 +++++++----
>  6 files changed, 34 insertions(+), 6 deletions(-)
> 
> diff --git a/arch/x86/kernel/early_printk.c b/arch/x86/kernel/early_printk.c
> index a62536a..19a94e0 100644
> --- a/arch/x86/kernel/early_printk.c
> +++ b/arch/x86/kernel/early_printk.c
> @@ -329,7 +329,7 @@ static inline void early_console_register(struct console *con, int keep_early)
>  	register_console(early_console);
>  }
>  
> -static int __init setup_early_printk(char *buf)
> +int __init setup_early_printk(char *buf)
>  {
>  	int keep;
>  
> diff --git a/arch/x86/kernel/head.c b/arch/x86/kernel/head.c
> index 992f442..b6e72aa 100644
> --- a/arch/x86/kernel/head.c
> +++ b/arch/x86/kernel/head.c
> @@ -69,3 +69,17 @@ void __init reserve_ebda_region(void)
>  	/* reserve all memory between lowmem and the 1MB mark */
>  	memblock_reserve(lowmem, 0x100000 - lowmem);
>  }
> +
> +void setup_early_serial_console() {

If you put this function in kernel/early_printk.c, then
setup_early_printk() can remain file scope.

> +#ifdef CONFIG_EARLY_PRINTK
> +	char *arg;
> +
> +	arg = strstr(boot_command_line, "earlyprintk=serial");
> +	if (!arg)
> +		arg = strstr(boot_command_line, "earlyprintk=ttyS");
> +	if (!arg)
> +		return;
> +
> +	setup_early_printk(boot_command_line);

Like Ingo already pointed out, you need to emit a printk() after the
call to setup_early_printk() which validates that earlier-than-early
is working.

Because this isn't. setup_early_printk() expects the argument
to point to the start of the earlyprintk= parameter; ie.,

       earlyprintk=ttyS0,115200
                   ^
                  buf


> +#endif
> +}
> diff --git a/arch/x86/kernel/head32.c b/arch/x86/kernel/head32.c
> index 7ad0ad0..64c7a80 100644
> --- a/arch/x86/kernel/head32.c
> +++ b/arch/x86/kernel/head32.c
> @@ -32,6 +32,8 @@ static void __init i386_default_early_setup(void)
>  asmlinkage __visible void __init i386_start_kernel(void)
>  {
>  	setup_cmdline();
> +	/* setup serial console as early as possible */
> +	setup_early_serial_console();
>  	cr4_init_shadow();
>  	sanitize_boot_params(&boot_params);
>  
> diff --git a/arch/x86/kernel/head64.c b/arch/x86/kernel/head64.c
> index 6eea2de..f0c03bd 100644
> --- a/arch/x86/kernel/head64.c
> +++ b/arch/x86/kernel/head64.c
> @@ -172,12 +172,15 @@ asmlinkage __visible void __init x86_64_start_kernel(char * real_mode_data)
>  
>  	copy_bootdata(__va(real_mode_data));
>  	setup_cmdline();
> +	/* setup serial console as early as possible */
> +	setup_early_serial_console();
>  
>  	/*
>  	 * Load microcode early on BSP.
>  	 */
>  	load_ucode_bsp();
>  
> +
>  	if (console_loglevel >= CONSOLE_LOGLEVEL_DEBUG)
>  		early_printk("Kernel alive\n");
>  
> @@ -193,8 +196,10 @@ asmlinkage __visible void __init x86_64_start_kernel(char * real_mode_data)
>  void __init x86_64_start_reservations(char *real_mode_data)
>  {
>  	/* version is always not zero if it is copied */
> -	if (!boot_params.hdr.version)
> +	if (!boot_params.hdr.version) {
>  		copy_bootdata(__va(real_mode_data));
> +		setup_early_serial_console();
> +	}
>  
>  	reserve_ebda_region();
>  
> diff --git a/include/linux/printk.h b/include/linux/printk.h
> index baa3f97..17358dd 100644
> --- a/include/linux/printk.h
> +++ b/include/linux/printk.h
> @@ -115,9 +115,13 @@ int no_printk(const char *fmt, ...)
>  #ifdef CONFIG_EARLY_PRINTK
>  extern asmlinkage __printf(1, 2)
>  void early_printk(const char *fmt, ...);
> +int setup_early_printk(char *buf);
> +void setup_early_serial_console(void);
>  #else
>  static inline __printf(1, 2) __cold
>  void early_printk(const char *s, ...) { }
> +int setup_early_printk(char *buf) { }
> +static void setup_early_serial_console(void) { }
>  #endif

These can't go here, because this will break the build of every non-x86
arch, since these symbols will not be defined in those arches. These need
to be in x86 includes only.

>  
>  typedef int(*printk_func_t)(const char *fmt, va_list args);
> diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c
> index bb0635b..e56285c 100644
> --- a/kernel/printk/printk.c
> +++ b/kernel/printk/printk.c
> @@ -2409,11 +2409,14 @@ void register_console(struct console *newcon)
>  	struct console_cmdline *c;
>  
>  	if (console_drivers)
> -		for_each_console(bcon)
> -			if (WARN(bcon == newcon,
> -					"console '%s%d' already registered\n",
> -					bcon->name, bcon->index))
> +		for_each_console(bcon) {
> +			/* not again */
> +			if (bcon == newcon) {
> +				printk(KERN_INFO "console '%s%d' already registered\n",
> +					bcon->name, bcon->index);
>  				return;
> +			}
> +		}

The WARN is still required here because the register_console() caller
is not always obvious.

A better way to achieve what you want is to not re-register the console
to begin with. Looking at early_console_register() and setup_early_printk(),
it seems like re-registration would already be prevented (since early_console
!= 0 after the first call to early_console_register())?  Have you tried this?

Regards,
Peter Hurley

>  
>  	/*
>  	 * before we register a new CON_BOOT console, make sure we don't
> 


^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PATCH 2/2] x86/earlyprintk: setup earlyprintk as early as possible
  2015-04-08 11:32   ` Peter Hurley
@ 2015-04-09  7:39     ` Alexander Kuleshov
  0 siblings, 0 replies; 5+ messages in thread
From: Alexander Kuleshov @ 2015-04-09  7:39 UTC (permalink / raw)
  To: Peter Hurley
  Cc: Thomas Gleixner, Ingo Molnar, H. Peter Anvin, Greg Kroah-Hartman,
	Yinghai Lu, LKML

Hello Peter,

2015-04-08 17:32 GMT+06:00 Peter Hurley <peter@hurleysoftware.com>:
>> +
>> +void setup_early_serial_console() {
>
> If you put this function in kernel/early_printk.c, then
> setup_early_printk() can remain file scope.
>

Yes, right. will fix it.

>
> The WARN is still required here because the register_console() caller
> is not always obvious.
>
> A better way to achieve what you want is to not re-register the console
> to begin with. Looking at early_console_register() and setup_early_printk(),
> it seems like re-registration would already be prevented (since early_console
> != 0 after the first call to early_console_register())?  Have you tried this?
>

hmm, now, thanks for the point will test it.

Thank you.

^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2015-04-09  7:39 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-04-08  9:31 [PATCH 0/2] x86/earlyprintk: setup earlyprintk as early as possible Alexander Kuleshov
2015-04-08  9:31 ` [PATCH 1/2] x86/setup: update boot_command_line with builtin_cmdline in separate function Alexander Kuleshov
2015-04-08  9:31 ` [PATCH 2/2] x86/earlyprintk: setup earlyprintk as early as possible Alexander Kuleshov
2015-04-08 11:32   ` Peter Hurley
2015-04-09  7:39     ` Alexander Kuleshov

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.