| 1 | /* |
|---|
| 2 | * drivers/xen/core/machine_kexec.c |
|---|
| 3 | * handle transition of Linux booting another kernel |
|---|
| 4 | */ |
|---|
| 5 | |
|---|
| 6 | #include <linux/kexec.h> |
|---|
| 7 | #include <xen/interface/kexec.h> |
|---|
| 8 | #include <linux/mm.h> |
|---|
| 9 | #include <linux/bootmem.h> |
|---|
| 10 | |
|---|
| 11 | extern void machine_kexec_setup_load_arg(xen_kexec_image_t *xki, |
|---|
| 12 | struct kimage *image); |
|---|
| 13 | |
|---|
| 14 | int xen_max_nr_phys_cpus; |
|---|
| 15 | struct resource xen_hypervisor_res; |
|---|
| 16 | struct resource *xen_phys_cpus; |
|---|
| 17 | |
|---|
| 18 | void xen_machine_kexec_setup_resources(void) |
|---|
| 19 | { |
|---|
| 20 | xen_kexec_range_t range; |
|---|
| 21 | struct resource *res; |
|---|
| 22 | int k = 0; |
|---|
| 23 | |
|---|
| 24 | if (!is_initial_xendomain()) |
|---|
| 25 | return; |
|---|
| 26 | |
|---|
| 27 | /* determine maximum number of physical cpus */ |
|---|
| 28 | |
|---|
| 29 | while (1) { |
|---|
| 30 | memset(&range, 0, sizeof(range)); |
|---|
| 31 | range.range = KEXEC_RANGE_MA_CPU; |
|---|
| 32 | range.nr = k; |
|---|
| 33 | |
|---|
| 34 | if(HYPERVISOR_kexec_op(KEXEC_CMD_kexec_get_range, &range)) |
|---|
| 35 | break; |
|---|
| 36 | |
|---|
| 37 | k++; |
|---|
| 38 | } |
|---|
| 39 | |
|---|
| 40 | if (k == 0) |
|---|
| 41 | return; |
|---|
| 42 | |
|---|
| 43 | xen_max_nr_phys_cpus = k; |
|---|
| 44 | |
|---|
| 45 | /* allocate xen_phys_cpus */ |
|---|
| 46 | |
|---|
| 47 | xen_phys_cpus = alloc_bootmem_low(k * sizeof(struct resource)); |
|---|
| 48 | BUG_ON(xen_phys_cpus == NULL); |
|---|
| 49 | |
|---|
| 50 | /* fill in xen_phys_cpus with per-cpu crash note information */ |
|---|
| 51 | |
|---|
| 52 | for (k = 0; k < xen_max_nr_phys_cpus; k++) { |
|---|
| 53 | memset(&range, 0, sizeof(range)); |
|---|
| 54 | range.range = KEXEC_RANGE_MA_CPU; |
|---|
| 55 | range.nr = k; |
|---|
| 56 | |
|---|
| 57 | if (HYPERVISOR_kexec_op(KEXEC_CMD_kexec_get_range, &range)) |
|---|
| 58 | goto err; |
|---|
| 59 | |
|---|
| 60 | res = xen_phys_cpus + k; |
|---|
| 61 | |
|---|
| 62 | memset(res, 0, sizeof(*res)); |
|---|
| 63 | res->name = "Crash note"; |
|---|
| 64 | res->start = range.start; |
|---|
| 65 | res->end = range.start + range.size - 1; |
|---|
| 66 | res->flags = IORESOURCE_BUSY | IORESOURCE_MEM; |
|---|
| 67 | } |
|---|
| 68 | |
|---|
| 69 | /* fill in xen_hypervisor_res with hypervisor machine address range */ |
|---|
| 70 | |
|---|
| 71 | memset(&range, 0, sizeof(range)); |
|---|
| 72 | range.range = KEXEC_RANGE_MA_XEN; |
|---|
| 73 | |
|---|
| 74 | if (HYPERVISOR_kexec_op(KEXEC_CMD_kexec_get_range, &range)) |
|---|
| 75 | goto err; |
|---|
| 76 | |
|---|
| 77 | xen_hypervisor_res.name = "Hypervisor code and data"; |
|---|
| 78 | xen_hypervisor_res.start = range.start; |
|---|
| 79 | xen_hypervisor_res.end = range.start + range.size - 1; |
|---|
| 80 | xen_hypervisor_res.flags = IORESOURCE_BUSY | IORESOURCE_MEM; |
|---|
| 81 | |
|---|
| 82 | /* fill in crashk_res if range is reserved by hypervisor */ |
|---|
| 83 | |
|---|
| 84 | memset(&range, 0, sizeof(range)); |
|---|
| 85 | range.range = KEXEC_RANGE_MA_CRASH; |
|---|
| 86 | |
|---|
| 87 | if (HYPERVISOR_kexec_op(KEXEC_CMD_kexec_get_range, &range)) |
|---|
| 88 | return; |
|---|
| 89 | |
|---|
| 90 | if (range.size) { |
|---|
| 91 | crashk_res.start = range.start; |
|---|
| 92 | crashk_res.end = range.start + range.size - 1; |
|---|
| 93 | } |
|---|
| 94 | |
|---|
| 95 | return; |
|---|
| 96 | |
|---|
| 97 | err: |
|---|
| 98 | /* |
|---|
| 99 | * It isn't possible to free xen_phys_cpus this early in the |
|---|
| 100 | * boot. Failure at this stage is unexpected and the amount of |
|---|
| 101 | * memory is small therefore we tolerate the potential leak. |
|---|
| 102 | */ |
|---|
| 103 | xen_max_nr_phys_cpus = 0; |
|---|
| 104 | return; |
|---|
| 105 | } |
|---|
| 106 | |
|---|
| 107 | void xen_machine_kexec_register_resources(struct resource *res) |
|---|
| 108 | { |
|---|
| 109 | int k; |
|---|
| 110 | |
|---|
| 111 | request_resource(res, &xen_hypervisor_res); |
|---|
| 112 | |
|---|
| 113 | for (k = 0; k < xen_max_nr_phys_cpus; k++) |
|---|
| 114 | request_resource(&xen_hypervisor_res, xen_phys_cpus + k); |
|---|
| 115 | |
|---|
| 116 | } |
|---|
| 117 | |
|---|
| 118 | static void setup_load_arg(xen_kexec_image_t *xki, struct kimage *image) |
|---|
| 119 | { |
|---|
| 120 | machine_kexec_setup_load_arg(xki, image); |
|---|
| 121 | |
|---|
| 122 | xki->indirection_page = image->head; |
|---|
| 123 | xki->start_address = image->start; |
|---|
| 124 | } |
|---|
| 125 | |
|---|
| 126 | /* |
|---|
| 127 | * Load the image into xen so xen can kdump itself |
|---|
| 128 | * This might have been done in prepare, but prepare |
|---|
| 129 | * is currently called too early. It might make sense |
|---|
| 130 | * to move prepare, but for now, just add an extra hook. |
|---|
| 131 | */ |
|---|
| 132 | int xen_machine_kexec_load(struct kimage *image) |
|---|
| 133 | { |
|---|
| 134 | xen_kexec_load_t xkl; |
|---|
| 135 | |
|---|
| 136 | memset(&xkl, 0, sizeof(xkl)); |
|---|
| 137 | xkl.type = image->type; |
|---|
| 138 | setup_load_arg(&xkl.image, image); |
|---|
| 139 | return HYPERVISOR_kexec_op(KEXEC_CMD_kexec_load, &xkl); |
|---|
| 140 | } |
|---|
| 141 | |
|---|
| 142 | /* |
|---|
| 143 | * Unload the image that was stored by machine_kexec_load() |
|---|
| 144 | * This might have been done in machine_kexec_cleanup() but it |
|---|
| 145 | * is called too late, and its possible xen could try and kdump |
|---|
| 146 | * using resources that have been freed. |
|---|
| 147 | */ |
|---|
| 148 | void xen_machine_kexec_unload(struct kimage *image) |
|---|
| 149 | { |
|---|
| 150 | xen_kexec_load_t xkl; |
|---|
| 151 | |
|---|
| 152 | memset(&xkl, 0, sizeof(xkl)); |
|---|
| 153 | xkl.type = image->type; |
|---|
| 154 | HYPERVISOR_kexec_op(KEXEC_CMD_kexec_unload, &xkl); |
|---|
| 155 | } |
|---|
| 156 | |
|---|
| 157 | /* |
|---|
| 158 | * Do not allocate memory (or fail in any way) in machine_kexec(). |
|---|
| 159 | * We are past the point of no return, committed to rebooting now. |
|---|
| 160 | * |
|---|
| 161 | * This has the hypervisor move to the prefered reboot CPU, |
|---|
| 162 | * stop all CPUs and kexec. That is it combines machine_shutdown() |
|---|
| 163 | * and machine_kexec() in Linux kexec terms. |
|---|
| 164 | */ |
|---|
| 165 | NORET_TYPE void machine_kexec(struct kimage *image) |
|---|
| 166 | { |
|---|
| 167 | xen_kexec_exec_t xke; |
|---|
| 168 | |
|---|
| 169 | memset(&xke, 0, sizeof(xke)); |
|---|
| 170 | xke.type = image->type; |
|---|
| 171 | HYPERVISOR_kexec_op(KEXEC_CMD_kexec, &xke); |
|---|
| 172 | panic("KEXEC_CMD_kexec hypercall should not return\n"); |
|---|
| 173 | } |
|---|
| 174 | |
|---|
| 175 | void machine_shutdown(void) |
|---|
| 176 | { |
|---|
| 177 | /* do nothing */ |
|---|
| 178 | } |
|---|
| 179 | |
|---|
| 180 | |
|---|
| 181 | /* |
|---|
| 182 | * Local variables: |
|---|
| 183 | * c-file-style: "linux" |
|---|
| 184 | * indent-tabs-mode: t |
|---|
| 185 | * c-indent-level: 8 |
|---|
| 186 | * c-basic-offset: 8 |
|---|
| 187 | * tab-width: 8 |
|---|
| 188 | * End: |
|---|
| 189 | */ |
|---|