From eba0cfa6b0bef4f2e73c8630a7efa3944df8b0f8 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Fri, 19 Apr 2024 04:56:35 +0200 Subject: Adding upstream version 1:2.0.27. Signed-off-by: Daniel Baumann --- purgatory/arch/ia64/purgatory-ia64.c | 307 +++++++++++++++++++++++++++++++++++ 1 file changed, 307 insertions(+) create mode 100644 purgatory/arch/ia64/purgatory-ia64.c (limited to 'purgatory/arch/ia64/purgatory-ia64.c') diff --git a/purgatory/arch/ia64/purgatory-ia64.c b/purgatory/arch/ia64/purgatory-ia64.c new file mode 100644 index 0000000..e138e9c --- /dev/null +++ b/purgatory/arch/ia64/purgatory-ia64.c @@ -0,0 +1,307 @@ +/* + * purgatory: setup code + * + * Copyright (C) 2005-2006 Zou Nan hai (nanhai.zou@intel.com) + * + * This program 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 (version 2 of the License). + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#include +#include +#include +#include "purgatory-ia64.h" + +#define PAGE_OFFSET 0xe000000000000000UL + +#define EFI_PAGE_SHIFT 12 +#define EFI_PAGE_SIZE (1UL<efi_memmap_base; + void *src = (void *)boot_param->efi_memmap; + uint64_t orig_type; + efi_memory_desc_t *src_md, *dst_md; + void *src_end = src + boot_param->efi_memmap_size; + unsigned long i; + for (; src < src_end; src += boot_param->efi_memdesc_size, + dest += boot_param->efi_memdesc_size) { + unsigned long mstart, mend; + src_md = src; + dst_md = dest; + if (src_md->num_pages == 0) + continue; + mstart = src_md->phys_addr; + mend = src_md->phys_addr + + (src_md->num_pages << EFI_PAGE_SHIFT); + *dst_md = *src_md; + if (src_md->type == EFI_LOADER_DATA) + dst_md->type = EFI_CONVENTIONAL_MEMORY; + /* segments are already sorted and aligned to 4K */ + orig_type = dst_md->type; + for (i = 0; i < params->loaded_segments_num; i++) { + struct loaded_segment *seg; + unsigned long start_pages, mid_pages, end_pages; + + seg = ¶ms->loaded_segments[i]; + if (seg->start < mstart || seg->start >= mend) + continue; + + while (seg->end > mend && src < src_end) { + src += boot_param->efi_memdesc_size; + src_md = src; + /* TODO check contig and attribute here */ + mend = src_md->phys_addr + + (src_md->num_pages << EFI_PAGE_SHIFT); + } + if (seg->end < mend && src < src_end) { + void *src_next; + efi_memory_desc_t *src_next_md; + src_next = src + boot_param->efi_memdesc_size; + src_next_md = src_next; + if (src_next_md->type == + EFI_CONVENTIONAL_MEMORY) { + /* TODO check contig and attribute */ + src += boot_param->efi_memdesc_size; + src_md = src; + mend = src_md->phys_addr + + (src_md->num_pages << + EFI_PAGE_SHIFT); + } + + } + start_pages = (seg->start - mstart) >> EFI_PAGE_SHIFT; + mid_pages = (seg->end - seg->start) >> EFI_PAGE_SHIFT; + end_pages = (mend - seg->end) >> EFI_PAGE_SHIFT; + if (start_pages) { + dst_md->num_pages = start_pages; + dest += boot_param->efi_memdesc_size; + dst_md = dest; + *dst_md = *src_md; + } + dst_md->phys_addr = seg->start; + dst_md->num_pages = mid_pages; + dst_md->type = EFI_LOADER_DATA; + if (!end_pages) + break; + dest += boot_param->efi_memdesc_size; + dst_md = dest; + *dst_md = *src_md; + dst_md->phys_addr = seg->end; + dst_md->num_pages = end_pages; + dst_md->type = orig_type; + mstart = seg->end; + } + } + + boot_param->efi_memmap_size = dest - (void *)params->efi_memmap_base; +} + +void +flush_icache_range(char *start, unsigned long len) +{ + unsigned long i, addr; + addr = (unsigned long)start & ~31UL; + len += (unsigned long)start - addr; + for (i = 0;i < len; i += 32) + asm volatile("fc.i %0"::"r"(start + i):"memory"); + asm volatile (";;sync.i;;":::"memory"); + asm volatile ("srlz.i":::"memory"); +} + +extern char __dummy_efi_function[], __dummy_efi_function_end[]; + + +void +ia64_env_setup(struct ia64_boot_param *boot_param, + struct kexec_boot_params *params) +{ + unsigned long len; + efi_system_table_t *systab; + efi_runtime_services_t *runtime; + unsigned long *set_virtual_address_map; + char *command_line = (char *)params->command_line; + uint64_t command_line_len = params->command_line_len; + struct ia64_boot_param *new_boot_param = + (struct ia64_boot_param *) params->boot_param_base; + memcpy(new_boot_param, boot_param, 4096); + + /* + * patch efi_runtime->set_virtual_address_map to a dummy function + * + * The EFI specification mandates that set_virtual_address_map only + * takes effect the first time that it is called, and that + * subsequent calls will return error. By replacing it with a + * dummy function the new OS can think it is calling it again + * without either the OS or any buggy EFI implementations getting + * upset. + * + * Note: as the EFI specification says that set_virtual_address_map + * will only take affect the first time it is called, the mapping + * can't be updated, and thus mapping of the old and new OS really + * needs to be the same. + */ + len = __dummy_efi_function_end - __dummy_efi_function; + memcpy(command_line + command_line_len, + __dummy_efi_function, len); + systab = (efi_system_table_t *)new_boot_param->efi_systab; + runtime = (efi_runtime_services_t *)PA(systab->runtime); + set_virtual_address_map = + (unsigned long *)PA(runtime->set_virtual_address_map); + *(set_virtual_address_map) = + (unsigned long)(command_line + command_line_len); + flush_icache_range(command_line + command_line_len, len); + + patch_efi_memmap(params, new_boot_param); + + new_boot_param->efi_memmap = params->efi_memmap_base; + new_boot_param->command_line = params->command_line; + new_boot_param->console_info.orig_x = 0; + new_boot_param->console_info.orig_y = 0; + new_boot_param->initrd_start = params->ramdisk_base; + new_boot_param->initrd_size = params->ramdisk_size; + new_boot_param->vmcode_start = params->vmcode_base; + new_boot_param->vmcode_size = params->vmcode_size; +} + +/* This function can be used to execute after the SHA256 verification. */ +void post_verification_setup_arch(void) +{ + /* Nothing for now */ +} -- cgit v1.2.3