From 97baeefd5b42d5f43006928126733d63379d0c46 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Roger=20Pau=20Monn=C3=A9?= Date: Tue, 11 Mar 2014 10:15:25 +0000 Subject: [PATCH] amd64: introduce hook for custom preload metadata parsers Add hooks to amd64 in order to have diverging implementations, since on Xen PV the metadata is passed to the kernel in a different form. Approbed by: gibbs Sponsored by: Citrix Systems R&D amd64/amd64/machdep.c: - Define init_ops for native. - Put native code inside of native_parse_preload_data hook. - Call the parse_preload_data in order to fill the metadata info. x86/include/init.h: - Declare the init_ops struct. x86/xen/pv.c: - Declare xen_init_ops that contains the Xen PV implementation of init_ops. - Implement the parse_preload_data for Xen PVH, the info is fetched from HYPERVISOR_start_info->cmd_line as provided by Xen. --- sys/amd64/amd64/machdep.c | 41 ++++++++++++++++++------- sys/x86/include/init.h | 43 ++++++++++++++++++++++++++ sys/x86/xen/pv.c | 63 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 136 insertions(+), 11 deletions(-) create mode 100644 sys/x86/include/init.h diff --git a/sys/amd64/amd64/machdep.c b/sys/amd64/amd64/machdep.c index 52256f7c30ff..dc4b09c9c2e7 100644 --- a/sys/amd64/amd64/machdep.c +++ b/sys/amd64/amd64/machdep.c @@ -145,6 +145,7 @@ __FBSDID("$FreeBSD$"); #include #include +#include /* Sanity check for __curthread() */ CTASSERT(offsetof(struct pcpu, pc_curthread) == 0); @@ -165,6 +166,14 @@ static int set_fpcontext(struct thread *td, const mcontext_t *mcp, char *xfpustate, size_t xfpustate_len); SYSINIT(cpu, SI_SUB_CPU, SI_ORDER_FIRST, cpu_startup, NULL); +/* Preload data parse function */ +static caddr_t native_parse_preload_data(u_int64_t); + +/* Default init_ops implementation. */ +struct init_ops init_ops = { + .parse_preload_data = native_parse_preload_data, +}; + /* * The file "conf/ldscript.amd64" defines the symbol "kernphys". Its value is * the physical address at which the kernel is loaded. @@ -1685,6 +1694,26 @@ do_next: msgbufp = (struct msgbuf *)PHYS_TO_DMAP(phys_avail[pa_indx]); } +static caddr_t +native_parse_preload_data(u_int64_t modulep) +{ + caddr_t kmdp; + + preload_metadata = (caddr_t)(uintptr_t)(modulep + KERNBASE); + preload_bootstrap_relocate(KERNBASE); + kmdp = preload_search_by_type("elf kernel"); + if (kmdp == NULL) + kmdp = preload_search_by_type("elf64 kernel"); + boothowto = MD_FETCH(kmdp, MODINFOMD_HOWTO, int); + kern_envp = MD_FETCH(kmdp, MODINFOMD_ENVP, char *) + KERNBASE; +#ifdef DDB + ksym_start = MD_FETCH(kmdp, MODINFOMD_SSYM, uintptr_t); + ksym_end = MD_FETCH(kmdp, MODINFOMD_ESYM, uintptr_t); +#endif + + return (kmdp); +} + u_int64_t hammer_time(u_int64_t modulep, u_int64_t physfree) { @@ -1709,17 +1738,7 @@ hammer_time(u_int64_t modulep, u_int64_t physfree) */ proc_linkup0(&proc0, &thread0); - preload_metadata = (caddr_t)(uintptr_t)(modulep + KERNBASE); - preload_bootstrap_relocate(KERNBASE); - kmdp = preload_search_by_type("elf kernel"); - if (kmdp == NULL) - kmdp = preload_search_by_type("elf64 kernel"); - boothowto = MD_FETCH(kmdp, MODINFOMD_HOWTO, int); - kern_envp = MD_FETCH(kmdp, MODINFOMD_ENVP, char *) + KERNBASE; -#ifdef DDB - ksym_start = MD_FETCH(kmdp, MODINFOMD_SSYM, uintptr_t); - ksym_end = MD_FETCH(kmdp, MODINFOMD_ESYM, uintptr_t); -#endif + kmdp = init_ops.parse_preload_data(modulep); /* Init basic tunables, hz etc */ init_param1(); diff --git a/sys/x86/include/init.h b/sys/x86/include/init.h new file mode 100644 index 000000000000..7e032df214fe --- /dev/null +++ b/sys/x86/include/init.h @@ -0,0 +1,43 @@ +/*- + * Copyright (c) 2013 Roger Pau Monné + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#ifndef __X86_INIT_H__ +#define __X86_INIT_H__ +/* + * Struct containing pointers to init functions whose + * implementation is run time selectable. Selection can be made, + * for example, based on detection of a BIOS variant or + * hypervisor environment. + */ +struct init_ops { + caddr_t (*parse_preload_data)(u_int64_t); +}; + +extern struct init_ops init_ops; + +#endif /* __X86_INIT_H__ */ diff --git a/sys/x86/xen/pv.c b/sys/x86/xen/pv.c index 94985e3d1ad9..63dc39b92709 100644 --- a/sys/x86/xen/pv.c +++ b/sys/x86/xen/pv.c @@ -37,6 +37,7 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include #include #include @@ -47,6 +48,8 @@ __FBSDID("$FreeBSD$"); #include #include +#include + #include #include @@ -55,6 +58,16 @@ extern u_int64_t hammer_time(u_int64_t, u_int64_t); /* Xen initial function */ uint64_t hammer_time_xen(start_info_t *, uint64_t); +/*--------------------------- Forward Declarations ---------------------------*/ +static caddr_t xen_pv_parse_preload_data(u_int64_t); + +/*-------------------------------- Global Data -------------------------------*/ +/* Xen init_ops implementation. */ +struct init_ops xen_init_ops = { + .parse_preload_data = xen_pv_parse_preload_data, +}; + +/*-------------------------------- Xen PV init -------------------------------*/ /* * First function called by the Xen PVH boot sequence. * @@ -119,6 +132,56 @@ hammer_time_xen(start_info_t *si, uint64_t xenstack) } load_cr3(((uint64_t)&PT4[0]) - KERNBASE); + /* Set the hooks for early functions that diverge from bare metal */ + init_ops = xen_init_ops; + /* Now we can jump into the native init function */ return (hammer_time(0, physfree)); } + +/*-------------------------------- PV specific -------------------------------*/ +/* + * Functions to convert the "extra" parameters passed by Xen + * into FreeBSD boot options. + */ +static void +xen_pv_set_env(void) +{ + char *cmd_line_next, *cmd_line; + size_t env_size; + + cmd_line = HYPERVISOR_start_info->cmd_line; + env_size = sizeof(HYPERVISOR_start_info->cmd_line); + + /* Skip leading spaces */ + for (; isspace(*cmd_line) && (env_size != 0); cmd_line++) + env_size--; + + /* Replace ',' with '\0' */ + for (cmd_line_next = cmd_line; strsep(&cmd_line_next, ",") != NULL;) + ; + + init_static_kenv(cmd_line, env_size); +} + +static void +xen_pv_set_boothowto(void) +{ + int i; + + /* get equivalents from the environment */ + for (i = 0; howto_names[i].ev != NULL; i++) { + if (getenv(howto_names[i].ev) != NULL) + boothowto |= howto_names[i].mask; + } +} + +static caddr_t +xen_pv_parse_preload_data(u_int64_t modulep) +{ + /* Parse the extra boot information given by Xen */ + xen_pv_set_env(); + xen_pv_set_boothowto(); + + return (NULL); +}