diff options
author | Konrad Rzeszutek Wilk <konrad.wilk@oracle.com> | 2012-08-21 14:31:24 -0400 |
---|---|---|
committer | Konrad Rzeszutek Wilk <konrad.wilk@oracle.com> | 2012-08-21 14:45:33 -0400 |
commit | 806c312e50f122c47913145cf884f53dd09d9199 (patch) | |
tree | c6d64ccc297c5f8e9a2959365d74c877cde93894 /arch/x86/xen/enlighten.c | |
parent | 59b294403e9814e7c1154043567f0d71bac7a511 (diff) |
xen/x86: Workaround 64-bit hypervisor and 32-bit initial domain.
If a 64-bit hypervisor is booted with a 32-bit initial domain,
the hypervisor deals with the initial domain as "compat" and
does some extra adjustments (like pagetables are 4 bytes instead
of 8). It also adjusts the xen_start_info->pt_base incorrectly.
When booted with a 32-bit hypervisor (32-bit initial domain):
..
(XEN) Start info: cf831000->cf83147c
(XEN) Page tables: cf832000->cf8b5000
..
[ 0.000000] PT: cf832000 (f832000)
[ 0.000000] Reserving PT: f832000->f8b5000
And with a 64-bit hypervisor:
(XEN) Start info: 00000000cf831000->00000000cf8314b4
(XEN) Page tables: 00000000cf832000->00000000cf8b6000
[ 0.000000] PT: cf834000 (f834000)
[ 0.000000] Reserving PT: f834000->f8b8000
To deal with this, we keep keep track of the highest physical
address we have reserved via memblock_reserve. If that address
does not overlap with pt_base, we have a gap which we reserve.
Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk@oracle.com>
Diffstat (limited to 'arch/x86/xen/enlighten.c')
-rw-r--r-- | arch/x86/xen/enlighten.c | 30 |
1 files changed, 21 insertions, 9 deletions
diff --git a/arch/x86/xen/enlighten.c b/arch/x86/xen/enlighten.c index e532eb50e8d7..511f92d79e4a 100644 --- a/arch/x86/xen/enlighten.c +++ b/arch/x86/xen/enlighten.c | |||
@@ -1002,19 +1002,24 @@ static int xen_write_msr_safe(unsigned int msr, unsigned low, unsigned high) | |||
1002 | * If the MFN is not in the m2p (provided to us by the hypervisor) this | 1002 | * If the MFN is not in the m2p (provided to us by the hypervisor) this |
1003 | * function won't do anything. In practice this means that the XenBus | 1003 | * function won't do anything. In practice this means that the XenBus |
1004 | * MFN won't be available for the initial domain. */ | 1004 | * MFN won't be available for the initial domain. */ |
1005 | static void __init xen_reserve_mfn(unsigned long mfn) | 1005 | static unsigned long __init xen_reserve_mfn(unsigned long mfn) |
1006 | { | 1006 | { |
1007 | unsigned long pfn; | 1007 | unsigned long pfn, end_pfn = 0; |
1008 | 1008 | ||
1009 | if (!mfn) | 1009 | if (!mfn) |
1010 | return; | 1010 | return end_pfn; |
1011 | |||
1011 | pfn = mfn_to_pfn(mfn); | 1012 | pfn = mfn_to_pfn(mfn); |
1012 | if (phys_to_machine_mapping_valid(pfn)) | 1013 | if (phys_to_machine_mapping_valid(pfn)) { |
1013 | memblock_reserve(PFN_PHYS(pfn), PAGE_SIZE); | 1014 | end_pfn = PFN_PHYS(pfn) + PAGE_SIZE; |
1015 | memblock_reserve(PFN_PHYS(pfn), end_pfn); | ||
1016 | } | ||
1017 | return end_pfn; | ||
1014 | } | 1018 | } |
1015 | static void __init xen_reserve_internals(void) | 1019 | static void __init xen_reserve_internals(void) |
1016 | { | 1020 | { |
1017 | unsigned long size; | 1021 | unsigned long size; |
1022 | unsigned long last_phys = 0; | ||
1018 | 1023 | ||
1019 | if (!xen_pv_domain()) | 1024 | if (!xen_pv_domain()) |
1020 | return; | 1025 | return; |
@@ -1022,12 +1027,13 @@ static void __init xen_reserve_internals(void) | |||
1022 | /* xen_start_info does not exist in the M2P, hence can't use | 1027 | /* xen_start_info does not exist in the M2P, hence can't use |
1023 | * xen_reserve_mfn. */ | 1028 | * xen_reserve_mfn. */ |
1024 | memblock_reserve(__pa(xen_start_info), PAGE_SIZE); | 1029 | memblock_reserve(__pa(xen_start_info), PAGE_SIZE); |
1030 | last_phys = __pa(xen_start_info) + PAGE_SIZE; | ||
1025 | 1031 | ||
1026 | xen_reserve_mfn(PFN_DOWN(xen_start_info->shared_info)); | 1032 | last_phys = max(xen_reserve_mfn(PFN_DOWN(xen_start_info->shared_info)), last_phys); |
1027 | xen_reserve_mfn(xen_start_info->store_mfn); | 1033 | last_phys = max(xen_reserve_mfn(xen_start_info->store_mfn), last_phys); |
1028 | 1034 | ||
1029 | if (!xen_initial_domain()) | 1035 | if (!xen_initial_domain()) |
1030 | xen_reserve_mfn(xen_start_info->console.domU.mfn); | 1036 | last_phys = max(xen_reserve_mfn(xen_start_info->console.domU.mfn), last_phys); |
1031 | 1037 | ||
1032 | if (xen_feature(XENFEAT_auto_translated_physmap)) | 1038 | if (xen_feature(XENFEAT_auto_translated_physmap)) |
1033 | return; | 1039 | return; |
@@ -1043,8 +1049,14 @@ static void __init xen_reserve_internals(void) | |||
1043 | * a lot (and call memblock_reserve for each PAGE), so lets just use | 1049 | * a lot (and call memblock_reserve for each PAGE), so lets just use |
1044 | * the easy way and reserve it wholesale. */ | 1050 | * the easy way and reserve it wholesale. */ |
1045 | memblock_reserve(__pa(xen_start_info->mfn_list), size); | 1051 | memblock_reserve(__pa(xen_start_info->mfn_list), size); |
1046 | 1052 | last_phys = max(__pa(xen_start_info->mfn_list) + size, last_phys); | |
1047 | /* The pagetables are reserved in mmu.c */ | 1053 | /* The pagetables are reserved in mmu.c */ |
1054 | |||
1055 | /* Under 64-bit hypervisor with a 32-bit domain, the hypervisor | ||
1056 | * offsets the pt_base by two pages. Hence the reservation that is done | ||
1057 | * in mmu.c misses two pages. We correct it here if we detect this. */ | ||
1058 | if (last_phys < __pa(xen_start_info->pt_base)) | ||
1059 | memblock_reserve(last_phys, __pa(xen_start_info->pt_base) - last_phys); | ||
1048 | } | 1060 | } |
1049 | void xen_setup_shared_info(void) | 1061 | void xen_setup_shared_info(void) |
1050 | { | 1062 | { |