diff options
Diffstat (limited to 'purgatory/arch/ia64/purgatory-ia64.c')
-rw-r--r-- | purgatory/arch/ia64/purgatory-ia64.c | 188 |
1 files changed, 172 insertions, 16 deletions
diff --git a/purgatory/arch/ia64/purgatory-ia64.c b/purgatory/arch/ia64/purgatory-ia64.c index 8d2008c..c0115c0 100644 --- a/purgatory/arch/ia64/purgatory-ia64.c +++ b/purgatory/arch/ia64/purgatory-ia64.c @@ -1,9 +1,47 @@ +/* + * 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 <purgatory.h> #include <stdint.h> #include <string.h> #include "purgatory-ia64.h" -#define PAGE_OFFSET 0xe000000000000000 +#define PAGE_OFFSET 0xe000000000000000UL + +#define EFI_PAGE_SHIFT 12 +#define EFI_PAGE_SIZE (1UL<<EFI_PAGE_SHIFT) +#define EFI_PAGE_ALIGN(x) ((x + EFI_PAGE_SIZE - 1)&~(EFI_PAGE_SIZE-1)) +/* Memory types: */ +#define EFI_RESERVED_TYPE 0 +#define EFI_LOADER_CODE 1 +#define EFI_LOADER_DATA 2 +#define EFI_BOOT_SERVICES_CODE 3 +#define EFI_BOOT_SERVICES_DATA 4 +#define EFI_RUNTIME_SERVICES_CODE 5 +#define EFI_RUNTIME_SERVICES_DATA 6 +#define EFI_CONVENTIONAL_MEMORY 7 +#define EFI_UNUSABLE_MEMORY 8 +#define EFI_ACPI_RECLAIM_MEMORY 9 +#define EFI_ACPI_MEMORY_NVS 10 +#define EFI_MEMORY_MAPPED_IO 11 +#define EFI_MEMORY_MAPPED_IO_PORT_SPACE 12 +#define EFI_PAL_CODE 13 +#define EFI_MAX_MEMORY_TYPE 14 typedef struct { uint64_t signature; @@ -63,53 +101,171 @@ struct ia64_boot_param { uint64_t initrd_size; }; -void setup_arch(void) +typedef struct { + uint32_t type; + uint32_t pad; + uint64_t phys_addr; + uint64_t virt_addr; + uint64_t num_pages; + uint64_t attribute; +} efi_memory_desc_t; + +struct loaded_segment { + unsigned long start; + unsigned long end; + unsigned long reserved; +}; + +struct kexec_boot_params { + uint64_t ramdisk_base; + uint64_t ramdisk_size; + uint64_t command_line; + uint64_t command_line_len; + uint64_t efi_memmap_base; + uint64_t efi_memmap_size; + struct loaded_segment *loaded_segments; + unsigned long loaded_segments_num; +}; + +void +setup_arch(void) { - /* Nothing for now */ + reset_vga(); } + inline unsigned long PA(unsigned long addr) { return addr - PAGE_OFFSET; } -void flush_icache_range(char *start, unsigned long len) +void +patch_efi_memmap(struct kexec_boot_params *params, + struct ia64_boot_param *boot_param) +{ + void *dest = (void *)params->efi_memmap_base; + void *src = (void *)boot_param->efi_memmap; + unsigned long len = boot_param->efi_memmap_size; + unsigned long memdesc_size = boot_param->efi_memdesc_size; + uint64_t orig_type; + efi_memory_desc_t *md1, *md2; + void *p1, *p2, *src_end = src + len; + int i; + for (p1 = src, p2 = dest; p1 < src_end; + p1 += memdesc_size, p2 += memdesc_size) { + unsigned long mstart, mend; + md1 = p1; + md2 = p2; + if (md1->num_pages == 0) + continue; + mstart = md1->phys_addr; + mend = md1->phys_addr + (md1->num_pages + << EFI_PAGE_SHIFT); + switch (md1->type) { + case EFI_LOADER_DATA: + *md2 = *md1; + md2->type = EFI_CONVENTIONAL_MEMORY; + break; + default: + *md2 = *md1; + } + // segments are already sorted and aligned to 4K + orig_type = md2->type; + for (i = 0; i < params->loaded_segments_num; i++) { + struct loaded_segment *seg; + seg = ¶ms->loaded_segments[i]; + if (seg->start >= mstart && seg->start < mend) { + unsigned long start_pages, mid_pages, end_pages; + if (seg->end > mend) { + p1 += memdesc_size; + for(; p1 < src_end; + p1 += memdesc_size) { + md1 = p1; + /* TODO check contig and attribute here */ + mend = md1->phys_addr + + (md1->num_pages << EFI_PAGE_SHIFT); + if (seg->end < mend) + break; + } + } + 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) { + md2->num_pages = start_pages; + p2 += memdesc_size; + md2 = p2; + *md2 = *md1; + } + md2->phys_addr = seg->start; + md2->num_pages = mid_pages; + md2->type = seg->reserved ? + EFI_UNUSABLE_MEMORY:EFI_LOADER_DATA; + if (end_pages) { + p2 += memdesc_size; + md2 = p2; + *md2 = *md1; + md2->phys_addr = seg->end; + md2->num_pages = end_pages; + md2->type = orig_type; + mstart = seg->end; + } else + break; + } + } + } + + boot_param->efi_memmap_size = p2 - dest; +} + +void +flush_icache_range(char *start, unsigned long len) { unsigned long i; for (i = 0;i < len; i += 32) - asm volatile("fc.i %0"::"r"(start+i):"memory"); + 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, - uint64_t command_line, uint64_t command_line_len, - uint64_t ramdisk_base, uint64_t ramdisk_size) + +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; // patch efi_runtime->set_virtual_address_map to a // dummy function len = __dummy_efi_function_end - __dummy_efi_function; - memcpy((char *)command_line + command_line_len, __dummy_efi_function, - len); + memcpy(command_line + command_line_len, + __dummy_efi_function, len); systab = (efi_system_table_t *)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)((char *)command_line + command_line_len); - flush_icache_range((char *)command_line+command_line_len, len); + *(set_virtual_address_map) = + (unsigned long)(command_line + command_line_len); + flush_icache_range(command_line + command_line_len, len); + + patch_efi_memmap(params, boot_param); + + boot_param->efi_memmap = params->efi_memmap_base; - boot_param->command_line = command_line; + boot_param->command_line = params->command_line; boot_param->console_info.orig_x = 0; boot_param->console_info.orig_y = 0; - boot_param->initrd_start = ramdisk_base; - boot_param->initrd_size = ramdisk_size; + boot_param->initrd_start = params->ramdisk_base; + boot_param->initrd_size = params->ramdisk_size; } /* This function can be used to execute after the SHA256 verification. */ |