mirror of
https://github.com/xen-project/xen.git
synced 2026-10-29 18:50:05 +01:00
Signed-off-by: Mukesh Rathor <mukesh.rathor@oracle.com> Acked-by: Tim Deegan <tim@xen.org> Acked-by: Ian Jackson <ian.jackson@eu.citrix.com> Acked-by: Keir Fraser <keir@xen.org> Acked-by: Eddie Dong <eddie.dong@intel.com>
373 lines
12 KiB
C
373 lines
12 KiB
C
/*
|
|
* This library is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
* License as published by the Free Software Foundation;
|
|
* version 2.1 of the License.
|
|
*
|
|
* This library is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* Lesser General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
* License along with this library; if not, write to the Free Software
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
*/
|
|
|
|
#include <xen/libelf/libelf.h>
|
|
|
|
#define INVALID_P2M_ENTRY ((xen_pfn_t)-1)
|
|
|
|
/* --- typedefs and structs ---------------------------------------- */
|
|
|
|
typedef uint64_t xen_vaddr_t;
|
|
typedef uint64_t xen_paddr_t;
|
|
|
|
#define PRIpfn PRI_xen_pfn
|
|
|
|
struct xc_dom_seg {
|
|
xen_vaddr_t vstart;
|
|
xen_vaddr_t vend;
|
|
xen_pfn_t pfn;
|
|
};
|
|
|
|
struct xc_dom_mem {
|
|
struct xc_dom_mem *next;
|
|
void *mmap_ptr;
|
|
size_t mmap_len;
|
|
unsigned char memory[0];
|
|
};
|
|
|
|
struct xc_dom_phys {
|
|
struct xc_dom_phys *next;
|
|
void *ptr;
|
|
xen_pfn_t first;
|
|
xen_pfn_t count;
|
|
};
|
|
|
|
struct xc_dom_image {
|
|
/* files */
|
|
void *kernel_blob;
|
|
size_t kernel_size;
|
|
void *ramdisk_blob;
|
|
size_t ramdisk_size;
|
|
|
|
size_t max_kernel_size;
|
|
size_t max_ramdisk_size;
|
|
|
|
/* arguments and parameters */
|
|
char *cmdline;
|
|
uint32_t f_requested[XENFEAT_NR_SUBMAPS];
|
|
|
|
/* info from (elf) kernel image */
|
|
struct elf_dom_parms parms;
|
|
char *guest_type;
|
|
|
|
/* memory layout */
|
|
struct xc_dom_seg kernel_seg;
|
|
struct xc_dom_seg ramdisk_seg;
|
|
struct xc_dom_seg p2m_seg;
|
|
struct xc_dom_seg pgtables_seg;
|
|
struct xc_dom_seg devicetree_seg;
|
|
xen_pfn_t start_info_pfn;
|
|
xen_pfn_t console_pfn;
|
|
xen_pfn_t xenstore_pfn;
|
|
xen_pfn_t shared_info_pfn;
|
|
xen_pfn_t bootstack_pfn;
|
|
xen_vaddr_t virt_alloc_end;
|
|
xen_vaddr_t bsd_symtab_start;
|
|
|
|
/* initial page tables */
|
|
unsigned int pgtables;
|
|
unsigned int pg_l4;
|
|
unsigned int pg_l3;
|
|
unsigned int pg_l2;
|
|
unsigned int pg_l1;
|
|
unsigned int alloc_bootstack;
|
|
unsigned int extra_pages;
|
|
xen_vaddr_t virt_pgtab_end;
|
|
|
|
/* other state info */
|
|
uint32_t f_active[XENFEAT_NR_SUBMAPS];
|
|
/*
|
|
* p2m_host maps guest physical addresses an offset from
|
|
* rambase_pfn (see below) into gfns.
|
|
*
|
|
* For a pure PV guest this means that it maps GPFNs into MFNs for
|
|
* a hybrid guest this means that it maps GPFNs to GPFNS.
|
|
*
|
|
* Note that the input is offset by rambase.
|
|
*/
|
|
xen_pfn_t *p2m_host;
|
|
void *p2m_guest;
|
|
|
|
/* physical memory
|
|
*
|
|
* A PV guest has a single contiguous block of physical RAM,
|
|
* consisting of total_pages starting at rambase_pfn.
|
|
*/
|
|
xen_pfn_t rambase_pfn;
|
|
xen_pfn_t total_pages;
|
|
struct xc_dom_phys *phys_pages;
|
|
int realmodearea_log;
|
|
|
|
/* malloc memory pool */
|
|
struct xc_dom_mem *memblocks;
|
|
|
|
/* memory footprint stats */
|
|
size_t alloc_malloc;
|
|
size_t alloc_mem_map;
|
|
size_t alloc_file_map;
|
|
size_t alloc_domU_map;
|
|
|
|
/* misc xen domain config stuff */
|
|
unsigned long flags;
|
|
unsigned int console_evtchn;
|
|
unsigned int xenstore_evtchn;
|
|
domid_t console_domid;
|
|
domid_t xenstore_domid;
|
|
xen_pfn_t shared_info_mfn;
|
|
int pvh_enabled;
|
|
|
|
xc_interface *xch;
|
|
domid_t guest_domid;
|
|
int8_t vhpt_size_log2; /* for IA64 */
|
|
int8_t superpages;
|
|
int claim_enabled; /* 0 by default, 1 enables it */
|
|
int shadow_enabled;
|
|
|
|
int xen_version;
|
|
xen_capabilities_info_t xen_caps;
|
|
|
|
/* kernel loader, arch hooks */
|
|
struct xc_dom_loader *kernel_loader;
|
|
void *private_loader;
|
|
|
|
/* kernel loader */
|
|
struct xc_dom_arch *arch_hooks;
|
|
/* allocate up to virt_alloc_end */
|
|
int (*allocate) (struct xc_dom_image * dom, xen_vaddr_t up_to);
|
|
};
|
|
|
|
/* --- pluggable kernel loader ------------------------------------- */
|
|
|
|
struct xc_dom_loader {
|
|
char *name;
|
|
/* Sadly the error returns from these functions are not consistent: */
|
|
elf_negerrnoval (*probe) (struct xc_dom_image * dom);
|
|
elf_negerrnoval (*parser) (struct xc_dom_image * dom);
|
|
elf_errorstatus (*loader) (struct xc_dom_image * dom);
|
|
|
|
struct xc_dom_loader *next;
|
|
};
|
|
|
|
#define __init __attribute__ ((constructor))
|
|
void xc_dom_register_loader(struct xc_dom_loader *loader);
|
|
|
|
/* --- arch specific hooks ----------------------------------------- */
|
|
|
|
struct xc_dom_arch {
|
|
/* pagetable setup */
|
|
int (*alloc_magic_pages) (struct xc_dom_image * dom);
|
|
int (*count_pgtables) (struct xc_dom_image * dom);
|
|
int (*setup_pgtables) (struct xc_dom_image * dom);
|
|
|
|
/* arch-specific data structs setup */
|
|
int (*start_info) (struct xc_dom_image * dom);
|
|
int (*shared_info) (struct xc_dom_image * dom, void *shared_info);
|
|
int (*vcpu) (struct xc_dom_image * dom, void *vcpu_ctxt);
|
|
|
|
char *guest_type;
|
|
char *native_protocol;
|
|
int page_shift;
|
|
int sizeof_pfn;
|
|
|
|
struct xc_dom_arch *next;
|
|
};
|
|
void xc_dom_register_arch_hooks(struct xc_dom_arch *hooks);
|
|
|
|
#define XC_DOM_PAGE_SHIFT(dom) ((dom)->arch_hooks->page_shift)
|
|
#define XC_DOM_PAGE_SIZE(dom) (1 << (dom)->arch_hooks->page_shift)
|
|
|
|
/* --- main functions ---------------------------------------------- */
|
|
|
|
struct xc_dom_image *xc_dom_allocate(xc_interface *xch,
|
|
const char *cmdline, const char *features);
|
|
void xc_dom_release_phys(struct xc_dom_image *dom);
|
|
void xc_dom_release(struct xc_dom_image *dom);
|
|
int xc_dom_mem_init(struct xc_dom_image *dom, unsigned int mem_mb);
|
|
|
|
/* Set this larger if you have enormous ramdisks/kernels. Note that
|
|
* you should trust all kernels not to be maliciously large (e.g. to
|
|
* exhaust all dom0 memory) if you do this (see CVE-2012-4544 /
|
|
* XSA-25). You can also set the default independently for
|
|
* ramdisks/kernels in xc_dom_allocate() or call
|
|
* xc_dom_{kernel,ramdisk}_max_size.
|
|
*/
|
|
#ifndef XC_DOM_DECOMPRESS_MAX
|
|
#define XC_DOM_DECOMPRESS_MAX (1024*1024*1024) /* 1GB */
|
|
#endif
|
|
|
|
int xc_dom_kernel_check_size(struct xc_dom_image *dom, size_t sz);
|
|
int xc_dom_kernel_max_size(struct xc_dom_image *dom, size_t sz);
|
|
|
|
int xc_dom_ramdisk_check_size(struct xc_dom_image *dom, size_t sz);
|
|
int xc_dom_ramdisk_max_size(struct xc_dom_image *dom, size_t sz);
|
|
|
|
size_t xc_dom_check_gzip(xc_interface *xch,
|
|
void *blob, size_t ziplen);
|
|
int xc_dom_do_gunzip(xc_interface *xch,
|
|
void *src, size_t srclen, void *dst, size_t dstlen);
|
|
int xc_dom_try_gunzip(struct xc_dom_image *dom, void **blob, size_t * size);
|
|
|
|
int xc_dom_kernel_file(struct xc_dom_image *dom, const char *filename);
|
|
int xc_dom_ramdisk_file(struct xc_dom_image *dom, const char *filename);
|
|
int xc_dom_kernel_mem(struct xc_dom_image *dom, const void *mem,
|
|
size_t memsize);
|
|
int xc_dom_ramdisk_mem(struct xc_dom_image *dom, const void *mem,
|
|
size_t memsize);
|
|
|
|
int xc_dom_parse_image(struct xc_dom_image *dom);
|
|
struct xc_dom_arch *xc_dom_find_arch_hooks(xc_interface *xch, char *guest_type);
|
|
int xc_dom_build_image(struct xc_dom_image *dom);
|
|
int xc_dom_update_guest_p2m(struct xc_dom_image *dom);
|
|
|
|
int xc_dom_boot_xen_init(struct xc_dom_image *dom, xc_interface *xch,
|
|
domid_t domid);
|
|
int xc_dom_boot_mem_init(struct xc_dom_image *dom);
|
|
void *xc_dom_boot_domU_map(struct xc_dom_image *dom, xen_pfn_t pfn,
|
|
xen_pfn_t count);
|
|
int xc_dom_boot_image(struct xc_dom_image *dom);
|
|
int xc_dom_compat_check(struct xc_dom_image *dom);
|
|
int xc_dom_gnttab_init(struct xc_dom_image *dom);
|
|
int xc_dom_gnttab_hvm_seed(xc_interface *xch, domid_t domid,
|
|
xen_pfn_t console_gmfn,
|
|
xen_pfn_t xenstore_gmfn,
|
|
domid_t console_domid,
|
|
domid_t xenstore_domid);
|
|
int xc_dom_gnttab_seed(xc_interface *xch, domid_t domid,
|
|
xen_pfn_t console_gmfn,
|
|
xen_pfn_t xenstore_gmfn,
|
|
domid_t console_domid,
|
|
domid_t xenstore_domid);
|
|
int xc_dom_feature_translated(struct xc_dom_image *dom);
|
|
|
|
/* --- debugging bits ---------------------------------------------- */
|
|
|
|
int xc_dom_loginit(xc_interface *xch);
|
|
|
|
void xc_dom_printf(xc_interface *xch, const char *fmt, ...)
|
|
__attribute__ ((format(printf, 2, 3)));
|
|
void xc_dom_panic_func(xc_interface *xch,
|
|
const char *file, int line, xc_error_code err,
|
|
const char *fmt, ...)
|
|
__attribute__ ((format(printf, 5, 6)));
|
|
|
|
#define xc_dom_panic(xch, err, fmt, args...) \
|
|
xc_dom_panic_func(xch, __FILE__, __LINE__, err, fmt, ## args)
|
|
#define xc_dom_trace(mark) \
|
|
xc_dom_printf("%s:%d: trace %s\n", __FILE__, __LINE__, mark)
|
|
|
|
void xc_dom_log_memory_footprint(struct xc_dom_image *dom);
|
|
|
|
/* --- simple memory pool ------------------------------------------ */
|
|
|
|
void *xc_dom_malloc(struct xc_dom_image *dom, size_t size);
|
|
void *xc_dom_malloc_page_aligned(struct xc_dom_image *dom, size_t size);
|
|
void *xc_dom_malloc_filemap(struct xc_dom_image *dom,
|
|
const char *filename, size_t * size,
|
|
const size_t max_size);
|
|
char *xc_dom_strdup(struct xc_dom_image *dom, const char *str);
|
|
|
|
/* --- alloc memory pool ------------------------------------------- */
|
|
|
|
int xc_dom_alloc_page(struct xc_dom_image *dom, char *name);
|
|
int xc_dom_alloc_segment(struct xc_dom_image *dom,
|
|
struct xc_dom_seg *seg, char *name,
|
|
xen_vaddr_t start, xen_vaddr_t size);
|
|
|
|
/* --- misc bits --------------------------------------------------- */
|
|
|
|
void *xc_dom_pfn_to_ptr(struct xc_dom_image *dom, xen_pfn_t first,
|
|
xen_pfn_t count);
|
|
void *xc_dom_pfn_to_ptr_retcount(struct xc_dom_image *dom, xen_pfn_t first,
|
|
xen_pfn_t count, xen_pfn_t *count_out);
|
|
void xc_dom_unmap_one(struct xc_dom_image *dom, xen_pfn_t pfn);
|
|
void xc_dom_unmap_all(struct xc_dom_image *dom);
|
|
|
|
static inline void *xc_dom_seg_to_ptr_pages(struct xc_dom_image *dom,
|
|
struct xc_dom_seg *seg,
|
|
xen_pfn_t *pages_out)
|
|
{
|
|
xen_vaddr_t segsize = seg->vend - seg->vstart;
|
|
unsigned int page_size = XC_DOM_PAGE_SIZE(dom);
|
|
xen_pfn_t pages = (segsize + page_size - 1) / page_size;
|
|
void *retval;
|
|
|
|
retval = xc_dom_pfn_to_ptr(dom, seg->pfn, pages);
|
|
|
|
*pages_out = retval ? pages : 0;
|
|
return retval;
|
|
}
|
|
|
|
static inline void *xc_dom_seg_to_ptr(struct xc_dom_image *dom,
|
|
struct xc_dom_seg *seg)
|
|
{
|
|
xen_pfn_t dummy;
|
|
|
|
return xc_dom_seg_to_ptr_pages(dom, seg, &dummy);
|
|
}
|
|
|
|
static inline void *xc_dom_vaddr_to_ptr(struct xc_dom_image *dom,
|
|
xen_vaddr_t vaddr,
|
|
size_t *safe_region_out)
|
|
{
|
|
unsigned int page_size = XC_DOM_PAGE_SIZE(dom);
|
|
xen_pfn_t page = (vaddr - dom->parms.virt_base) / page_size;
|
|
unsigned int offset = (vaddr - dom->parms.virt_base) % page_size;
|
|
xen_pfn_t safe_region_count;
|
|
void *ptr;
|
|
|
|
*safe_region_out = 0;
|
|
ptr = xc_dom_pfn_to_ptr_retcount(dom, page, 0, &safe_region_count);
|
|
if ( ptr == NULL )
|
|
return ptr;
|
|
*safe_region_out = (safe_region_count << XC_DOM_PAGE_SHIFT(dom)) - offset;
|
|
return ptr;
|
|
}
|
|
|
|
static inline xen_pfn_t xc_dom_p2m_host(struct xc_dom_image *dom, xen_pfn_t pfn)
|
|
{
|
|
if (dom->shadow_enabled)
|
|
return pfn;
|
|
if (pfn < dom->rambase_pfn || pfn >= dom->rambase_pfn + dom->total_pages)
|
|
return INVALID_MFN;
|
|
return dom->p2m_host[pfn - dom->rambase_pfn];
|
|
}
|
|
|
|
static inline xen_pfn_t xc_dom_p2m_guest(struct xc_dom_image *dom,
|
|
xen_pfn_t pfn)
|
|
{
|
|
if (xc_dom_feature_translated(dom))
|
|
return pfn;
|
|
if (pfn < dom->rambase_pfn || pfn >= dom->rambase_pfn + dom->total_pages)
|
|
return INVALID_MFN;
|
|
return dom->p2m_host[pfn - dom->rambase_pfn];
|
|
}
|
|
|
|
/* --- arch bits --------------------------------------------------- */
|
|
|
|
int arch_setup_meminit(struct xc_dom_image *dom);
|
|
int arch_setup_bootearly(struct xc_dom_image *dom);
|
|
int arch_setup_bootlate(struct xc_dom_image *dom);
|
|
|
|
/*
|
|
* Local variables:
|
|
* mode: C
|
|
* c-file-style: "BSD"
|
|
* c-basic-offset: 4
|
|
* tab-width: 4
|
|
* indent-tabs-mode: nil
|
|
* End:
|
|
*/
|