/* * GRUB -- GRand Unified Bootloader * Copyright (C) 2009 Free Software Foundation, Inc. * * GRUB is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRUB 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GRUB. If not, see . */ #include #include #include #include #include #include #include #include typedef grub_addr_t grub_xen_reg_t; struct grub_relocator_xen_paging_area { grub_xen_reg_t start; grub_xen_reg_t size; } GRUB_PACKED; extern grub_uint8_t grub_relocator_xen_start; extern grub_uint8_t grub_relocator_xen_end; extern grub_uint8_t grub_relocator_xen_remap_start; extern grub_uint8_t grub_relocator_xen_remap_end; extern grub_xen_reg_t grub_relocator_xen_stack; extern grub_xen_reg_t grub_relocator_xen_start_info; extern grub_xen_reg_t grub_relocator_xen_entry_point; extern grub_xen_reg_t grub_relocator_xen_remapper_virt; extern grub_xen_reg_t grub_relocator_xen_remapper_virt2; extern grub_xen_reg_t grub_relocator_xen_remapper_map; extern grub_xen_reg_t grub_relocator_xen_mfn_list; extern struct grub_relocator_xen_paging_area grub_relocator_xen_paging_areas[XEN_MAX_MAPPINGS]; extern grub_xen_reg_t grub_relocator_xen_remap_continue; #ifdef __i386__ extern grub_xen_reg_t grub_relocator_xen_mmu_op_addr; extern grub_xen_reg_t grub_relocator_xen_paging_areas_addr; extern grub_xen_reg_t grub_relocator_xen_remapper_map_high; #endif extern mmuext_op_t grub_relocator_xen_mmu_op[3]; #define RELOCATOR_SIZEOF(x) (&grub_relocator##x##_end - &grub_relocator##x##_start) grub_err_t grub_relocator_xen_boot (struct grub_relocator *rel, struct grub_relocator_xen_state state, grub_uint64_t remapper_pfn, grub_addr_t remapper_virt, grub_uint64_t trampoline_pfn, grub_addr_t trampoline_virt) { grub_err_t err; void *relst; int i; grub_relocator_chunk_t ch, ch_tramp; grub_xen_mfn_t *mfn_list = (grub_xen_mfn_t *) grub_xen_start_page_addr->mfn_list; err = grub_relocator_alloc_chunk_addr (rel, &ch, remapper_pfn << 12, RELOCATOR_SIZEOF (_xen_remap)); if (err) return err; err = grub_relocator_alloc_chunk_addr (rel, &ch_tramp, trampoline_pfn << 12, RELOCATOR_SIZEOF (_xen)); if (err) return err; grub_relocator_xen_stack = state.stack; grub_relocator_xen_start_info = state.start_info; grub_relocator_xen_entry_point = state.entry_point; for (i = 0; i < XEN_MAX_MAPPINGS; i++) { grub_relocator_xen_paging_areas[i].start = state.paging_start[i]; grub_relocator_xen_paging_areas[i].size = state.paging_size[i]; } grub_relocator_xen_remapper_virt = remapper_virt; grub_relocator_xen_remapper_virt2 = remapper_virt; grub_relocator_xen_remap_continue = trampoline_virt; grub_relocator_xen_remapper_map = (mfn_list[remapper_pfn] << 12) | 5; #ifdef __i386__ grub_relocator_xen_remapper_map_high = (mfn_list[remapper_pfn] >> 20); grub_relocator_xen_mmu_op_addr = (char *) &grub_relocator_xen_mmu_op - (char *) &grub_relocator_xen_remap_start + remapper_virt; grub_relocator_xen_paging_areas_addr = (char *) &grub_relocator_xen_paging_areas - (char *) &grub_relocator_xen_remap_start + remapper_virt; #endif grub_relocator_xen_mfn_list = state.mfn_list; grub_memset (grub_relocator_xen_mmu_op, 0, sizeof (grub_relocator_xen_mmu_op)); #ifdef __i386__ grub_relocator_xen_mmu_op[0].cmd = MMUEXT_PIN_L3_TABLE; #else grub_relocator_xen_mmu_op[0].cmd = MMUEXT_PIN_L4_TABLE; #endif grub_relocator_xen_mmu_op[0].arg1.mfn = mfn_list[state.paging_start[0]]; grub_relocator_xen_mmu_op[1].cmd = MMUEXT_NEW_BASEPTR; grub_relocator_xen_mmu_op[1].arg1.mfn = mfn_list[state.paging_start[0]]; grub_relocator_xen_mmu_op[2].cmd = MMUEXT_UNPIN_TABLE; grub_relocator_xen_mmu_op[2].arg1.mfn = mfn_list[grub_xen_start_page_addr->pt_base >> 12]; grub_memmove (get_virtual_current_address (ch), &grub_relocator_xen_remap_start, RELOCATOR_SIZEOF (_xen_remap)); grub_memmove (get_virtual_current_address (ch_tramp), &grub_relocator_xen_start, RELOCATOR_SIZEOF (_xen)); err = grub_relocator_prepare_relocs (rel, get_physical_target_address (ch), &relst, NULL); if (err) return err; ((void (*)(void)) relst) (); /* Not reached. */ return GRUB_ERR_NONE; }