1 /******************************************************************************
2  * arch/x86/guest/pvh-boot.c
3  *
4  * PVH boot time support
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; If not, see <http://www.gnu.org/licenses/>.
18  *
19  * Copyright (c) 2017 Citrix Systems Ltd.
20  */
21 #include <xen/init.h>
22 #include <xen/lib.h>
23 #include <xen/mm.h>
24 
25 #include <asm/e820.h>
26 #include <asm/guest.h>
27 
28 #include <public/arch-x86/hvm/start_info.h>
29 
30 /* Initialised in head.S, before .bss is zeroed. */
31 bool __initdata pvh_boot;
32 uint32_t __initdata pvh_start_info_pa;
33 
34 static multiboot_info_t __initdata pvh_mbi;
35 static module_t __initdata pvh_mbi_mods[8];
36 static const char *__initdata pvh_loader = "PVH Directboot";
37 
convert_pvh_info(void)38 static void __init convert_pvh_info(void)
39 {
40     const struct hvm_start_info *pvh_info = __va(pvh_start_info_pa);
41     const struct hvm_modlist_entry *entry;
42     module_t *mod;
43     unsigned int i;
44 
45     ASSERT(pvh_info->magic == XEN_HVM_START_MAGIC_VALUE);
46 
47     /*
48      * Turn hvm_start_info into mbi. Luckily all modules are placed under 4GB
49      * boundary on x86.
50      */
51     pvh_mbi.flags = MBI_CMDLINE | MBI_MODULES | MBI_LOADERNAME;
52 
53     BUG_ON(pvh_info->cmdline_paddr >> 32);
54     pvh_mbi.cmdline = pvh_info->cmdline_paddr;
55     pvh_mbi.boot_loader_name = __pa(pvh_loader);
56 
57     BUG_ON(pvh_info->nr_modules >= ARRAY_SIZE(pvh_mbi_mods));
58     pvh_mbi.mods_count = pvh_info->nr_modules;
59     pvh_mbi.mods_addr = __pa(pvh_mbi_mods);
60 
61     mod = pvh_mbi_mods;
62     entry = __va(pvh_info->modlist_paddr);
63     for ( i = 0; i < pvh_info->nr_modules; i++ )
64     {
65         BUG_ON(entry[i].paddr >> 32);
66         BUG_ON(entry[i].cmdline_paddr >> 32);
67 
68         mod[i].mod_start = entry[i].paddr;
69         mod[i].mod_end   = entry[i].paddr + entry[i].size;
70         mod[i].string    = entry[i].cmdline_paddr;
71     }
72 }
73 
get_memory_map(void)74 static void __init get_memory_map(void)
75 {
76     struct xen_memory_map memmap = {
77         .nr_entries = E820MAX,
78     };
79 
80     set_xen_guest_handle(memmap.buffer, e820_raw.map);
81     BUG_ON(xen_hypercall_memory_op(XENMEM_memory_map, &memmap));
82     e820_raw.nr_map = memmap.nr_entries;
83 
84     /* :( Various toolstacks don't sort the memory map. */
85     sanitize_e820_map(e820_raw.map, &e820_raw.nr_map);
86 }
87 
pvh_init(void)88 multiboot_info_t *__init pvh_init(void)
89 {
90     convert_pvh_info();
91 
92     probe_hypervisor();
93     ASSERT(xen_guest);
94 
95     get_memory_map();
96 
97     return &pvh_mbi;
98 }
99 
pvh_print_info(void)100 void __init pvh_print_info(void)
101 {
102     const struct hvm_start_info *pvh_info = __va(pvh_start_info_pa);
103     const struct hvm_modlist_entry *entry;
104     unsigned int i;
105 
106     ASSERT(pvh_info->magic == XEN_HVM_START_MAGIC_VALUE);
107 
108     printk("PVH start info: (pa %08x)\n", pvh_start_info_pa);
109     printk("  version:    %u\n", pvh_info->version);
110     printk("  flags:      %#"PRIx32"\n", pvh_info->flags);
111     printk("  nr_modules: %u\n", pvh_info->nr_modules);
112     printk("  modlist_pa: %016"PRIx64"\n", pvh_info->modlist_paddr);
113     printk("  cmdline_pa: %016"PRIx64"\n", pvh_info->cmdline_paddr);
114     if ( pvh_info->cmdline_paddr )
115         printk("  cmdline:    '%s'\n", (char *)__va(pvh_info->cmdline_paddr));
116     printk("  rsdp_pa:    %016"PRIx64"\n", pvh_info->rsdp_paddr);
117 
118     entry = __va(pvh_info->modlist_paddr);
119     for ( i = 0; i < pvh_info->nr_modules; i++ )
120     {
121         printk("    mod[%u].pa:         %016"PRIx64"\n", i, entry[i].paddr);
122         printk("    mod[%u].size:       %016"PRIu64"\n", i, entry[i].size);
123         printk("    mod[%u].cmdline_pa: %016"PRIx64"\n",
124                i, entry[i].cmdline_paddr);
125         if ( entry[i].cmdline_paddr )
126             printk("    mod[%1u].cmdline:    '%s'\n", i,
127                    (char *)__va(entry[i].cmdline_paddr));
128     }
129 }
130 
131 /*
132  * Local variables:
133  * mode: C
134  * c-file-style: "BSD"
135  * c-basic-offset: 4
136  * tab-width: 4
137  * indent-tabs-mode: nil
138  * End:
139  */
140