| /* |
| * 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 <http://www.gnu.org/licenses/>. |
| */ |
| |
| #include <grub/mm.h> |
| #include <grub/misc.h> |
| |
| #include <grub/types.h> |
| #include <grub/err.h> |
| #include <grub/term.h> |
| #include <grub/xen.h> |
| |
| #include <grub/xen/relocator.h> |
| #include <grub/relocator_private.h> |
| |
| 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; |
| } |