efi.c revision 965e7c8affeca27f7e5de75c97954e74d3b8052d
11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 21da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Extensible Firmware Interface 31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 47d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis * Based on Extensible Firmware Interface Specification version 0.9 57d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis * April 30, 1999 61da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 71da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Copyright (C) 1999 VA Linux Systems 81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Copyright (C) 1999 Walt Drummond <drummond@valinux.com> 91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Copyright (C) 1999-2003 Hewlett-Packard Co. 101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * David Mosberger-Tang <davidm@hpl.hp.com> 111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Stephane Eranian <eranian@hpl.hp.com> 1232e62c636a728cb39c0b3bd191286f2ca65d4028Bjorn Helgaas * (c) Copyright 2006 Hewlett-Packard Development Company, L.P. 1332e62c636a728cb39c0b3bd191286f2ca65d4028Bjorn Helgaas * Bjorn Helgaas <bjorn.helgaas@hp.com> 141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * All EFI Runtime Services are not implemented yet as EFI only 161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * supports physical mode addressing on SoftSDV. This is to be fixed 171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * in a future version. --drummond 1999-07-20 181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Implemented EFI runtime services and virtual mode calls. --davidm 201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Goutham Rao: <goutham.rao@intel.com> 221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Skip non-WB memory and ignore empty memory ranges. 231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/module.h> 25f4a570997e71b892805a1e71303d09c327af135fHorms#include <linux/bootmem.h> 261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/kernel.h> 271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/init.h> 281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/types.h> 291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/time.h> 301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/efi.h> 31a79561134f38de12dce14ed72138f38e55ef53fcZou Nan hai#include <linux/kexec.h> 32ed7ed365172e27b0efe9d43cc962723c7193e34eMel Gorman#include <linux/mm.h> 331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/io.h> 351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/kregs.h> 361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/meminit.h> 371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/pgtable.h> 381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/processor.h> 391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/mca.h> 401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define EFI_DEBUG 0 421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsextern efi_status_t efi_call_phys (void *, ...); 441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct efi efi; 461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsEXPORT_SYMBOL(efi); 471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic efi_runtime_services_t *runtime; 48a79561134f38de12dce14ed72138f38e55ef53fcZou Nan haistatic unsigned long mem_limit = ~0UL, max_addr = ~0UL, min_addr = 0UL; 491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define efi_call_virt(f, args...) (*(f))(args) 511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 527d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis#define STUB_GET_TIME(prefix, adjust_arg) \ 537d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffisstatic efi_status_t \ 547d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffisprefix##_get_time (efi_time_t *tm, efi_time_cap_t *tc) \ 557d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis{ \ 567d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis struct ia64_fpreg fr[6]; \ 577d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis efi_time_cap_t *atc = NULL; \ 587d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis efi_status_t ret; \ 597d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis \ 607d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis if (tc) \ 617d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis atc = adjust_arg(tc); \ 627d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis ia64_save_scratch_fpregs(fr); \ 637d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis ret = efi_call_##prefix((efi_get_time_t *) __va(runtime->get_time), \ 647d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis adjust_arg(tm), atc); \ 657d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis ia64_load_scratch_fpregs(fr); \ 667d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis return ret; \ 671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 697d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis#define STUB_SET_TIME(prefix, adjust_arg) \ 707d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffisstatic efi_status_t \ 717d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffisprefix##_set_time (efi_time_t *tm) \ 727d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis{ \ 737d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis struct ia64_fpreg fr[6]; \ 747d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis efi_status_t ret; \ 757d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis \ 767d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis ia64_save_scratch_fpregs(fr); \ 777d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis ret = efi_call_##prefix((efi_set_time_t *) __va(runtime->set_time), \ 787d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis adjust_arg(tm)); \ 797d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis ia64_load_scratch_fpregs(fr); \ 807d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis return ret; \ 811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 837d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis#define STUB_GET_WAKEUP_TIME(prefix, adjust_arg) \ 847d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffisstatic efi_status_t \ 857d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffisprefix##_get_wakeup_time (efi_bool_t *enabled, efi_bool_t *pending, \ 867d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis efi_time_t *tm) \ 877d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis{ \ 887d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis struct ia64_fpreg fr[6]; \ 897d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis efi_status_t ret; \ 907d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis \ 917d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis ia64_save_scratch_fpregs(fr); \ 927d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis ret = efi_call_##prefix( \ 937d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis (efi_get_wakeup_time_t *) __va(runtime->get_wakeup_time), \ 947d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis adjust_arg(enabled), adjust_arg(pending), adjust_arg(tm)); \ 957d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis ia64_load_scratch_fpregs(fr); \ 967d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis return ret; \ 971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 997d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis#define STUB_SET_WAKEUP_TIME(prefix, adjust_arg) \ 1007d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffisstatic efi_status_t \ 1017d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffisprefix##_set_wakeup_time (efi_bool_t enabled, efi_time_t *tm) \ 1027d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis{ \ 1037d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis struct ia64_fpreg fr[6]; \ 1047d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis efi_time_t *atm = NULL; \ 1057d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis efi_status_t ret; \ 1067d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis \ 1077d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis if (tm) \ 1087d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis atm = adjust_arg(tm); \ 1097d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis ia64_save_scratch_fpregs(fr); \ 1107d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis ret = efi_call_##prefix( \ 1117d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis (efi_set_wakeup_time_t *) __va(runtime->set_wakeup_time), \ 1127d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis enabled, atm); \ 1137d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis ia64_load_scratch_fpregs(fr); \ 1147d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis return ret; \ 1151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1177d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis#define STUB_GET_VARIABLE(prefix, adjust_arg) \ 1187d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffisstatic efi_status_t \ 1197d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffisprefix##_get_variable (efi_char16_t *name, efi_guid_t *vendor, u32 *attr, \ 1207d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis unsigned long *data_size, void *data) \ 1217d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis{ \ 1227d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis struct ia64_fpreg fr[6]; \ 1237d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis u32 *aattr = NULL; \ 1247d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis efi_status_t ret; \ 1257d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis \ 1267d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis if (attr) \ 1277d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis aattr = adjust_arg(attr); \ 1287d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis ia64_save_scratch_fpregs(fr); \ 1297d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis ret = efi_call_##prefix( \ 1307d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis (efi_get_variable_t *) __va(runtime->get_variable), \ 1317d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis adjust_arg(name), adjust_arg(vendor), aattr, \ 1327d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis adjust_arg(data_size), adjust_arg(data)); \ 1337d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis ia64_load_scratch_fpregs(fr); \ 1347d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis return ret; \ 1351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1377d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis#define STUB_GET_NEXT_VARIABLE(prefix, adjust_arg) \ 1387d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffisstatic efi_status_t \ 1397d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffisprefix##_get_next_variable (unsigned long *name_size, efi_char16_t *name, \ 1407d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis efi_guid_t *vendor) \ 1417d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis{ \ 1427d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis struct ia64_fpreg fr[6]; \ 1437d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis efi_status_t ret; \ 1447d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis \ 1457d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis ia64_save_scratch_fpregs(fr); \ 1467d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis ret = efi_call_##prefix( \ 1477d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis (efi_get_next_variable_t *) __va(runtime->get_next_variable), \ 1487d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis adjust_arg(name_size), adjust_arg(name), adjust_arg(vendor)); \ 1497d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis ia64_load_scratch_fpregs(fr); \ 1507d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis return ret; \ 1511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1537d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis#define STUB_SET_VARIABLE(prefix, adjust_arg) \ 1547d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffisstatic efi_status_t \ 1557d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffisprefix##_set_variable (efi_char16_t *name, efi_guid_t *vendor, \ 1567d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis unsigned long attr, unsigned long data_size, \ 1577d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis void *data) \ 1587d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis{ \ 1597d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis struct ia64_fpreg fr[6]; \ 1607d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis efi_status_t ret; \ 1617d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis \ 1627d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis ia64_save_scratch_fpregs(fr); \ 1637d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis ret = efi_call_##prefix( \ 1647d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis (efi_set_variable_t *) __va(runtime->set_variable), \ 1657d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis adjust_arg(name), adjust_arg(vendor), attr, data_size, \ 1667d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis adjust_arg(data)); \ 1677d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis ia64_load_scratch_fpregs(fr); \ 1687d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis return ret; \ 1691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1717d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis#define STUB_GET_NEXT_HIGH_MONO_COUNT(prefix, adjust_arg) \ 1727d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffisstatic efi_status_t \ 1737d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffisprefix##_get_next_high_mono_count (u32 *count) \ 1747d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis{ \ 1757d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis struct ia64_fpreg fr[6]; \ 1767d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis efi_status_t ret; \ 1777d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis \ 1787d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis ia64_save_scratch_fpregs(fr); \ 1797d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis ret = efi_call_##prefix((efi_get_next_high_mono_count_t *) \ 1807d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis __va(runtime->get_next_high_mono_count), \ 1817d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis adjust_arg(count)); \ 1827d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis ia64_load_scratch_fpregs(fr); \ 1837d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis return ret; \ 1841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1867d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis#define STUB_RESET_SYSTEM(prefix, adjust_arg) \ 1877d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffisstatic void \ 1887d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffisprefix##_reset_system (int reset_type, efi_status_t status, \ 1897d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis unsigned long data_size, efi_char16_t *data) \ 1907d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis{ \ 1917d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis struct ia64_fpreg fr[6]; \ 1927d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis efi_char16_t *adata = NULL; \ 1937d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis \ 1947d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis if (data) \ 1957d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis adata = adjust_arg(data); \ 1967d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis \ 1977d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis ia64_save_scratch_fpregs(fr); \ 1987d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis efi_call_##prefix( \ 1997d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis (efi_reset_system_t *) __va(runtime->reset_system), \ 2007d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis reset_type, status, data_size, adata); \ 2017d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis /* should not return, but just in case... */ \ 2027d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis ia64_load_scratch_fpregs(fr); \ 2031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define phys_ptr(arg) ((__typeof__(arg)) ia64_tpa(arg)) 2061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsSTUB_GET_TIME(phys, phys_ptr) 2081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsSTUB_SET_TIME(phys, phys_ptr) 2091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsSTUB_GET_WAKEUP_TIME(phys, phys_ptr) 2101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsSTUB_SET_WAKEUP_TIME(phys, phys_ptr) 2111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsSTUB_GET_VARIABLE(phys, phys_ptr) 2121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsSTUB_GET_NEXT_VARIABLE(phys, phys_ptr) 2131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsSTUB_SET_VARIABLE(phys, phys_ptr) 2141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsSTUB_GET_NEXT_HIGH_MONO_COUNT(phys, phys_ptr) 2151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsSTUB_RESET_SYSTEM(phys, phys_ptr) 2161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define id(arg) arg 2181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsSTUB_GET_TIME(virt, id) 2201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsSTUB_SET_TIME(virt, id) 2211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsSTUB_GET_WAKEUP_TIME(virt, id) 2221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsSTUB_SET_WAKEUP_TIME(virt, id) 2231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsSTUB_GET_VARIABLE(virt, id) 2241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsSTUB_GET_NEXT_VARIABLE(virt, id) 2251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsSTUB_SET_VARIABLE(virt, id) 2261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsSTUB_GET_NEXT_HIGH_MONO_COUNT(virt, id) 2271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsSTUB_RESET_SYSTEM(virt, id) 2281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid 2301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsefi_gettimeofday (struct timespec *ts) 2311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds efi_time_t tm; 2331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2344b07ae9b9d7b05a63e3ece32a666041949b7f421Li Zefan if ((*efi.get_time)(&tm, NULL) != EFI_SUCCESS) { 2354b07ae9b9d7b05a63e3ece32a666041949b7f421Li Zefan memset(ts, 0, sizeof(*ts)); 2361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 2374b07ae9b9d7b05a63e3ece32a666041949b7f421Li Zefan } 2381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2397d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis ts->tv_sec = mktime(tm.year, tm.month, tm.day, 2407d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis tm.hour, tm.minute, tm.second); 2411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ts->tv_nsec = tm.nanosecond; 2421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int 24566888a6e5ffc756b9a4115fc766ee2258eefb928Christoph Lameteris_memory_available (efi_memory_desc_t *md) 2461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!(md->attribute & EFI_MEMORY_WB)) 2481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 2491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (md->type) { 2511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case EFI_LOADER_CODE: 2521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case EFI_LOADER_DATA: 2531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case EFI_BOOT_SERVICES_CODE: 2541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case EFI_BOOT_SERVICES_DATA: 2551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case EFI_CONVENTIONAL_MEMORY: 2561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 1; 2571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 2591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 261d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Lucktypedef struct kern_memdesc { 262d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck u64 attribute; 263d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck u64 start; 264d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck u64 num_pages; 265d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck} kern_memdesc_t; 2661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 267d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luckstatic kern_memdesc_t *kern_memmap; 2681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 26980851ef2a5a404e6054211ca96ecd5ac4b06d297Bjorn Helgaas#define efi_md_size(md) (md->num_pages << EFI_PAGE_SHIFT) 27080851ef2a5a404e6054211ca96ecd5ac4b06d297Bjorn Helgaas 27180851ef2a5a404e6054211ca96ecd5ac4b06d297Bjorn Helgaasstatic inline u64 27280851ef2a5a404e6054211ca96ecd5ac4b06d297Bjorn Helgaaskmd_end(kern_memdesc_t *kmd) 27380851ef2a5a404e6054211ca96ecd5ac4b06d297Bjorn Helgaas{ 27480851ef2a5a404e6054211ca96ecd5ac4b06d297Bjorn Helgaas return (kmd->start + (kmd->num_pages << EFI_PAGE_SHIFT)); 27580851ef2a5a404e6054211ca96ecd5ac4b06d297Bjorn Helgaas} 27680851ef2a5a404e6054211ca96ecd5ac4b06d297Bjorn Helgaas 27780851ef2a5a404e6054211ca96ecd5ac4b06d297Bjorn Helgaasstatic inline u64 27880851ef2a5a404e6054211ca96ecd5ac4b06d297Bjorn Helgaasefi_md_end(efi_memory_desc_t *md) 27980851ef2a5a404e6054211ca96ecd5ac4b06d297Bjorn Helgaas{ 28080851ef2a5a404e6054211ca96ecd5ac4b06d297Bjorn Helgaas return (md->phys_addr + efi_md_size(md)); 28180851ef2a5a404e6054211ca96ecd5ac4b06d297Bjorn Helgaas} 28280851ef2a5a404e6054211ca96ecd5ac4b06d297Bjorn Helgaas 28380851ef2a5a404e6054211ca96ecd5ac4b06d297Bjorn Helgaasstatic inline int 28480851ef2a5a404e6054211ca96ecd5ac4b06d297Bjorn Helgaasefi_wb(efi_memory_desc_t *md) 28580851ef2a5a404e6054211ca96ecd5ac4b06d297Bjorn Helgaas{ 28680851ef2a5a404e6054211ca96ecd5ac4b06d297Bjorn Helgaas return (md->attribute & EFI_MEMORY_WB); 28780851ef2a5a404e6054211ca96ecd5ac4b06d297Bjorn Helgaas} 28880851ef2a5a404e6054211ca96ecd5ac4b06d297Bjorn Helgaas 28980851ef2a5a404e6054211ca96ecd5ac4b06d297Bjorn Helgaasstatic inline int 29080851ef2a5a404e6054211ca96ecd5ac4b06d297Bjorn Helgaasefi_uc(efi_memory_desc_t *md) 29180851ef2a5a404e6054211ca96ecd5ac4b06d297Bjorn Helgaas{ 29280851ef2a5a404e6054211ca96ecd5ac4b06d297Bjorn Helgaas return (md->attribute & EFI_MEMORY_UC); 29380851ef2a5a404e6054211ca96ecd5ac4b06d297Bjorn Helgaas} 29480851ef2a5a404e6054211ca96ecd5ac4b06d297Bjorn Helgaas 2951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void 296d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luckwalk (efi_freemem_callback_t callback, void *arg, u64 attr) 2971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 298d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck kern_memdesc_t *k; 299d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck u64 start, end, voff; 3001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 301d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck voff = (attr == EFI_MEMORY_WB) ? PAGE_OFFSET : __IA64_UNCACHED_OFFSET; 302d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck for (k = kern_memmap; k->start != ~0UL; k++) { 303d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck if (k->attribute != attr) 304d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck continue; 305d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck start = PAGE_ALIGN(k->start); 306d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck end = (k->start + (k->num_pages << EFI_PAGE_SHIFT)) & PAGE_MASK; 307d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck if (start < end) 308d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck if ((*callback)(start + voff, end + voff, arg) < 0) 309d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck return; 310d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck } 3111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 314965e7c8affeca27f7e5de75c97954e74d3b8052dAron Griffis * Walk the EFI memory map and call CALLBACK once for each EFI memory 3157d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis * descriptor that has memory that is available for OS use. 3161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 3171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid 3181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsefi_memmap_walk (efi_freemem_callback_t callback, void *arg) 3191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 320d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck walk(callback, arg, EFI_MEMORY_WB); 3211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 324965e7c8affeca27f7e5de75c97954e74d3b8052dAron Griffis * Walk the EFI memory map and call CALLBACK once for each EFI memory 3257d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis * descriptor that has memory that is available for uncached allocator. 326f14f75b81187cdbe10cc53a521bf9fdf97b59f8cJes Sorensen */ 327d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luckvoid 328d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luckefi_memmap_walk_uc (efi_freemem_callback_t callback, void *arg) 329f14f75b81187cdbe10cc53a521bf9fdf97b59f8cJes Sorensen{ 330d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck walk(callback, arg, EFI_MEMORY_UC); 331f14f75b81187cdbe10cc53a521bf9fdf97b59f8cJes Sorensen} 332f14f75b81187cdbe10cc53a521bf9fdf97b59f8cJes Sorensen 333f14f75b81187cdbe10cc53a521bf9fdf97b59f8cJes Sorensen/* 334965e7c8affeca27f7e5de75c97954e74d3b8052dAron Griffis * Look for the PAL_CODE region reported by EFI and map it using an 3351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * ITR to enable safe PAL calls in virtual mode. See IA-64 Processor 3361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Abstraction Layer chapter 11 in ADAG 3371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 3381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid * 3391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsefi_get_pal_addr (void) 3401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 3411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds void *efi_map_start, *efi_map_end, *p; 3421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds efi_memory_desc_t *md; 3431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u64 efi_desc_size; 3441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int pal_code_count = 0; 3451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u64 vaddr, mask; 3461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds efi_map_start = __va(ia64_boot_param->efi_memmap); 3481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds efi_map_end = efi_map_start + ia64_boot_param->efi_memmap_size; 3491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds efi_desc_size = ia64_boot_param->efi_memdesc_size; 3501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (p = efi_map_start; p < efi_map_end; p += efi_desc_size) { 3521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds md = p; 3531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (md->type != EFI_PAL_CODE) 3541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds continue; 3551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (++pal_code_count > 1) { 3577d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis printk(KERN_ERR "Too many EFI Pal Code memory ranges, " 3587d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis "dropped @ %lx\n", md->phys_addr); 3591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds continue; 3601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 3627d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis * The only ITLB entry in region 7 that is used is the one 3637d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis * installed by __start(). That entry covers a 64MB range. 3641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 3651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mask = ~((1 << KERNEL_TR_PAGE_SHIFT) - 1); 3661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds vaddr = PAGE_OFFSET + md->phys_addr; 3671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 3697d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis * We must check that the PAL mapping won't overlap with the 3707d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis * kernel mapping. 3711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 3727d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis * PAL code is guaranteed to be aligned on a power of 2 between 3737d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis * 4k and 256KB and that only one ITR is needed to map it. This 3747d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis * implies that the PAL code is always aligned on its size, 3757d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis * i.e., the closest matching page size supported by the TLB. 3767d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis * Therefore PAL code is guaranteed never to cross a 64MB unless 3777d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis * it is bigger than 64MB (very unlikely!). So for now the 3787d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis * following test is enough to determine whether or not we need 3797d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis * a dedicated ITR for the PAL code. 3801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 3811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((vaddr & mask) == (KERNEL_START & mask)) { 3827d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis printk(KERN_INFO "%s: no need to install ITR for " 3837d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis "PAL code\n", __FUNCTION__); 3841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds continue; 3851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 387685c7f5d3629d558b17ee193b6d7f194e82aadf0Li Zefan if (efi_md_size(md) > IA64_GRANULE_SIZE) 388965e7c8affeca27f7e5de75c97954e74d3b8052dAron Griffis panic("Whoa! PAL code size bigger than a granule!"); 3891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#if EFI_DEBUG 3911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mask = ~((1 << IA64_GRANULE_SHIFT) - 1); 3921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3937d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis printk(KERN_INFO "CPU %d: mapping PAL code " 3947d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis "[0x%lx-0x%lx) into [0x%lx-0x%lx)\n", 3957d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis smp_processor_id(), md->phys_addr, 3967d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis md->phys_addr + efi_md_size(md), 3977d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis vaddr & mask, (vaddr & mask) + IA64_GRANULE_SIZE); 3981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 3991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return __va(md->phys_addr); 4001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4019473252f20e8482464415d9030b3957b5593796dHorms printk(KERN_WARNING "%s: no PAL-code memory-descriptor found\n", 4021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds __FUNCTION__); 4031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return NULL; 4041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid 4071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsefi_map_pal_code (void) 4081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 4091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds void *pal_vaddr = efi_get_pal_addr (); 4101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u64 psr; 4111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!pal_vaddr) 4131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 4141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 4161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Cannot write to CRx with PSR.ic=1 4171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 4181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds psr = ia64_clear_ic(); 4197d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis ia64_itr(0x1, IA64_TR_PALCODE, 4207d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis GRANULEROUNDDOWN((unsigned long) pal_vaddr), 4211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pte_val(pfn_pte(__pa(pal_vaddr) >> PAGE_SHIFT, PAGE_KERNEL)), 4221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds IA64_GRANULE_SHIFT); 4231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ia64_set_psr(psr); /* restore psr */ 4241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ia64_srlz_i(); 4251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid __init 4281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsefi_init (void) 4291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 4301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds void *efi_map_start, *efi_map_end; 4311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds efi_config_table_t *config_tables; 4321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds efi_char16_t *c16; 4331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u64 efi_desc_size; 4349d78f43d1fd3e028bfd37510ce847d0896f71f78Zou Nan hai char *cp, vendor[100] = "unknown"; 4351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i; 4361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4377d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis /* 438965e7c8affeca27f7e5de75c97954e74d3b8052dAron Griffis * It's too early to be able to use the standard kernel command line 4397d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis * support... 4407d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis */ 441a8d91b8477aa433ee0131b031d782411976e1726Alon Bar-Lev for (cp = boot_command_line; *cp; ) { 4421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (memcmp(cp, "mem=", 4) == 0) { 4439d78f43d1fd3e028bfd37510ce847d0896f71f78Zou Nan hai mem_limit = memparse(cp + 4, &cp); 4441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else if (memcmp(cp, "max_addr=", 9) == 0) { 4459d78f43d1fd3e028bfd37510ce847d0896f71f78Zou Nan hai max_addr = GRANULEROUNDDOWN(memparse(cp + 9, &cp)); 446a79561134f38de12dce14ed72138f38e55ef53fcZou Nan hai } else if (memcmp(cp, "min_addr=", 9) == 0) { 447a79561134f38de12dce14ed72138f38e55ef53fcZou Nan hai min_addr = GRANULEROUNDDOWN(memparse(cp + 9, &cp)); 4481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 4491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while (*cp != ' ' && *cp) 4501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ++cp; 4511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while (*cp == ' ') 4521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ++cp; 4531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 455a79561134f38de12dce14ed72138f38e55ef53fcZou Nan hai if (min_addr != 0UL) 4567d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis printk(KERN_INFO "Ignoring memory below %luMB\n", 4577d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis min_addr >> 20); 4581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (max_addr != ~0UL) 4597d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis printk(KERN_INFO "Ignoring memory above %luMB\n", 4607d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis max_addr >> 20); 4611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds efi.systab = __va(ia64_boot_param->efi_systab); 4631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 4651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Verify the EFI Table 4661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 4671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (efi.systab == NULL) 468965e7c8affeca27f7e5de75c97954e74d3b8052dAron Griffis panic("Whoa! Can't find EFI system table.\n"); 4691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (efi.systab->hdr.signature != EFI_SYSTEM_TABLE_SIGNATURE) 470965e7c8affeca27f7e5de75c97954e74d3b8052dAron Griffis panic("Whoa! EFI system table signature incorrect\n"); 471873ec746158403af82c57ce26780166aafc159e1Bjorn Helgaas if ((efi.systab->hdr.revision >> 16) == 0) 472873ec746158403af82c57ce26780166aafc159e1Bjorn Helgaas printk(KERN_WARNING "Warning: EFI system table version " 473873ec746158403af82c57ce26780166aafc159e1Bjorn Helgaas "%d.%02d, expected 1.00 or greater\n", 474873ec746158403af82c57ce26780166aafc159e1Bjorn Helgaas efi.systab->hdr.revision >> 16, 475873ec746158403af82c57ce26780166aafc159e1Bjorn Helgaas efi.systab->hdr.revision & 0xffff); 4761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds config_tables = __va(efi.systab->tables); 4781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Show what we know for posterity */ 4801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds c16 = __va(efi.systab->fw_vendor); 4811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (c16) { 482ecdd5dabd33d67066d476467e447cdcadab90550Zou Nan hai for (i = 0;i < (int) sizeof(vendor) - 1 && *c16; ++i) 4831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds vendor[i] = *c16++; 4841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds vendor[i] = '\0'; 4851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_INFO "EFI v%u.%.02u by %s:", 4887d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis efi.systab->hdr.revision >> 16, 4897d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis efi.systab->hdr.revision & 0xffff, vendor); 4901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 491b2c99e3c70d77fb194df5aa1642030080d28ea48Bjorn Helgaas efi.mps = EFI_INVALID_TABLE_ADDR; 492b2c99e3c70d77fb194df5aa1642030080d28ea48Bjorn Helgaas efi.acpi = EFI_INVALID_TABLE_ADDR; 493b2c99e3c70d77fb194df5aa1642030080d28ea48Bjorn Helgaas efi.acpi20 = EFI_INVALID_TABLE_ADDR; 494b2c99e3c70d77fb194df5aa1642030080d28ea48Bjorn Helgaas efi.smbios = EFI_INVALID_TABLE_ADDR; 495b2c99e3c70d77fb194df5aa1642030080d28ea48Bjorn Helgaas efi.sal_systab = EFI_INVALID_TABLE_ADDR; 496b2c99e3c70d77fb194df5aa1642030080d28ea48Bjorn Helgaas efi.boot_info = EFI_INVALID_TABLE_ADDR; 497b2c99e3c70d77fb194df5aa1642030080d28ea48Bjorn Helgaas efi.hcdp = EFI_INVALID_TABLE_ADDR; 498b2c99e3c70d77fb194df5aa1642030080d28ea48Bjorn Helgaas efi.uga = EFI_INVALID_TABLE_ADDR; 499b2c99e3c70d77fb194df5aa1642030080d28ea48Bjorn Helgaas 5001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; i < (int) efi.systab->nr_tables; i++) { 5011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (efi_guidcmp(config_tables[i].guid, MPS_TABLE_GUID) == 0) { 502b2c99e3c70d77fb194df5aa1642030080d28ea48Bjorn Helgaas efi.mps = config_tables[i].table; 5031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(" MPS=0x%lx", config_tables[i].table); 5041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else if (efi_guidcmp(config_tables[i].guid, ACPI_20_TABLE_GUID) == 0) { 505b2c99e3c70d77fb194df5aa1642030080d28ea48Bjorn Helgaas efi.acpi20 = config_tables[i].table; 5061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(" ACPI 2.0=0x%lx", config_tables[i].table); 5071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else if (efi_guidcmp(config_tables[i].guid, ACPI_TABLE_GUID) == 0) { 508b2c99e3c70d77fb194df5aa1642030080d28ea48Bjorn Helgaas efi.acpi = config_tables[i].table; 5091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(" ACPI=0x%lx", config_tables[i].table); 5101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else if (efi_guidcmp(config_tables[i].guid, SMBIOS_TABLE_GUID) == 0) { 511b2c99e3c70d77fb194df5aa1642030080d28ea48Bjorn Helgaas efi.smbios = config_tables[i].table; 5121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(" SMBIOS=0x%lx", config_tables[i].table); 5131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else if (efi_guidcmp(config_tables[i].guid, SAL_SYSTEM_TABLE_GUID) == 0) { 514b2c99e3c70d77fb194df5aa1642030080d28ea48Bjorn Helgaas efi.sal_systab = config_tables[i].table; 5151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(" SALsystab=0x%lx", config_tables[i].table); 5161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else if (efi_guidcmp(config_tables[i].guid, HCDP_TABLE_GUID) == 0) { 517b2c99e3c70d77fb194df5aa1642030080d28ea48Bjorn Helgaas efi.hcdp = config_tables[i].table; 5181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(" HCDP=0x%lx", config_tables[i].table); 5191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 5201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 5211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk("\n"); 5221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds runtime = __va(efi.systab->runtime); 5241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds efi.get_time = phys_get_time; 5251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds efi.set_time = phys_set_time; 5261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds efi.get_wakeup_time = phys_get_wakeup_time; 5271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds efi.set_wakeup_time = phys_set_wakeup_time; 5281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds efi.get_variable = phys_get_variable; 5291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds efi.get_next_variable = phys_get_next_variable; 5301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds efi.set_variable = phys_set_variable; 5311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds efi.get_next_high_mono_count = phys_get_next_high_mono_count; 5321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds efi.reset_system = phys_reset_system; 5331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds efi_map_start = __va(ia64_boot_param->efi_memmap); 5351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds efi_map_end = efi_map_start + ia64_boot_param->efi_memmap_size; 5361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds efi_desc_size = ia64_boot_param->efi_memdesc_size; 5371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#if EFI_DEBUG 5391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* print EFI memory map: */ 5401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { 5411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds efi_memory_desc_t *md; 5421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds void *p; 5431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5447d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis for (i = 0, p = efi_map_start; p < efi_map_end; 5457d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis ++i, p += efi_desc_size) 5467d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis { 5471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds md = p; 5487d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis printk("mem%02u: type=%u, attr=0x%lx, " 5497d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis "range=[0x%016lx-0x%016lx) (%luMB)\n", 5501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds i, md->type, md->attribute, md->phys_addr, 551685c7f5d3629d558b17ee193b6d7f194e82aadf0Li Zefan md->phys_addr + efi_md_size(md), 5521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds md->num_pages >> (20 - EFI_PAGE_SHIFT)); 5531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 5541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 5551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 5561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds efi_map_pal_code(); 5581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds efi_enter_virtual_mode(); 5591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 5601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid 5621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsefi_enter_virtual_mode (void) 5631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 5641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds void *efi_map_start, *efi_map_end, *p; 5651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds efi_memory_desc_t *md; 5661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds efi_status_t status; 5671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u64 efi_desc_size; 5681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds efi_map_start = __va(ia64_boot_param->efi_memmap); 5701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds efi_map_end = efi_map_start + ia64_boot_param->efi_memmap_size; 5711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds efi_desc_size = ia64_boot_param->efi_memdesc_size; 5721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (p = efi_map_start; p < efi_map_end; p += efi_desc_size) { 5741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds md = p; 5751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (md->attribute & EFI_MEMORY_RUNTIME) { 5761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 5777d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis * Some descriptors have multiple bits set, so the 5787d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis * order of the tests is relevant. 5791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 5801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (md->attribute & EFI_MEMORY_WB) { 5811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds md->virt_addr = (u64) __va(md->phys_addr); 5821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else if (md->attribute & EFI_MEMORY_UC) { 5831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds md->virt_addr = (u64) ioremap(md->phys_addr, 0); 5841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else if (md->attribute & EFI_MEMORY_WC) { 5851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#if 0 5867d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis md->virt_addr = ia64_remap(md->phys_addr, 5877d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis (_PAGE_A | 5887d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis _PAGE_P | 5897d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis _PAGE_D | 5907d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis _PAGE_MA_WC | 5917d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis _PAGE_PL_0 | 5927d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis _PAGE_AR_RW)); 5931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#else 5941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_INFO "EFI_MEMORY_WC mapping\n"); 5951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds md->virt_addr = (u64) ioremap(md->phys_addr, 0); 5961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 5971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else if (md->attribute & EFI_MEMORY_WT) { 5981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#if 0 5997d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis md->virt_addr = ia64_remap(md->phys_addr, 6007d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis (_PAGE_A | 6017d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis _PAGE_P | 6027d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis _PAGE_D | 6037d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis _PAGE_MA_WT | 6047d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis _PAGE_PL_0 | 6057d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis _PAGE_AR_RW)); 6061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#else 6071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_INFO "EFI_MEMORY_WT mapping\n"); 6081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds md->virt_addr = (u64) ioremap(md->phys_addr, 0); 6091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 6101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 6111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 6121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 6131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds status = efi_call_phys(__va(runtime->set_virtual_address_map), 6151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ia64_boot_param->efi_memmap_size, 6167d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis efi_desc_size, 6177d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis ia64_boot_param->efi_memdesc_version, 6181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ia64_boot_param->efi_memmap); 6191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (status != EFI_SUCCESS) { 6207d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis printk(KERN_WARNING "warning: unable to switch EFI into " 6217d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis "virtual mode (status=%lu)\n", status); 6221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 6231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 6241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 6267d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis * Now that EFI is in virtual mode, we call the EFI functions more 6277d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis * efficiently: 6281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 6291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds efi.get_time = virt_get_time; 6301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds efi.set_time = virt_set_time; 6311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds efi.get_wakeup_time = virt_get_wakeup_time; 6321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds efi.set_wakeup_time = virt_set_wakeup_time; 6331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds efi.get_variable = virt_get_variable; 6341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds efi.get_next_variable = virt_get_next_variable; 6351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds efi.set_variable = virt_set_variable; 6361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds efi.get_next_high_mono_count = virt_get_next_high_mono_count; 6371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds efi.reset_system = virt_reset_system; 6381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 6391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 6417d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis * Walk the EFI memory map looking for the I/O port range. There can only be 6427d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis * one entry of this type, other I/O port ranges should be described via ACPI. 6431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 6441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsu64 6451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsefi_get_iobase (void) 6461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 6471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds void *efi_map_start, *efi_map_end, *p; 6481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds efi_memory_desc_t *md; 6491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u64 efi_desc_size; 6501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds efi_map_start = __va(ia64_boot_param->efi_memmap); 6521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds efi_map_end = efi_map_start + ia64_boot_param->efi_memmap_size; 6531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds efi_desc_size = ia64_boot_param->efi_memdesc_size; 6541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (p = efi_map_start; p < efi_map_end; p += efi_desc_size) { 6561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds md = p; 6571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (md->type == EFI_MEMORY_MAPPED_IO_PORT_SPACE) { 6581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (md->attribute & EFI_MEMORY_UC) 6591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return md->phys_addr; 6601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 6611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 6621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 6631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 6641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 66532e62c636a728cb39c0b3bd191286f2ca65d4028Bjorn Helgaasstatic struct kern_memdesc * 66632e62c636a728cb39c0b3bd191286f2ca65d4028Bjorn Helgaaskern_memory_descriptor (unsigned long phys_addr) 6671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 66832e62c636a728cb39c0b3bd191286f2ca65d4028Bjorn Helgaas struct kern_memdesc *md; 6691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 67032e62c636a728cb39c0b3bd191286f2ca65d4028Bjorn Helgaas for (md = kern_memmap; md->start != ~0UL; md++) { 67132e62c636a728cb39c0b3bd191286f2ca65d4028Bjorn Helgaas if (phys_addr - md->start < (md->num_pages << EFI_PAGE_SHIFT)) 67280851ef2a5a404e6054211ca96ecd5ac4b06d297Bjorn Helgaas return md; 6731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 674e037cda559547e6353c5a792802963572d0b750eKeith Owens return NULL; 6751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 6761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 67732e62c636a728cb39c0b3bd191286f2ca65d4028Bjorn Helgaasstatic efi_memory_desc_t * 67832e62c636a728cb39c0b3bd191286f2ca65d4028Bjorn Helgaasefi_memory_descriptor (unsigned long phys_addr) 6791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 6801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds void *efi_map_start, *efi_map_end, *p; 6811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds efi_memory_desc_t *md; 6821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u64 efi_desc_size; 6831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds efi_map_start = __va(ia64_boot_param->efi_memmap); 6851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds efi_map_end = efi_map_start + ia64_boot_param->efi_memmap_size; 6861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds efi_desc_size = ia64_boot_param->efi_memdesc_size; 6871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (p = efi_map_start; p < efi_map_end; p += efi_desc_size) { 6891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds md = p; 6901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 691685c7f5d3629d558b17ee193b6d7f194e82aadf0Li Zefan if (phys_addr - md->phys_addr < efi_md_size(md)) 69232e62c636a728cb39c0b3bd191286f2ca65d4028Bjorn Helgaas return md; 6931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 694e037cda559547e6353c5a792802963572d0b750eKeith Owens return NULL; 6951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 69680851ef2a5a404e6054211ca96ecd5ac4b06d297Bjorn Helgaas 6976d40fc514c9ea886dc18ddd20043a411816b63d1Bjorn Helgaasstatic int 6986d40fc514c9ea886dc18ddd20043a411816b63d1Bjorn Helgaasefi_memmap_intersects (unsigned long phys_addr, unsigned long size) 6996d40fc514c9ea886dc18ddd20043a411816b63d1Bjorn Helgaas{ 7006d40fc514c9ea886dc18ddd20043a411816b63d1Bjorn Helgaas void *efi_map_start, *efi_map_end, *p; 7016d40fc514c9ea886dc18ddd20043a411816b63d1Bjorn Helgaas efi_memory_desc_t *md; 7026d40fc514c9ea886dc18ddd20043a411816b63d1Bjorn Helgaas u64 efi_desc_size; 7036d40fc514c9ea886dc18ddd20043a411816b63d1Bjorn Helgaas unsigned long end; 7046d40fc514c9ea886dc18ddd20043a411816b63d1Bjorn Helgaas 7056d40fc514c9ea886dc18ddd20043a411816b63d1Bjorn Helgaas efi_map_start = __va(ia64_boot_param->efi_memmap); 7066d40fc514c9ea886dc18ddd20043a411816b63d1Bjorn Helgaas efi_map_end = efi_map_start + ia64_boot_param->efi_memmap_size; 7076d40fc514c9ea886dc18ddd20043a411816b63d1Bjorn Helgaas efi_desc_size = ia64_boot_param->efi_memdesc_size; 7086d40fc514c9ea886dc18ddd20043a411816b63d1Bjorn Helgaas 7096d40fc514c9ea886dc18ddd20043a411816b63d1Bjorn Helgaas end = phys_addr + size; 7106d40fc514c9ea886dc18ddd20043a411816b63d1Bjorn Helgaas 7116d40fc514c9ea886dc18ddd20043a411816b63d1Bjorn Helgaas for (p = efi_map_start; p < efi_map_end; p += efi_desc_size) { 7126d40fc514c9ea886dc18ddd20043a411816b63d1Bjorn Helgaas md = p; 7136d40fc514c9ea886dc18ddd20043a411816b63d1Bjorn Helgaas if (md->phys_addr < end && efi_md_end(md) > phys_addr) 7146d40fc514c9ea886dc18ddd20043a411816b63d1Bjorn Helgaas return 1; 7156d40fc514c9ea886dc18ddd20043a411816b63d1Bjorn Helgaas } 7166d40fc514c9ea886dc18ddd20043a411816b63d1Bjorn Helgaas return 0; 7176d40fc514c9ea886dc18ddd20043a411816b63d1Bjorn Helgaas} 7186d40fc514c9ea886dc18ddd20043a411816b63d1Bjorn Helgaas 71980851ef2a5a404e6054211ca96ecd5ac4b06d297Bjorn Helgaasu32 72080851ef2a5a404e6054211ca96ecd5ac4b06d297Bjorn Helgaasefi_mem_type (unsigned long phys_addr) 72180851ef2a5a404e6054211ca96ecd5ac4b06d297Bjorn Helgaas{ 72280851ef2a5a404e6054211ca96ecd5ac4b06d297Bjorn Helgaas efi_memory_desc_t *md = efi_memory_descriptor(phys_addr); 72380851ef2a5a404e6054211ca96ecd5ac4b06d297Bjorn Helgaas 72480851ef2a5a404e6054211ca96ecd5ac4b06d297Bjorn Helgaas if (md) 72580851ef2a5a404e6054211ca96ecd5ac4b06d297Bjorn Helgaas return md->type; 72680851ef2a5a404e6054211ca96ecd5ac4b06d297Bjorn Helgaas return 0; 72780851ef2a5a404e6054211ca96ecd5ac4b06d297Bjorn Helgaas} 72880851ef2a5a404e6054211ca96ecd5ac4b06d297Bjorn Helgaas 72980851ef2a5a404e6054211ca96ecd5ac4b06d297Bjorn Helgaasu64 73080851ef2a5a404e6054211ca96ecd5ac4b06d297Bjorn Helgaasefi_mem_attributes (unsigned long phys_addr) 73180851ef2a5a404e6054211ca96ecd5ac4b06d297Bjorn Helgaas{ 73280851ef2a5a404e6054211ca96ecd5ac4b06d297Bjorn Helgaas efi_memory_desc_t *md = efi_memory_descriptor(phys_addr); 73380851ef2a5a404e6054211ca96ecd5ac4b06d297Bjorn Helgaas 73480851ef2a5a404e6054211ca96ecd5ac4b06d297Bjorn Helgaas if (md) 73580851ef2a5a404e6054211ca96ecd5ac4b06d297Bjorn Helgaas return md->attribute; 73680851ef2a5a404e6054211ca96ecd5ac4b06d297Bjorn Helgaas return 0; 73780851ef2a5a404e6054211ca96ecd5ac4b06d297Bjorn Helgaas} 7381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsEXPORT_SYMBOL(efi_mem_attributes); 7391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 74032e62c636a728cb39c0b3bd191286f2ca65d4028Bjorn Helgaasu64 74132e62c636a728cb39c0b3bd191286f2ca65d4028Bjorn Helgaasefi_mem_attribute (unsigned long phys_addr, unsigned long size) 74280851ef2a5a404e6054211ca96ecd5ac4b06d297Bjorn Helgaas{ 743136939a2b5aa4302281215745ccd567e1df2e8d4Bjorn Helgaas unsigned long end = phys_addr + size; 74480851ef2a5a404e6054211ca96ecd5ac4b06d297Bjorn Helgaas efi_memory_desc_t *md = efi_memory_descriptor(phys_addr); 74532e62c636a728cb39c0b3bd191286f2ca65d4028Bjorn Helgaas u64 attr; 74632e62c636a728cb39c0b3bd191286f2ca65d4028Bjorn Helgaas 74732e62c636a728cb39c0b3bd191286f2ca65d4028Bjorn Helgaas if (!md) 74832e62c636a728cb39c0b3bd191286f2ca65d4028Bjorn Helgaas return 0; 74932e62c636a728cb39c0b3bd191286f2ca65d4028Bjorn Helgaas 75032e62c636a728cb39c0b3bd191286f2ca65d4028Bjorn Helgaas /* 75132e62c636a728cb39c0b3bd191286f2ca65d4028Bjorn Helgaas * EFI_MEMORY_RUNTIME is not a memory attribute; it just tells 75232e62c636a728cb39c0b3bd191286f2ca65d4028Bjorn Helgaas * the kernel that firmware needs this region mapped. 75332e62c636a728cb39c0b3bd191286f2ca65d4028Bjorn Helgaas */ 75432e62c636a728cb39c0b3bd191286f2ca65d4028Bjorn Helgaas attr = md->attribute & ~EFI_MEMORY_RUNTIME; 75532e62c636a728cb39c0b3bd191286f2ca65d4028Bjorn Helgaas do { 75632e62c636a728cb39c0b3bd191286f2ca65d4028Bjorn Helgaas unsigned long md_end = efi_md_end(md); 75732e62c636a728cb39c0b3bd191286f2ca65d4028Bjorn Helgaas 75832e62c636a728cb39c0b3bd191286f2ca65d4028Bjorn Helgaas if (end <= md_end) 75932e62c636a728cb39c0b3bd191286f2ca65d4028Bjorn Helgaas return attr; 76032e62c636a728cb39c0b3bd191286f2ca65d4028Bjorn Helgaas 76132e62c636a728cb39c0b3bd191286f2ca65d4028Bjorn Helgaas md = efi_memory_descriptor(md_end); 76232e62c636a728cb39c0b3bd191286f2ca65d4028Bjorn Helgaas if (!md || (md->attribute & ~EFI_MEMORY_RUNTIME) != attr) 76332e62c636a728cb39c0b3bd191286f2ca65d4028Bjorn Helgaas return 0; 76432e62c636a728cb39c0b3bd191286f2ca65d4028Bjorn Helgaas } while (md); 76532e62c636a728cb39c0b3bd191286f2ca65d4028Bjorn Helgaas return 0; 76632e62c636a728cb39c0b3bd191286f2ca65d4028Bjorn Helgaas} 76732e62c636a728cb39c0b3bd191286f2ca65d4028Bjorn Helgaas 76832e62c636a728cb39c0b3bd191286f2ca65d4028Bjorn Helgaasu64 76932e62c636a728cb39c0b3bd191286f2ca65d4028Bjorn Helgaaskern_mem_attribute (unsigned long phys_addr, unsigned long size) 77032e62c636a728cb39c0b3bd191286f2ca65d4028Bjorn Helgaas{ 77132e62c636a728cb39c0b3bd191286f2ca65d4028Bjorn Helgaas unsigned long end = phys_addr + size; 77232e62c636a728cb39c0b3bd191286f2ca65d4028Bjorn Helgaas struct kern_memdesc *md; 77332e62c636a728cb39c0b3bd191286f2ca65d4028Bjorn Helgaas u64 attr; 77480851ef2a5a404e6054211ca96ecd5ac4b06d297Bjorn Helgaas 775136939a2b5aa4302281215745ccd567e1df2e8d4Bjorn Helgaas /* 77632e62c636a728cb39c0b3bd191286f2ca65d4028Bjorn Helgaas * This is a hack for ioremap calls before we set up kern_memmap. 77732e62c636a728cb39c0b3bd191286f2ca65d4028Bjorn Helgaas * Maybe we should do efi_memmap_init() earlier instead. 778136939a2b5aa4302281215745ccd567e1df2e8d4Bjorn Helgaas */ 77932e62c636a728cb39c0b3bd191286f2ca65d4028Bjorn Helgaas if (!kern_memmap) { 78032e62c636a728cb39c0b3bd191286f2ca65d4028Bjorn Helgaas attr = efi_mem_attribute(phys_addr, size); 78132e62c636a728cb39c0b3bd191286f2ca65d4028Bjorn Helgaas if (attr & EFI_MEMORY_WB) 78232e62c636a728cb39c0b3bd191286f2ca65d4028Bjorn Helgaas return EFI_MEMORY_WB; 78380851ef2a5a404e6054211ca96ecd5ac4b06d297Bjorn Helgaas return 0; 784136939a2b5aa4302281215745ccd567e1df2e8d4Bjorn Helgaas } 78580851ef2a5a404e6054211ca96ecd5ac4b06d297Bjorn Helgaas 78632e62c636a728cb39c0b3bd191286f2ca65d4028Bjorn Helgaas md = kern_memory_descriptor(phys_addr); 78732e62c636a728cb39c0b3bd191286f2ca65d4028Bjorn Helgaas if (!md) 78832e62c636a728cb39c0b3bd191286f2ca65d4028Bjorn Helgaas return 0; 78932e62c636a728cb39c0b3bd191286f2ca65d4028Bjorn Helgaas 79032e62c636a728cb39c0b3bd191286f2ca65d4028Bjorn Helgaas attr = md->attribute; 79180851ef2a5a404e6054211ca96ecd5ac4b06d297Bjorn Helgaas do { 79232e62c636a728cb39c0b3bd191286f2ca65d4028Bjorn Helgaas unsigned long md_end = kmd_end(md); 793136939a2b5aa4302281215745ccd567e1df2e8d4Bjorn Helgaas 794136939a2b5aa4302281215745ccd567e1df2e8d4Bjorn Helgaas if (end <= md_end) 79532e62c636a728cb39c0b3bd191286f2ca65d4028Bjorn Helgaas return attr; 79680851ef2a5a404e6054211ca96ecd5ac4b06d297Bjorn Helgaas 79732e62c636a728cb39c0b3bd191286f2ca65d4028Bjorn Helgaas md = kern_memory_descriptor(md_end); 79832e62c636a728cb39c0b3bd191286f2ca65d4028Bjorn Helgaas if (!md || md->attribute != attr) 799136939a2b5aa4302281215745ccd567e1df2e8d4Bjorn Helgaas return 0; 80080851ef2a5a404e6054211ca96ecd5ac4b06d297Bjorn Helgaas } while (md); 80180851ef2a5a404e6054211ca96ecd5ac4b06d297Bjorn Helgaas return 0; 80280851ef2a5a404e6054211ca96ecd5ac4b06d297Bjorn Helgaas} 80332e62c636a728cb39c0b3bd191286f2ca65d4028Bjorn HelgaasEXPORT_SYMBOL(kern_mem_attribute); 80480851ef2a5a404e6054211ca96ecd5ac4b06d297Bjorn Helgaas 8051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint 806136939a2b5aa4302281215745ccd567e1df2e8d4Bjorn Helgaasvalid_phys_addr_range (unsigned long phys_addr, unsigned long size) 8071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 80832e62c636a728cb39c0b3bd191286f2ca65d4028Bjorn Helgaas u64 attr; 80932e62c636a728cb39c0b3bd191286f2ca65d4028Bjorn Helgaas 81032e62c636a728cb39c0b3bd191286f2ca65d4028Bjorn Helgaas /* 81132e62c636a728cb39c0b3bd191286f2ca65d4028Bjorn Helgaas * /dev/mem reads and writes use copy_to_user(), which implicitly 81232e62c636a728cb39c0b3bd191286f2ca65d4028Bjorn Helgaas * uses a granule-sized kernel identity mapping. It's really 81332e62c636a728cb39c0b3bd191286f2ca65d4028Bjorn Helgaas * only safe to do this for regions in kern_memmap. For more 81432e62c636a728cb39c0b3bd191286f2ca65d4028Bjorn Helgaas * details, see Documentation/ia64/aliasing.txt. 81532e62c636a728cb39c0b3bd191286f2ca65d4028Bjorn Helgaas */ 81632e62c636a728cb39c0b3bd191286f2ca65d4028Bjorn Helgaas attr = kern_mem_attribute(phys_addr, size); 81732e62c636a728cb39c0b3bd191286f2ca65d4028Bjorn Helgaas if (attr & EFI_MEMORY_WB || attr & EFI_MEMORY_UC) 81832e62c636a728cb39c0b3bd191286f2ca65d4028Bjorn Helgaas return 1; 81932e62c636a728cb39c0b3bd191286f2ca65d4028Bjorn Helgaas return 0; 82080851ef2a5a404e6054211ca96ecd5ac4b06d297Bjorn Helgaas} 8211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 82280851ef2a5a404e6054211ca96ecd5ac4b06d297Bjorn Helgaasint 82306c67befeeb16f2995c11b0e04a348103ddbfab1Lennert Buytenhekvalid_mmap_phys_addr_range (unsigned long pfn, unsigned long size) 82480851ef2a5a404e6054211ca96ecd5ac4b06d297Bjorn Helgaas{ 8256d40fc514c9ea886dc18ddd20043a411816b63d1Bjorn Helgaas unsigned long phys_addr = pfn << PAGE_SHIFT; 8266d40fc514c9ea886dc18ddd20043a411816b63d1Bjorn Helgaas u64 attr; 8276d40fc514c9ea886dc18ddd20043a411816b63d1Bjorn Helgaas 8286d40fc514c9ea886dc18ddd20043a411816b63d1Bjorn Helgaas attr = efi_mem_attribute(phys_addr, size); 8296d40fc514c9ea886dc18ddd20043a411816b63d1Bjorn Helgaas 83032e62c636a728cb39c0b3bd191286f2ca65d4028Bjorn Helgaas /* 8316d40fc514c9ea886dc18ddd20043a411816b63d1Bjorn Helgaas * /dev/mem mmap uses normal user pages, so we don't need the entire 8326d40fc514c9ea886dc18ddd20043a411816b63d1Bjorn Helgaas * granule, but the entire region we're mapping must support the same 8336d40fc514c9ea886dc18ddd20043a411816b63d1Bjorn Helgaas * attribute. 83432e62c636a728cb39c0b3bd191286f2ca65d4028Bjorn Helgaas */ 8356d40fc514c9ea886dc18ddd20043a411816b63d1Bjorn Helgaas if (attr & EFI_MEMORY_WB || attr & EFI_MEMORY_UC) 8366d40fc514c9ea886dc18ddd20043a411816b63d1Bjorn Helgaas return 1; 8376d40fc514c9ea886dc18ddd20043a411816b63d1Bjorn Helgaas 8386d40fc514c9ea886dc18ddd20043a411816b63d1Bjorn Helgaas /* 8396d40fc514c9ea886dc18ddd20043a411816b63d1Bjorn Helgaas * Intel firmware doesn't tell us about all the MMIO regions, so 8406d40fc514c9ea886dc18ddd20043a411816b63d1Bjorn Helgaas * in general we have to allow mmap requests. But if EFI *does* 8416d40fc514c9ea886dc18ddd20043a411816b63d1Bjorn Helgaas * tell us about anything inside this region, we should deny it. 8426d40fc514c9ea886dc18ddd20043a411816b63d1Bjorn Helgaas * The user can always map a smaller region to avoid the overlap. 8436d40fc514c9ea886dc18ddd20043a411816b63d1Bjorn Helgaas */ 8446d40fc514c9ea886dc18ddd20043a411816b63d1Bjorn Helgaas if (efi_memmap_intersects(phys_addr, size)) 8456d40fc514c9ea886dc18ddd20043a411816b63d1Bjorn Helgaas return 0; 8466d40fc514c9ea886dc18ddd20043a411816b63d1Bjorn Helgaas 84732e62c636a728cb39c0b3bd191286f2ca65d4028Bjorn Helgaas return 1; 84832e62c636a728cb39c0b3bd191286f2ca65d4028Bjorn Helgaas} 8491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 85032e62c636a728cb39c0b3bd191286f2ca65d4028Bjorn Helgaaspgprot_t 85132e62c636a728cb39c0b3bd191286f2ca65d4028Bjorn Helgaasphys_mem_access_prot(struct file *file, unsigned long pfn, unsigned long size, 85232e62c636a728cb39c0b3bd191286f2ca65d4028Bjorn Helgaas pgprot_t vma_prot) 85332e62c636a728cb39c0b3bd191286f2ca65d4028Bjorn Helgaas{ 85432e62c636a728cb39c0b3bd191286f2ca65d4028Bjorn Helgaas unsigned long phys_addr = pfn << PAGE_SHIFT; 85532e62c636a728cb39c0b3bd191286f2ca65d4028Bjorn Helgaas u64 attr; 8561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 85732e62c636a728cb39c0b3bd191286f2ca65d4028Bjorn Helgaas /* 85832e62c636a728cb39c0b3bd191286f2ca65d4028Bjorn Helgaas * For /dev/mem mmap, we use user mappings, but if the region is 85932e62c636a728cb39c0b3bd191286f2ca65d4028Bjorn Helgaas * in kern_memmap (and hence may be covered by a kernel mapping), 86032e62c636a728cb39c0b3bd191286f2ca65d4028Bjorn Helgaas * we must use the same attribute as the kernel mapping. 86132e62c636a728cb39c0b3bd191286f2ca65d4028Bjorn Helgaas */ 86232e62c636a728cb39c0b3bd191286f2ca65d4028Bjorn Helgaas attr = kern_mem_attribute(phys_addr, size); 86332e62c636a728cb39c0b3bd191286f2ca65d4028Bjorn Helgaas if (attr & EFI_MEMORY_WB) 86432e62c636a728cb39c0b3bd191286f2ca65d4028Bjorn Helgaas return pgprot_cacheable(vma_prot); 86532e62c636a728cb39c0b3bd191286f2ca65d4028Bjorn Helgaas else if (attr & EFI_MEMORY_UC) 86632e62c636a728cb39c0b3bd191286f2ca65d4028Bjorn Helgaas return pgprot_noncached(vma_prot); 86732e62c636a728cb39c0b3bd191286f2ca65d4028Bjorn Helgaas 86832e62c636a728cb39c0b3bd191286f2ca65d4028Bjorn Helgaas /* 86932e62c636a728cb39c0b3bd191286f2ca65d4028Bjorn Helgaas * Some chipsets don't support UC access to memory. If 87032e62c636a728cb39c0b3bd191286f2ca65d4028Bjorn Helgaas * WB is supported, we prefer that. 87132e62c636a728cb39c0b3bd191286f2ca65d4028Bjorn Helgaas */ 87232e62c636a728cb39c0b3bd191286f2ca65d4028Bjorn Helgaas if (efi_mem_attribute(phys_addr, size) & EFI_MEMORY_WB) 87332e62c636a728cb39c0b3bd191286f2ca65d4028Bjorn Helgaas return pgprot_cacheable(vma_prot); 87432e62c636a728cb39c0b3bd191286f2ca65d4028Bjorn Helgaas 87532e62c636a728cb39c0b3bd191286f2ca65d4028Bjorn Helgaas return pgprot_noncached(vma_prot); 8761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 8771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint __init 8791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsefi_uart_console_only(void) 8801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 8811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds efi_status_t status; 8821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds char *s, name[] = "ConOut"; 8831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds efi_guid_t guid = EFI_GLOBAL_VARIABLE_GUID; 8841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds efi_char16_t *utf16, name_utf16[32]; 8851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned char data[1024]; 8861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long size = sizeof(data); 8871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct efi_generic_dev_path *hdr, *end_addr; 8881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int uart = 0; 8891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Convert to UTF-16 */ 8911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds utf16 = name_utf16; 8921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds s = name; 8931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while (*s) 8941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *utf16++ = *s++ & 0x7f; 8951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *utf16 = 0; 8961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds status = efi.get_variable(name_utf16, &guid, NULL, &size, data); 8981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (status != EFI_SUCCESS) { 8991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_ERR "No EFI %s variable?\n", name); 9001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 9011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 9021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds hdr = (struct efi_generic_dev_path *) data; 9041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds end_addr = (struct efi_generic_dev_path *) ((u8 *) data + size); 9051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while (hdr < end_addr) { 9061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (hdr->type == EFI_DEV_MSG && 9071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds hdr->sub_type == EFI_DEV_MSG_UART) 9081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds uart = 1; 9091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else if (hdr->type == EFI_DEV_END_PATH || 9101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds hdr->type == EFI_DEV_END_PATH2) { 9111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!uart) 9121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 9131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (hdr->sub_type == EFI_DEV_END_ENTIRE) 9141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 1; 9151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds uart = 0; 9161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 9177d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis hdr = (struct efi_generic_dev_path *)((u8 *) hdr + hdr->length); 9181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 9191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_ERR "Malformed %s value\n", name); 9201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 9211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 922d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck 923d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck/* 924d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck * Look for the first granule aligned memory descriptor memory 925d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck * that is big enough to hold EFI memory map. Make sure this 926d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck * descriptor is atleast granule sized so it does not get trimmed 927d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck */ 928d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luckstruct kern_memdesc * 929d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luckfind_memmap_space (void) 930d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck{ 931d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck u64 contig_low=0, contig_high=0; 932d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck u64 as = 0, ae; 933d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck void *efi_map_start, *efi_map_end, *p, *q; 934d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck efi_memory_desc_t *md, *pmd = NULL, *check_md; 935d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck u64 space_needed, efi_desc_size; 936d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck unsigned long total_mem = 0; 937d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck 938d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck efi_map_start = __va(ia64_boot_param->efi_memmap); 939d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck efi_map_end = efi_map_start + ia64_boot_param->efi_memmap_size; 940d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck efi_desc_size = ia64_boot_param->efi_memdesc_size; 941d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck 942d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck /* 943d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck * Worst case: we need 3 kernel descriptors for each efi descriptor 944d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck * (if every entry has a WB part in the middle, and UC head and tail), 945d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck * plus one for the end marker. 946d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck */ 947d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck space_needed = sizeof(kern_memdesc_t) * 948d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck (3 * (ia64_boot_param->efi_memmap_size/efi_desc_size) + 1); 949d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck 950d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck for (p = efi_map_start; p < efi_map_end; pmd = md, p += efi_desc_size) { 951d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck md = p; 952d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck if (!efi_wb(md)) { 953d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck continue; 954d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck } 9557d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis if (pmd == NULL || !efi_wb(pmd) || 9567d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis efi_md_end(pmd) != md->phys_addr) { 957d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck contig_low = GRANULEROUNDUP(md->phys_addr); 958d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck contig_high = efi_md_end(md); 9597d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis for (q = p + efi_desc_size; q < efi_map_end; 9607d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis q += efi_desc_size) { 961d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck check_md = q; 962d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck if (!efi_wb(check_md)) 963d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck break; 964d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck if (contig_high != check_md->phys_addr) 965d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck break; 966d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck contig_high = efi_md_end(check_md); 967d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck } 968d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck contig_high = GRANULEROUNDDOWN(contig_high); 969d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck } 97066888a6e5ffc756b9a4115fc766ee2258eefb928Christoph Lameter if (!is_memory_available(md) || md->type == EFI_LOADER_DATA) 971d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck continue; 972d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck 973d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck /* Round ends inward to granule boundaries */ 974d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck as = max(contig_low, md->phys_addr); 975d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck ae = min(contig_high, efi_md_end(md)); 976d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck 977a79561134f38de12dce14ed72138f38e55ef53fcZou Nan hai /* keep within max_addr= and min_addr= command line arg */ 978a79561134f38de12dce14ed72138f38e55ef53fcZou Nan hai as = max(as, min_addr); 979d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck ae = min(ae, max_addr); 980d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck if (ae <= as) 981d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck continue; 982d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck 983d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck /* avoid going over mem= command line arg */ 984d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck if (total_mem + (ae - as) > mem_limit) 985d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck ae -= total_mem + (ae - as) - mem_limit; 986d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck 987d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck if (ae <= as) 988d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck continue; 989d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck 990d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck if (ae - as > space_needed) 991d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck break; 992d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck } 993d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck if (p >= efi_map_end) 994d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck panic("Can't allocate space for kernel memory descriptors"); 995d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck 996d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck return __va(as); 997d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck} 998d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck 999d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck/* 1000d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck * Walk the EFI memory map and gather all memory available for kernel 1001d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck * to use. We can allocate partial granules only if the unavailable 1002d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck * parts exist, and are WB. 1003d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck */ 1004cb3808532eeb1719667356157fac9222ccb2c4ffBernhard Walleunsigned long 1005d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luckefi_memmap_init(unsigned long *s, unsigned long *e) 1006d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck{ 1007e037cda559547e6353c5a792802963572d0b750eKeith Owens struct kern_memdesc *k, *prev = NULL; 1008d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck u64 contig_low=0, contig_high=0; 1009d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck u64 as, ae, lim; 1010d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck void *efi_map_start, *efi_map_end, *p, *q; 1011d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck efi_memory_desc_t *md, *pmd = NULL, *check_md; 1012d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck u64 efi_desc_size; 1013d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck unsigned long total_mem = 0; 1014d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck 1015d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck k = kern_memmap = find_memmap_space(); 1016d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck 1017d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck efi_map_start = __va(ia64_boot_param->efi_memmap); 1018d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck efi_map_end = efi_map_start + ia64_boot_param->efi_memmap_size; 1019d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck efi_desc_size = ia64_boot_param->efi_memdesc_size; 1020d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck 1021d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck for (p = efi_map_start; p < efi_map_end; pmd = md, p += efi_desc_size) { 1022d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck md = p; 1023d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck if (!efi_wb(md)) { 10247d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis if (efi_uc(md) && 10257d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis (md->type == EFI_CONVENTIONAL_MEMORY || 10267d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis md->type == EFI_BOOT_SERVICES_DATA)) { 1027d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck k->attribute = EFI_MEMORY_UC; 1028d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck k->start = md->phys_addr; 1029d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck k->num_pages = md->num_pages; 1030d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck k++; 1031d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck } 1032d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck continue; 1033d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck } 10347d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis if (pmd == NULL || !efi_wb(pmd) || 10357d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis efi_md_end(pmd) != md->phys_addr) { 1036d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck contig_low = GRANULEROUNDUP(md->phys_addr); 1037d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck contig_high = efi_md_end(md); 10387d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis for (q = p + efi_desc_size; q < efi_map_end; 10397d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis q += efi_desc_size) { 1040d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck check_md = q; 1041d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck if (!efi_wb(check_md)) 1042d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck break; 1043d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck if (contig_high != check_md->phys_addr) 1044d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck break; 1045d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck contig_high = efi_md_end(check_md); 1046d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck } 1047d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck contig_high = GRANULEROUNDDOWN(contig_high); 1048d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck } 104966888a6e5ffc756b9a4115fc766ee2258eefb928Christoph Lameter if (!is_memory_available(md)) 1050d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck continue; 1051d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck 1052e55fdf11f3029bcd41b1b9547ad9db12c27eea76Tony Luck#ifdef CONFIG_CRASH_DUMP 1053e55fdf11f3029bcd41b1b9547ad9db12c27eea76Tony Luck /* saved_max_pfn should ignore max_addr= command line arg */ 1054e55fdf11f3029bcd41b1b9547ad9db12c27eea76Tony Luck if (saved_max_pfn < (efi_md_end(md) >> PAGE_SHIFT)) 1055e55fdf11f3029bcd41b1b9547ad9db12c27eea76Tony Luck saved_max_pfn = (efi_md_end(md) >> PAGE_SHIFT); 1056e55fdf11f3029bcd41b1b9547ad9db12c27eea76Tony Luck#endif 1057d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck /* 1058d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck * Round ends inward to granule boundaries 1059d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck * Give trimmings to uncached allocator 1060d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck */ 1061d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck if (md->phys_addr < contig_low) { 1062d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck lim = min(efi_md_end(md), contig_low); 1063d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck if (efi_uc(md)) { 10647d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis if (k > kern_memmap && 10657d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis (k-1)->attribute == EFI_MEMORY_UC && 1066d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck kmd_end(k-1) == md->phys_addr) { 10677d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis (k-1)->num_pages += 10687d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis (lim - md->phys_addr) 10697d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis >> EFI_PAGE_SHIFT; 1070d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck } else { 1071d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck k->attribute = EFI_MEMORY_UC; 1072d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck k->start = md->phys_addr; 10737d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis k->num_pages = (lim - md->phys_addr) 10747d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis >> EFI_PAGE_SHIFT; 1075d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck k++; 1076d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck } 1077d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck } 1078d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck as = contig_low; 1079d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck } else 1080d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck as = md->phys_addr; 1081d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck 1082d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck if (efi_md_end(md) > contig_high) { 1083d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck lim = max(md->phys_addr, contig_high); 1084d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck if (efi_uc(md)) { 1085d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck if (lim == md->phys_addr && k > kern_memmap && 1086d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck (k-1)->attribute == EFI_MEMORY_UC && 1087d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck kmd_end(k-1) == md->phys_addr) { 1088d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck (k-1)->num_pages += md->num_pages; 1089d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck } else { 1090d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck k->attribute = EFI_MEMORY_UC; 1091d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck k->start = lim; 10927d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis k->num_pages = (efi_md_end(md) - lim) 10937d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis >> EFI_PAGE_SHIFT; 1094d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck k++; 1095d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck } 1096d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck } 1097d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck ae = contig_high; 1098d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck } else 1099d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck ae = efi_md_end(md); 1100d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck 1101a79561134f38de12dce14ed72138f38e55ef53fcZou Nan hai /* keep within max_addr= and min_addr= command line arg */ 1102a79561134f38de12dce14ed72138f38e55ef53fcZou Nan hai as = max(as, min_addr); 1103d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck ae = min(ae, max_addr); 1104d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck if (ae <= as) 1105d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck continue; 1106d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck 1107d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck /* avoid going over mem= command line arg */ 1108d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck if (total_mem + (ae - as) > mem_limit) 1109d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck ae -= total_mem + (ae - as) - mem_limit; 1110d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck 1111d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck if (ae <= as) 1112d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck continue; 1113d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck if (prev && kmd_end(prev) == md->phys_addr) { 1114d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck prev->num_pages += (ae - as) >> EFI_PAGE_SHIFT; 1115d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck total_mem += ae - as; 1116d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck continue; 1117d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck } 1118d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck k->attribute = EFI_MEMORY_WB; 1119d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck k->start = as; 1120d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck k->num_pages = (ae - as) >> EFI_PAGE_SHIFT; 1121d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck total_mem += ae - as; 1122d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck prev = k++; 1123d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck } 1124d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck k->start = ~0L; /* end-marker */ 1125d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck 1126d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck /* reserve the memory we are using for kern_memmap */ 1127d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck *s = (u64)kern_memmap; 1128d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck *e = (u64)++k; 1129cb3808532eeb1719667356157fac9222ccb2c4ffBernhard Walle 1130cb3808532eeb1719667356157fac9222ccb2c4ffBernhard Walle return total_mem; 1131d8c97d5f3aa348272df2ccb4e224b1cf9a1eb6d7Tony Luck} 1132be379124c0a5abfbe57dab2823fe8a71ce797aeeKhalid Aziz 1133be379124c0a5abfbe57dab2823fe8a71ce797aeeKhalid Azizvoid 1134be379124c0a5abfbe57dab2823fe8a71ce797aeeKhalid Azizefi_initialize_iomem_resources(struct resource *code_resource, 113500bf4098beb15ca174b54f3af1f1e1908d7d18a3Bernhard Walle struct resource *data_resource, 113600bf4098beb15ca174b54f3af1f1e1908d7d18a3Bernhard Walle struct resource *bss_resource) 1137be379124c0a5abfbe57dab2823fe8a71ce797aeeKhalid Aziz{ 1138be379124c0a5abfbe57dab2823fe8a71ce797aeeKhalid Aziz struct resource *res; 1139be379124c0a5abfbe57dab2823fe8a71ce797aeeKhalid Aziz void *efi_map_start, *efi_map_end, *p; 1140be379124c0a5abfbe57dab2823fe8a71ce797aeeKhalid Aziz efi_memory_desc_t *md; 1141be379124c0a5abfbe57dab2823fe8a71ce797aeeKhalid Aziz u64 efi_desc_size; 1142be379124c0a5abfbe57dab2823fe8a71ce797aeeKhalid Aziz char *name; 1143be379124c0a5abfbe57dab2823fe8a71ce797aeeKhalid Aziz unsigned long flags; 1144be379124c0a5abfbe57dab2823fe8a71ce797aeeKhalid Aziz 1145be379124c0a5abfbe57dab2823fe8a71ce797aeeKhalid Aziz efi_map_start = __va(ia64_boot_param->efi_memmap); 1146be379124c0a5abfbe57dab2823fe8a71ce797aeeKhalid Aziz efi_map_end = efi_map_start + ia64_boot_param->efi_memmap_size; 1147be379124c0a5abfbe57dab2823fe8a71ce797aeeKhalid Aziz efi_desc_size = ia64_boot_param->efi_memdesc_size; 1148be379124c0a5abfbe57dab2823fe8a71ce797aeeKhalid Aziz 1149be379124c0a5abfbe57dab2823fe8a71ce797aeeKhalid Aziz res = NULL; 1150be379124c0a5abfbe57dab2823fe8a71ce797aeeKhalid Aziz 1151be379124c0a5abfbe57dab2823fe8a71ce797aeeKhalid Aziz for (p = efi_map_start; p < efi_map_end; p += efi_desc_size) { 1152be379124c0a5abfbe57dab2823fe8a71ce797aeeKhalid Aziz md = p; 1153be379124c0a5abfbe57dab2823fe8a71ce797aeeKhalid Aziz 1154be379124c0a5abfbe57dab2823fe8a71ce797aeeKhalid Aziz if (md->num_pages == 0) /* should not happen */ 1155be379124c0a5abfbe57dab2823fe8a71ce797aeeKhalid Aziz continue; 1156be379124c0a5abfbe57dab2823fe8a71ce797aeeKhalid Aziz 1157887c3cb18865a4f9e0786e5a5b3ef47ff469b956Yasunori Goto flags = IORESOURCE_MEM | IORESOURCE_BUSY; 1158be379124c0a5abfbe57dab2823fe8a71ce797aeeKhalid Aziz switch (md->type) { 1159be379124c0a5abfbe57dab2823fe8a71ce797aeeKhalid Aziz 1160be379124c0a5abfbe57dab2823fe8a71ce797aeeKhalid Aziz case EFI_MEMORY_MAPPED_IO: 1161be379124c0a5abfbe57dab2823fe8a71ce797aeeKhalid Aziz case EFI_MEMORY_MAPPED_IO_PORT_SPACE: 1162be379124c0a5abfbe57dab2823fe8a71ce797aeeKhalid Aziz continue; 1163be379124c0a5abfbe57dab2823fe8a71ce797aeeKhalid Aziz 1164be379124c0a5abfbe57dab2823fe8a71ce797aeeKhalid Aziz case EFI_LOADER_CODE: 1165be379124c0a5abfbe57dab2823fe8a71ce797aeeKhalid Aziz case EFI_LOADER_DATA: 1166be379124c0a5abfbe57dab2823fe8a71ce797aeeKhalid Aziz case EFI_BOOT_SERVICES_DATA: 1167be379124c0a5abfbe57dab2823fe8a71ce797aeeKhalid Aziz case EFI_BOOT_SERVICES_CODE: 1168be379124c0a5abfbe57dab2823fe8a71ce797aeeKhalid Aziz case EFI_CONVENTIONAL_MEMORY: 1169be379124c0a5abfbe57dab2823fe8a71ce797aeeKhalid Aziz if (md->attribute & EFI_MEMORY_WP) { 1170be379124c0a5abfbe57dab2823fe8a71ce797aeeKhalid Aziz name = "System ROM"; 1171be379124c0a5abfbe57dab2823fe8a71ce797aeeKhalid Aziz flags |= IORESOURCE_READONLY; 1172be379124c0a5abfbe57dab2823fe8a71ce797aeeKhalid Aziz } else { 1173be379124c0a5abfbe57dab2823fe8a71ce797aeeKhalid Aziz name = "System RAM"; 1174be379124c0a5abfbe57dab2823fe8a71ce797aeeKhalid Aziz } 1175be379124c0a5abfbe57dab2823fe8a71ce797aeeKhalid Aziz break; 1176be379124c0a5abfbe57dab2823fe8a71ce797aeeKhalid Aziz 1177be379124c0a5abfbe57dab2823fe8a71ce797aeeKhalid Aziz case EFI_ACPI_MEMORY_NVS: 1178be379124c0a5abfbe57dab2823fe8a71ce797aeeKhalid Aziz name = "ACPI Non-volatile Storage"; 1179be379124c0a5abfbe57dab2823fe8a71ce797aeeKhalid Aziz break; 1180be379124c0a5abfbe57dab2823fe8a71ce797aeeKhalid Aziz 1181be379124c0a5abfbe57dab2823fe8a71ce797aeeKhalid Aziz case EFI_UNUSABLE_MEMORY: 1182be379124c0a5abfbe57dab2823fe8a71ce797aeeKhalid Aziz name = "reserved"; 1183887c3cb18865a4f9e0786e5a5b3ef47ff469b956Yasunori Goto flags |= IORESOURCE_DISABLED; 1184be379124c0a5abfbe57dab2823fe8a71ce797aeeKhalid Aziz break; 1185be379124c0a5abfbe57dab2823fe8a71ce797aeeKhalid Aziz 1186be379124c0a5abfbe57dab2823fe8a71ce797aeeKhalid Aziz case EFI_RESERVED_TYPE: 1187be379124c0a5abfbe57dab2823fe8a71ce797aeeKhalid Aziz case EFI_RUNTIME_SERVICES_CODE: 1188be379124c0a5abfbe57dab2823fe8a71ce797aeeKhalid Aziz case EFI_RUNTIME_SERVICES_DATA: 1189be379124c0a5abfbe57dab2823fe8a71ce797aeeKhalid Aziz case EFI_ACPI_RECLAIM_MEMORY: 1190be379124c0a5abfbe57dab2823fe8a71ce797aeeKhalid Aziz default: 1191be379124c0a5abfbe57dab2823fe8a71ce797aeeKhalid Aziz name = "reserved"; 1192be379124c0a5abfbe57dab2823fe8a71ce797aeeKhalid Aziz break; 1193be379124c0a5abfbe57dab2823fe8a71ce797aeeKhalid Aziz } 1194be379124c0a5abfbe57dab2823fe8a71ce797aeeKhalid Aziz 11957d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis if ((res = kzalloc(sizeof(struct resource), 11967d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis GFP_KERNEL)) == NULL) { 11977d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis printk(KERN_ERR 1198965e7c8affeca27f7e5de75c97954e74d3b8052dAron Griffis "failed to allocate resource for iomem\n"); 1199be379124c0a5abfbe57dab2823fe8a71ce797aeeKhalid Aziz return; 1200be379124c0a5abfbe57dab2823fe8a71ce797aeeKhalid Aziz } 1201be379124c0a5abfbe57dab2823fe8a71ce797aeeKhalid Aziz 1202be379124c0a5abfbe57dab2823fe8a71ce797aeeKhalid Aziz res->name = name; 1203be379124c0a5abfbe57dab2823fe8a71ce797aeeKhalid Aziz res->start = md->phys_addr; 1204685c7f5d3629d558b17ee193b6d7f194e82aadf0Li Zefan res->end = md->phys_addr + efi_md_size(md) - 1; 1205be379124c0a5abfbe57dab2823fe8a71ce797aeeKhalid Aziz res->flags = flags; 1206be379124c0a5abfbe57dab2823fe8a71ce797aeeKhalid Aziz 1207be379124c0a5abfbe57dab2823fe8a71ce797aeeKhalid Aziz if (insert_resource(&iomem_resource, res) < 0) 1208be379124c0a5abfbe57dab2823fe8a71ce797aeeKhalid Aziz kfree(res); 1209be379124c0a5abfbe57dab2823fe8a71ce797aeeKhalid Aziz else { 1210be379124c0a5abfbe57dab2823fe8a71ce797aeeKhalid Aziz /* 1211be379124c0a5abfbe57dab2823fe8a71ce797aeeKhalid Aziz * We don't know which region contains 1212be379124c0a5abfbe57dab2823fe8a71ce797aeeKhalid Aziz * kernel data so we try it repeatedly and 1213be379124c0a5abfbe57dab2823fe8a71ce797aeeKhalid Aziz * let the resource manager test it. 1214be379124c0a5abfbe57dab2823fe8a71ce797aeeKhalid Aziz */ 1215be379124c0a5abfbe57dab2823fe8a71ce797aeeKhalid Aziz insert_resource(res, code_resource); 1216be379124c0a5abfbe57dab2823fe8a71ce797aeeKhalid Aziz insert_resource(res, data_resource); 121700bf4098beb15ca174b54f3af1f1e1908d7d18a3Bernhard Walle insert_resource(res, bss_resource); 1218a79561134f38de12dce14ed72138f38e55ef53fcZou Nan hai#ifdef CONFIG_KEXEC 1219a79561134f38de12dce14ed72138f38e55ef53fcZou Nan hai insert_resource(res, &efi_memmap_res); 1220a79561134f38de12dce14ed72138f38e55ef53fcZou Nan hai insert_resource(res, &boot_param_res); 1221a79561134f38de12dce14ed72138f38e55ef53fcZou Nan hai if (crashk_res.end > crashk_res.start) 1222a79561134f38de12dce14ed72138f38e55ef53fcZou Nan hai insert_resource(res, &crashk_res); 1223a79561134f38de12dce14ed72138f38e55ef53fcZou Nan hai#endif 1224be379124c0a5abfbe57dab2823fe8a71ce797aeeKhalid Aziz } 1225be379124c0a5abfbe57dab2823fe8a71ce797aeeKhalid Aziz } 1226be379124c0a5abfbe57dab2823fe8a71ce797aeeKhalid Aziz} 1227a79561134f38de12dce14ed72138f38e55ef53fcZou Nan hai 1228a79561134f38de12dce14ed72138f38e55ef53fcZou Nan hai#ifdef CONFIG_KEXEC 1229a79561134f38de12dce14ed72138f38e55ef53fcZou Nan hai/* find a block of memory aligned to 64M exclude reserved regions 1230a79561134f38de12dce14ed72138f38e55ef53fcZou Nan hai rsvd_regions are sorted 1231a79561134f38de12dce14ed72138f38e55ef53fcZou Nan hai */ 12322a3a2827c7cbe464610116cc17ca4fac63245a43Hormsunsigned long __init 12337d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffiskdump_find_rsvd_region (unsigned long size, struct rsvd_region *r, int n) 1234a79561134f38de12dce14ed72138f38e55ef53fcZou Nan hai{ 12357d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis int i; 12367d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis u64 start, end; 12377d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis u64 alignment = 1UL << _PAGE_SIZE_64M; 12387d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis void *efi_map_start, *efi_map_end, *p; 12397d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis efi_memory_desc_t *md; 12407d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis u64 efi_desc_size; 12417d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis 12427d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis efi_map_start = __va(ia64_boot_param->efi_memmap); 12437d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis efi_map_end = efi_map_start + ia64_boot_param->efi_memmap_size; 12447d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis efi_desc_size = ia64_boot_param->efi_memdesc_size; 12457d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis 12467d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis for (p = efi_map_start; p < efi_map_end; p += efi_desc_size) { 12477d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis md = p; 12487d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis if (!efi_wb(md)) 12497d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis continue; 12507d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis start = ALIGN(md->phys_addr, alignment); 12517d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis end = efi_md_end(md); 12527d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis for (i = 0; i < n; i++) { 12537d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis if (__pa(r[i].start) >= start && __pa(r[i].end) < end) { 12547d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis if (__pa(r[i].start) > start + size) 12557d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis return start; 12567d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis start = ALIGN(__pa(r[i].end), alignment); 12577d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis if (i < n-1 && 12587d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis __pa(r[i+1].start) < start + size) 12597d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis continue; 12607d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis else 12617d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis break; 12627d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis } 1263a79561134f38de12dce14ed72138f38e55ef53fcZou Nan hai } 12647d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis if (end > start + size) 12657d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis return start; 12667d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis } 12677d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis 12687d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis printk(KERN_WARNING 12697d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis "Cannot reserve 0x%lx byte of memory for crashdump\n", size); 12707d9aed26ed11d7a472104b7078b0c5e4fd416059Aron Griffis return ~0UL; 1271a79561134f38de12dce14ed72138f38e55ef53fcZou Nan hai} 1272a79561134f38de12dce14ed72138f38e55ef53fcZou Nan hai#endif 1273cee87af2a5f75713b98d3e65e43872e547122cd5Magnus Damm 1274cee87af2a5f75713b98d3e65e43872e547122cd5Magnus Damm#ifdef CONFIG_PROC_VMCORE 1275cee87af2a5f75713b98d3e65e43872e547122cd5Magnus Damm/* locate the size find a the descriptor at a certain address */ 12761775fe851632fd906bc5e5c6f77494d8f7ef1275Simon Hormanunsigned long __init 1277cee87af2a5f75713b98d3e65e43872e547122cd5Magnus Dammvmcore_find_descriptor_size (unsigned long address) 1278cee87af2a5f75713b98d3e65e43872e547122cd5Magnus Damm{ 1279cee87af2a5f75713b98d3e65e43872e547122cd5Magnus Damm void *efi_map_start, *efi_map_end, *p; 1280cee87af2a5f75713b98d3e65e43872e547122cd5Magnus Damm efi_memory_desc_t *md; 1281cee87af2a5f75713b98d3e65e43872e547122cd5Magnus Damm u64 efi_desc_size; 1282cee87af2a5f75713b98d3e65e43872e547122cd5Magnus Damm unsigned long ret = 0; 1283cee87af2a5f75713b98d3e65e43872e547122cd5Magnus Damm 1284cee87af2a5f75713b98d3e65e43872e547122cd5Magnus Damm efi_map_start = __va(ia64_boot_param->efi_memmap); 1285cee87af2a5f75713b98d3e65e43872e547122cd5Magnus Damm efi_map_end = efi_map_start + ia64_boot_param->efi_memmap_size; 1286cee87af2a5f75713b98d3e65e43872e547122cd5Magnus Damm efi_desc_size = ia64_boot_param->efi_memdesc_size; 1287cee87af2a5f75713b98d3e65e43872e547122cd5Magnus Damm 1288cee87af2a5f75713b98d3e65e43872e547122cd5Magnus Damm for (p = efi_map_start; p < efi_map_end; p += efi_desc_size) { 1289cee87af2a5f75713b98d3e65e43872e547122cd5Magnus Damm md = p; 1290cee87af2a5f75713b98d3e65e43872e547122cd5Magnus Damm if (efi_wb(md) && md->type == EFI_LOADER_DATA 1291cee87af2a5f75713b98d3e65e43872e547122cd5Magnus Damm && md->phys_addr == address) { 1292cee87af2a5f75713b98d3e65e43872e547122cd5Magnus Damm ret = efi_md_size(md); 1293cee87af2a5f75713b98d3e65e43872e547122cd5Magnus Damm break; 1294cee87af2a5f75713b98d3e65e43872e547122cd5Magnus Damm } 1295cee87af2a5f75713b98d3e65e43872e547122cd5Magnus Damm } 1296cee87af2a5f75713b98d3e65e43872e547122cd5Magnus Damm 1297cee87af2a5f75713b98d3e65e43872e547122cd5Magnus Damm if (ret == 0) 1298cee87af2a5f75713b98d3e65e43872e547122cd5Magnus Damm printk(KERN_WARNING "Cannot locate EFI vmcore descriptor\n"); 1299cee87af2a5f75713b98d3e65e43872e547122cd5Magnus Damm 1300cee87af2a5f75713b98d3e65e43872e547122cd5Magnus Damm return ret; 1301cee87af2a5f75713b98d3e65e43872e547122cd5Magnus Damm} 1302cee87af2a5f75713b98d3e65e43872e547122cd5Magnus Damm#endif 1303