📄 fw-emu.c
字号:
/* * PAL & SAL emulation. * * Copyright (C) 1998-2000 Hewlett-Packard Co * Copyright (C) 1998-2000 David Mosberger-Tang <davidm@hpl.hp.com> * * * Copyright (C) 2000-2002 Silicon Graphics, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of version 2 of the GNU General Public License * as published by the Free Software Foundation. * * This program is distributed in the hope that it would be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * * Further, this software is distributed without any warranty that it is * free of the rightful claim of any third person regarding infringement * or the like. Any license provided herein, whether implied or * otherwise, applies only to this software file. Patent licenses, if * any, provided herein do not apply to combinations of this program with * other software, or any other product whatsoever. * * You should have received a copy of the GNU General Public * License along with this program; if not, write the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. * * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, * Mountain View, CA 94043, or: * * http://www.sgi.com * * For further information regarding this notice, see: * * http://oss.sgi.com/projects/GenInfo/NoticeExplan */#include <linux/config.h>#include <asm/efi.h>#include <asm/pal.h>#include <asm/sal.h>#include <asm/sn/sn_sal.h>#include <asm/processor.h>#include <asm/sn/sn_cpuid.h>#ifdef CONFIG_IA64_SGI_SN2#include <asm/sn/sn2/addrs.h>#include <asm/sn/sn2/shub_mmr.h>#endif#include <asm/acpi-ext.h>#include "fpmem.h"#define zzACPI_1_0 1 /* Include ACPI 1.0 tables */#define OEMID "SGI"#ifdef CONFIG_IA64_SGI_SN1#define PRODUCT "SN1"#define PROXIMITY_DOMAIN(nasid) (nasid)#else#define PRODUCT "SN2"#define PROXIMITY_DOMAIN(nasid) (((nasid)>>1) & 255)#endif#define MB (1024*1024UL)#define GB (MB*1024UL)#define BOOT_PARAM_ADDR 0x40000#define MAX(i,j) ((i) > (j) ? (i) : (j))#define MIN(i,j) ((i) < (j) ? (i) : (j))#define ABS(i) ((i) > 0 ? (i) : -(i))#define ALIGN8(p) (((long)(p) +7) & ~7)#define FPROM_BUG() do {while (1);} while (0)#define MAX_SN_NODES 128#define MAX_LSAPICS 512#define MAX_CPUS 512#define MAX_CPUS_NODE 4#define CPUS_PER_NODE 4#define CPUS_PER_FSB 2#define CPUS_PER_FSB_MASK (CPUS_PER_FSB-1)#ifdef ACPI_1_0#define NUM_EFI_DESCS 3#else#define NUM_EFI_DESCS 2#endif#define RSDP_CHECKSUM_LENGTH 20typedef union ia64_nasid_va { struct {#if defined(CONFIG_IA64_SGI_SN1) unsigned long off : 33; /* intra-region offset */ unsigned long nasid : 7; /* NASID */ unsigned long off2 : 21; /* fill */ unsigned long reg : 3; /* region number */#elif defined(CONFIG_IA64_SGI_SN2) unsigned long off : 36; /* intra-region offset */ unsigned long attr : 2; unsigned long nasid : 11; /* NASID */ unsigned long off2 : 12; /* fill */ unsigned long reg : 3; /* region number */#endif } f; unsigned long l; void *p;} ia64_nasid_va;typedef struct { unsigned long pc; unsigned long gp;} func_ptr_t; #define IS_VIRTUAL_MODE() ({struct ia64_psr psr; asm("mov %0=psr" : "=r"(psr)); psr.dt;})#define ADDR_OF(p) (IS_VIRTUAL_MODE() ? ((void*)((long)(p)+PAGE_OFFSET)) : ((void*) (p)))#if defined(CONFIG_IA64_SGI_SN1)#define __fwtab_pa(n,x) ({ia64_nasid_va _v; _v.l = (long) (x); _v.f.nasid = (x) ? (n) : 0; _v.f.reg = 0; _v.l;})#elif defined(CONFIG_IA64_SGI_SN2)#define __fwtab_pa(n,x) ({ia64_nasid_va _v; _v.l = (long) (x); _v.f.nasid = (x) ? (n) : 0; _v.f.reg = 0; _v.f.attr = 3; _v.l;})#endif/* * The following variables are passed thru registersfrom the configuration file and * are set via the _start function. */long base_nasid;long num_cpus;long bsp_entry_pc=0;long num_nodes;long app_entry_pc;int bsp_lid;func_ptr_t ap_entry;extern void pal_emulator(void);static efi_runtime_services_t *efi_runtime_p;static char fw_mem[( sizeof(efi_system_table_t) + sizeof(efi_runtime_services_t) + NUM_EFI_DESCS*sizeof(efi_config_table_t) + sizeof(struct ia64_sal_systab) + sizeof(struct ia64_sal_desc_entry_point) + sizeof(struct ia64_sal_desc_ap_wakeup)#ifdef ACPI_1_0 + sizeof(acpi_rsdp_t) + sizeof(acpi_rsdt_t) + sizeof(acpi_sapic_t) + MAX_LSAPICS*(sizeof(acpi_entry_lsapic_t))#endif + sizeof(acpi20_rsdp_t) + sizeof(acpi_xsdt_t) + sizeof(acpi_slit_t) + MAX_SN_NODES*MAX_SN_NODES+8 + sizeof(acpi_madt_t) + 16*MAX_CPUS + (1+8*MAX_SN_NODES)*(sizeof(efi_memory_desc_t)) + sizeof(acpi_srat_t) + MAX_CPUS*sizeof(srat_cpu_affinity_t) + MAX_SN_NODES*sizeof(srat_memory_affinity_t) + sizeof(ia64_sal_desc_ptc_t) + + MAX_SN_NODES*sizeof(ia64_sal_ptc_domain_info_t) + + MAX_CPUS*sizeof(ia64_sal_ptc_domain_proc_entry_t) + + 1024)] __attribute__ ((aligned (8)));static efi_status_tefi_get_time (efi_time_t *tm, efi_time_cap_t *tc){ if (tm) { memset(tm, 0, sizeof(*tm)); tm->year = 2000; tm->month = 2; tm->day = 13; tm->hour = 10; tm->minute = 11; tm->second = 12; } if (tc) { tc->resolution = 10; tc->accuracy = 12; tc->sets_to_zero = 1; } return EFI_SUCCESS;}static voidefi_reset_system (int reset_type, efi_status_t status, unsigned long data_size, efi_char16_t *data){ while(1); /* Is there a pseudo-op to stop medusa */}static efi_status_tefi_success (void){ return EFI_SUCCESS;}static efi_status_tefi_unimplemented (void){ return EFI_UNSUPPORTED;}#ifdef CONFIG_IA64_SGI_SN2#undef cpu_physical_id#define cpu_physical_id(cpuid) ((ia64_get_lid() >> 16) & 0xffff)voidfprom_send_cpei(void) { long *p, val; long physid; long nasid, slice; physid = cpu_physical_id(0); nasid = cpu_physical_id_to_nasid(physid); slice = cpu_physical_id_to_slice(physid); p = (long*)GLOBAL_MMR_ADDR(nasid, SH_IPI_INT); val = (1UL<<SH_IPI_INT_SEND_SHFT) | (physid<<SH_IPI_INT_PID_SHFT) | ((long)0<<SH_IPI_INT_TYPE_SHFT) | ((long)0x1e<<SH_IPI_INT_IDX_SHFT) | (0x000feeUL<<SH_IPI_INT_BASE_SHFT); *p = val;}#endifstatic longsal_emulator (long index, unsigned long in1, unsigned long in2, unsigned long in3, unsigned long in4, unsigned long in5, unsigned long in6, unsigned long in7){ register long r9 asm ("r9") = 0; register long r10 asm ("r10") = 0; register long r11 asm ("r11") = 0; long status; /* * Don't do a "switch" here since that gives us code that * isn't self-relocatable. */ status = 0; if (index == SAL_FREQ_BASE) { switch (in1) { case SAL_FREQ_BASE_PLATFORM: r9 = 500000000; break; case SAL_FREQ_BASE_INTERVAL_TIMER: /* * Is this supposed to be the cr.itc frequency * or something platform specific? The SAL * doc ain't exactly clear on this... */ r9 = 700000000; break; case SAL_FREQ_BASE_REALTIME_CLOCK: r9 = 50000000; break; default: status = -1; break; } } else if (index == SAL_SET_VECTORS) { if (in1 == SAL_VECTOR_OS_BOOT_RENDEZ) { func_ptr_t *fp; fp = ADDR_OF(&ap_entry); fp->pc = in2; fp->gp = in3; } else if (in1 == SAL_VECTOR_OS_MCA || in1 == SAL_VECTOR_OS_INIT) { } else { status = -1; } ; } else if (index == SAL_GET_STATE_INFO) { ; } else if (index == SAL_GET_STATE_INFO_SIZE) { ; } else if (index == SAL_CLEAR_STATE_INFO) { ; } else if (index == SAL_MC_RENDEZ) { ; } else if (index == SAL_MC_SET_PARAMS) { ; } else if (index == SAL_CACHE_FLUSH) { ; } else if (index == SAL_CACHE_INIT) { ; } else if (index == SAL_UPDATE_PAL) { ;#ifdef CONFIG_IA64_SGI_SN2 } else if (index == SN_SAL_LOG_CE) {#ifdef ajmtestcpei fprom_send_cpei();#else /* ajmtestcpei */ ;#endif /* ajmtestcpei */#endif } else if (index == SN_SAL_PROBE) { r9 = 0UL; if (in2 == 4) { r9 = *(unsigned *)in1; if (r9 == -1) { status = 1; } } else if (in2 == 2) { r9 = *(unsigned short *)in1; if (r9 == -1) { status = 1; } } else if (in2 == 1) { r9 = *(unsigned char *)in1; if (r9 == -1) { status = 1; } } else if (in2 == 8) { r9 = *(unsigned long *)in1; if (r9 == -1) { status = 1; } } else { status = 2; } } else if (index == SN_SAL_GET_KLCONFIG_ADDR) { r9 = 0x30000; } else if (index == SN_SAL_CONSOLE_PUTC) { status = -1; } else if (index == SN_SAL_CONSOLE_GETC) { status = -1; } else if (index == SN_SAL_CONSOLE_POLL) { status = -1; } else { status = -1; } asm volatile ("" :: "r"(r9), "r"(r10), "r"(r11)); return status;}/* * This is here to work around a bug in egcs-1.1.1b that causes the * compiler to crash (seems like a bug in the new alias analysis code. */void *id (long addr){ return (void *) addr;}/* * Fix the addresses in a function pointer by adding base node address * to pc & gp. */voidfix_function_pointer(void *fp){ func_ptr_t *_fp; _fp = fp; _fp->pc = __fwtab_pa(base_nasid, _fp->pc); _fp->gp = __fwtab_pa(base_nasid, _fp->gp);}voidfix_virt_function_pointer(void **fptr){ func_ptr_t *fp; long *p; p = (long*)fptr; fp = *fptr; fp->pc = fp->pc | PAGE_OFFSET; fp->gp = fp->gp | PAGE_OFFSET; *p |= PAGE_OFFSET;}intefi_set_virtual_address_map(void){ efi_runtime_services_t *runtime; runtime = efi_runtime_p; fix_virt_function_pointer((void**)&runtime->get_time); fix_virt_function_pointer((void**)&runtime->set_time); fix_virt_function_pointer((void**)&runtime->get_wakeup_time); fix_virt_function_pointer((void**)&runtime->set_wakeup_time); fix_virt_function_pointer((void**)&runtime->set_virtual_address_map); fix_virt_function_pointer((void**)&runtime->get_variable); fix_virt_function_pointer((void**)&runtime->get_next_variable); fix_virt_function_pointer((void**)&runtime->set_variable); fix_virt_function_pointer((void**)&runtime->get_next_high_mono_count); fix_virt_function_pointer((void**)&runtime->reset_system); return EFI_SUCCESS;;}voidacpi_table_init(acpi_desc_table_hdr_t *p, char *sig, int siglen, int revision, int oem_revision){ memcpy(p->signature, sig, siglen); memcpy(p->oem_id, OEMID, 6); memcpy(p->oem_table_id, sig, 4); memcpy(p->oem_table_id+4, PRODUCT, 4); p->revision = revision; p->oem_revision = (revision<<16) + oem_revision; p->creator_id = 1; p->creator_revision = 1;}voidacpi_checksum(acpi_desc_table_hdr_t *p, int length){
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -