[34] | 1 | /* |
---|
| 2 | * Xen domain builder -- powerpc bits. |
---|
| 3 | * |
---|
| 4 | * Most architecture-specific code for powerpc goes here. |
---|
| 5 | * |
---|
| 6 | * This code is licenced under the GPL. |
---|
| 7 | * written 2006 by Gerd Hoffmann <kraxel@suse.de>. |
---|
| 8 | * |
---|
| 9 | * Copyright IBM Corp. 2007 |
---|
| 10 | * |
---|
| 11 | * Authors: Gerd Hoffmann <kraxel@suse.de> |
---|
| 12 | * Hollis Blanchard <hollisb@us.ibm.com> |
---|
| 13 | * |
---|
| 14 | */ |
---|
| 15 | #include <stdio.h> |
---|
| 16 | #include <stdlib.h> |
---|
| 17 | #include <string.h> |
---|
| 18 | #include <inttypes.h> |
---|
| 19 | |
---|
| 20 | #include <xen/xen.h> |
---|
| 21 | |
---|
| 22 | #include "xg_private.h" |
---|
| 23 | #include "xc_dom.h" |
---|
| 24 | #include "powerpc64/flatdevtree.h" |
---|
| 25 | #include "powerpc64/mk_flatdevtree.h" |
---|
| 26 | |
---|
| 27 | #define RMA_LOG 26 /* 64 MB */ |
---|
| 28 | #define EXTENT_LOG 24 /* 16 MB */ |
---|
| 29 | #define EXTENT_ORDER (EXTENT_LOG - PAGE_SHIFT) |
---|
| 30 | |
---|
| 31 | /* ------------------------------------------------------------------------ */ |
---|
| 32 | |
---|
| 33 | static int alloc_magic_pages(struct xc_dom_image *dom) |
---|
| 34 | { |
---|
| 35 | struct ft_cxt devtree; |
---|
| 36 | void *guest_devtree; |
---|
| 37 | unsigned long shadow_mb; |
---|
| 38 | int rma_pages; |
---|
| 39 | int rc; |
---|
| 40 | |
---|
| 41 | /* Allocate special pages from the end of the RMA. */ |
---|
| 42 | rma_pages = 1 << (dom->realmodearea_log - PAGE_SHIFT); |
---|
| 43 | dom->shared_info_pfn = --rma_pages; |
---|
| 44 | dom->console_pfn = --rma_pages; |
---|
| 45 | dom->xenstore_pfn = --rma_pages; |
---|
| 46 | |
---|
| 47 | /* Gather shadow allocation info for the device tree. */ |
---|
| 48 | rc = xc_shadow_control(dom->guest_xc, dom->guest_domid, |
---|
| 49 | XEN_DOMCTL_SHADOW_OP_GET_ALLOCATION, NULL, 0, |
---|
| 50 | &shadow_mb, 0, NULL); |
---|
| 51 | if (rc < 0 || shadow_mb == 0) { |
---|
| 52 | xc_dom_printf("Couldn't get shadow allocation size or it was 0.\n"); |
---|
| 53 | return rc; |
---|
| 54 | } |
---|
| 55 | |
---|
| 56 | /* Build device tree. */ |
---|
| 57 | rc = make_devtree(&devtree, dom, shadow_mb); |
---|
| 58 | if (rc < 0) { |
---|
| 59 | xc_dom_printf("Failed to create flattened device tree.\n"); |
---|
| 60 | return rc; |
---|
| 61 | } |
---|
| 62 | |
---|
| 63 | /* Find a spot for it. */ |
---|
| 64 | rc = xc_dom_alloc_segment(dom, &dom->devicetree_seg, "devtree", 0, |
---|
| 65 | devtree.bph->totalsize); |
---|
| 66 | if (rc) |
---|
| 67 | goto out; |
---|
| 68 | |
---|
| 69 | /* Copy the device tree into place. */ |
---|
| 70 | guest_devtree = xc_dom_seg_to_ptr(dom, &dom->devicetree_seg); |
---|
| 71 | if (!guest_devtree) { |
---|
| 72 | xc_dom_printf("Couldn't map guest memory for device tree.\n"); |
---|
| 73 | rc = -1; |
---|
| 74 | goto out; |
---|
| 75 | } |
---|
| 76 | memcpy(guest_devtree, devtree.bph, devtree.bph->totalsize); |
---|
| 77 | |
---|
| 78 | out: |
---|
| 79 | free_devtree(&devtree); |
---|
| 80 | return rc; |
---|
| 81 | } |
---|
| 82 | |
---|
| 83 | static int shared_info(struct xc_dom_image *dom, void *ptr) |
---|
| 84 | { |
---|
| 85 | shared_info_t *shared_info = ptr; |
---|
| 86 | |
---|
| 87 | xc_dom_printf("%s: called\n", __FUNCTION__); |
---|
| 88 | |
---|
| 89 | memset(shared_info, 0, sizeof(*shared_info)); |
---|
| 90 | return 0; |
---|
| 91 | } |
---|
| 92 | |
---|
| 93 | static int vcpu(struct xc_dom_image *dom, void *ptr) |
---|
| 94 | { |
---|
| 95 | vcpu_guest_context_t *ctxt = ptr; |
---|
| 96 | |
---|
| 97 | memset(ctxt, 0x55, sizeof(*ctxt)); |
---|
| 98 | ctxt->user_regs.pc = dom->parms.virt_entry; |
---|
| 99 | ctxt->user_regs.msr = 0; |
---|
| 100 | ctxt->user_regs.gprs[1] = 0; /* Linux uses its own stack */ |
---|
| 101 | ctxt->user_regs.gprs[3] = dom->devicetree_seg.pfn << PAGE_SHIFT; |
---|
| 102 | ctxt->user_regs.gprs[4] = dom->kernel_seg.pfn << PAGE_SHIFT; |
---|
| 103 | ctxt->user_regs.gprs[5] = 0; |
---|
| 104 | |
---|
| 105 | /* There is a buggy kernel that does not zero the "local_paca", so |
---|
| 106 | * we must make sure this register is 0 */ |
---|
| 107 | ctxt->user_regs.gprs[13] = 0; |
---|
| 108 | |
---|
| 109 | xc_dom_printf("%s: initial vcpu:\n", __FUNCTION__); |
---|
| 110 | xc_dom_printf(" pc 0x%016"PRIx64", msr 0x%016"PRIx64"\n" |
---|
| 111 | " r1-5 %016"PRIx64" %016"PRIx64" %016"PRIx64" %016"PRIx64 |
---|
| 112 | " %016"PRIx64"\n", |
---|
| 113 | ctxt->user_regs.pc, ctxt->user_regs.msr, |
---|
| 114 | ctxt->user_regs.gprs[1], |
---|
| 115 | ctxt->user_regs.gprs[2], |
---|
| 116 | ctxt->user_regs.gprs[3], |
---|
| 117 | ctxt->user_regs.gprs[4], |
---|
| 118 | ctxt->user_regs.gprs[5]); |
---|
| 119 | |
---|
| 120 | return 0; |
---|
| 121 | } |
---|
| 122 | |
---|
| 123 | /* ------------------------------------------------------------------------ */ |
---|
| 124 | |
---|
| 125 | static struct xc_dom_arch xc_dom_arch = { |
---|
| 126 | .guest_type = "xen-3.0-powerpc64", |
---|
| 127 | .page_shift = PAGE_SHIFT, |
---|
| 128 | .alloc_magic_pages = alloc_magic_pages, |
---|
| 129 | .shared_info = shared_info, |
---|
| 130 | .vcpu = vcpu, |
---|
| 131 | }; |
---|
| 132 | |
---|
| 133 | static void __init register_arch_hooks(void) |
---|
| 134 | { |
---|
| 135 | xc_dom_register_arch_hooks(&xc_dom_arch); |
---|
| 136 | } |
---|
| 137 | |
---|
| 138 | int arch_setup_meminit(struct xc_dom_image *dom) |
---|
| 139 | { |
---|
| 140 | xen_pfn_t *extent_list; |
---|
| 141 | unsigned long total_mem = dom->total_pages << PAGE_SHIFT; |
---|
| 142 | unsigned long rma_bytes; |
---|
| 143 | unsigned long rma_nr_pages; |
---|
| 144 | unsigned long nr_extents; |
---|
| 145 | int rc = 0; |
---|
| 146 | int i; |
---|
| 147 | |
---|
| 148 | /* XXX RMA size is processor-dependent. */ |
---|
| 149 | dom->realmodearea_log = RMA_LOG; |
---|
| 150 | rma_bytes = 1 << dom->realmodearea_log; |
---|
| 151 | rma_nr_pages = rma_bytes >> PAGE_SHIFT; |
---|
| 152 | |
---|
| 153 | xc_dom_printf("dom%u memory: %lu MB RMA, %lu MB additional.\n", |
---|
| 154 | dom->guest_domid, rma_bytes >> 20, (total_mem - rma_bytes) >> 20); |
---|
| 155 | |
---|
| 156 | if (total_mem < rma_bytes) { |
---|
| 157 | xc_dom_printf("Domain must have at least %lu MB\n", rma_bytes >> 20); |
---|
| 158 | return -EINVAL; |
---|
| 159 | } |
---|
| 160 | |
---|
| 161 | /* Allocate the first chunk of memory. */ |
---|
| 162 | rc = xc_alloc_real_mode_area(dom->guest_xc, dom->guest_domid, |
---|
| 163 | dom->realmodearea_log); |
---|
| 164 | if (rc) { |
---|
| 165 | xc_dom_printf("Failed to allocate real mode area.\n"); |
---|
| 166 | return rc; |
---|
| 167 | } |
---|
| 168 | |
---|
| 169 | /* Allocate p2m map. */ |
---|
| 170 | dom->p2m_host = xc_dom_malloc(dom, sizeof(xen_pfn_t) * dom->total_pages); |
---|
| 171 | if (dom->p2m_host == NULL) { |
---|
| 172 | xc_dom_printf("Couldn't allocate p2m map.\n"); |
---|
| 173 | return -ENOMEM; |
---|
| 174 | } |
---|
| 175 | |
---|
| 176 | nr_extents = (dom->total_pages - rma_nr_pages) >> EXTENT_ORDER; |
---|
| 177 | if (nr_extents) { |
---|
| 178 | /* Allocate extent list for populate_physmap() call. */ |
---|
| 179 | extent_list = xc_dom_malloc(dom, sizeof(xen_pfn_t) * nr_extents); |
---|
| 180 | if (extent_list == NULL) { |
---|
| 181 | xc_dom_printf("Couldn't allocate extent list.\n"); |
---|
| 182 | return -ENOMEM; |
---|
| 183 | } |
---|
| 184 | |
---|
| 185 | /* Allocate the remaining (non-RMA) memory. */ |
---|
| 186 | for (i = 0; i < nr_extents; i++) { |
---|
| 187 | /* Use PFNs above the RMA memory we already allocated. */ |
---|
| 188 | extent_list[i] = rma_nr_pages + i * (1<<EXTENT_ORDER); |
---|
| 189 | } |
---|
| 190 | rc = xc_domain_memory_populate_physmap(dom->guest_xc, dom->guest_domid, |
---|
| 191 | nr_extents, EXTENT_ORDER, 0, |
---|
| 192 | extent_list); |
---|
| 193 | if (rc < 0) { |
---|
| 194 | xc_dom_printf("populate_physmap(0x%lx extents order %u) -> 0x%x\n", |
---|
| 195 | nr_extents, EXTENT_ORDER, rc); |
---|
| 196 | return rc; |
---|
| 197 | } |
---|
| 198 | } |
---|
| 199 | |
---|
| 200 | /* Populate the p2m map. */ |
---|
| 201 | rc = xc_get_pfn_list(dom->guest_xc, dom->guest_domid, dom->p2m_host, |
---|
| 202 | dom->total_pages); |
---|
| 203 | if (rc < 0) { |
---|
| 204 | xc_dom_printf("Couldn't get p2m translation.\n"); |
---|
| 205 | return rc; |
---|
| 206 | } |
---|
| 207 | |
---|
| 208 | xc_dom_printf("%s: success\n", __func__); |
---|
| 209 | |
---|
| 210 | return 0; |
---|
| 211 | } |
---|
| 212 | |
---|
| 213 | int arch_setup_bootearly(struct xc_dom_image *dom) |
---|
| 214 | { |
---|
| 215 | xc_dom_printf("%s: doing nothing\n", __FUNCTION__); |
---|
| 216 | return 0; |
---|
| 217 | } |
---|
| 218 | |
---|
| 219 | int arch_setup_bootlate(struct xc_dom_image *dom) |
---|
| 220 | { |
---|
| 221 | unsigned int page_size = XC_DOM_PAGE_SIZE(dom); |
---|
| 222 | shared_info_t *shared_info; |
---|
| 223 | |
---|
| 224 | /* setup shared_info page */ |
---|
| 225 | xc_dom_printf("%s: shared_info: mfn 0x%" PRIpfn "\n", |
---|
| 226 | __FUNCTION__, dom->shared_info_mfn); |
---|
| 227 | shared_info = xc_map_foreign_range(dom->guest_xc, dom->guest_domid, |
---|
| 228 | page_size, |
---|
| 229 | PROT_READ | PROT_WRITE, |
---|
| 230 | dom->shared_info_mfn); |
---|
| 231 | if ( shared_info == NULL ) |
---|
| 232 | return -1; |
---|
| 233 | dom->arch_hooks->shared_info(dom, shared_info); |
---|
| 234 | munmap(shared_info, page_size); |
---|
| 235 | return 0; |
---|
| 236 | } |
---|